dcavalca / rpms / rpm

Forked from rpms/rpm a year ago
Clone
3ca195
From 534fd1f0c84b12ba6080a46e07c57ef913c77cba Mon Sep 17 00:00:00 2001
3ca195
From: Radovan Sroka <rsroka@redhat.com>
3ca195
Date: Thu, 25 Aug 2022 15:38:01 +0200
3ca195
Subject: [PATCH] fapolicyd: Make write() nonblocking
3ca195
3ca195
- switch to read only and non blocking mode for pipe
3ca195
- add 1 minute loop to wait for pipe to reappear
3ca195
3ca195
Sometimes during the system update/upgrade fapolicyd
3ca195
get restarted e.g. when systemd gets updated.
3ca195
That can lead to the situation where fapolicyd pipe
3ca195
has been removed and created again.
3ca195
In such cases rpm-plugin-fapolicyd gets stuck on
3ca195
write() to the pipe which does not exist anymore.
3ca195
After switching to non blocking file descriptor
3ca195
we can try to reopen the pipe if there is an error
3ca195
from write(). Assuming that a new pipe should appear
3ca195
when fapolicyd daemon starts again.
3ca195
If not then after 1 minute of waiting we expect
3ca195
fapolicyd daemon to be not active and we let the
3ca195
transaction continue.
3ca195
3ca195
Signed-off-by: Radovan Sroka <rsroka@redhat.com>
3ca195
---
3ca195
 plugins/fapolicyd.c | 74 +++++++++++++++++++++++++++++++++++++++------
3ca195
 1 file changed, 65 insertions(+), 9 deletions(-)
3ca195
3ca195
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
3ca195
index 1ff50c30f..6c6322941 100644
3ca195
--- a/plugins/fapolicyd.c
3ca195
+++ b/plugins/fapolicyd.c
3ca195
@@ -27,7 +27,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
3ca195
     int fd = -1;
3ca195
     struct stat s;
3ca195
 
3ca195
-    fd = open(state->fifo_path, O_RDWR);
3ca195
+    fd = open(state->fifo_path, O_WRONLY|O_NONBLOCK);
3ca195
     if (fd == -1) {
3ca195
         rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno));
3ca195
         goto bad;
3ca195
@@ -55,15 +55,26 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
3ca195
     }
3ca195
 
3ca195
     state->fd = fd;
3ca195
+
3ca195
     /* considering success */
3ca195
     return RPMRC_OK;
3ca195
 
3ca195
  bad:
3ca195
     if (fd >= 0)
3ca195
         close(fd);
3ca195
+
3ca195
+    state->fd = -1;
3ca195
     return RPMRC_FAIL;
3ca195
 }
3ca195
 
3ca195
+static void close_fifo(struct fapolicyd_data* state)
3ca195
+{
3ca195
+    if (state->fd > 0)
3ca195
+        (void) close(state->fd);
3ca195
+
3ca195
+    state->fd = -1;
3ca195
+}
3ca195
+
3ca195
 static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
3ca195
 {
3ca195
     ssize_t len = strlen(str);
3ca195
@@ -86,6 +97,54 @@ static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
3ca195
     return RPMRC_FAIL;
3ca195
 }
3ca195
 
3ca195
+static void try_to_write_to_fifo(struct fapolicyd_data* state, const char * str)
3ca195
+{
3ca195
+    int reload = 0;
3ca195
+    int printed = 0;
3ca195
+
3ca195
+    /* 1min/60s */
3ca195
+    const int timeout = 60;
3ca195
+
3ca195
+    /* wait up to X seconds */
3ca195
+    for (int i = 0; i < timeout; i++) {
3ca195
+
3ca195
+        if (reload) {
3ca195
+            if (!printed) {
3ca195
+                rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: waiting for the service connection to resume, it can take up to %d seconds\n", timeout);
3ca195
+                printed = 1;
3ca195
+            }
3ca195
+
3ca195
+            (void) close_fifo(state);
3ca195
+            (void) open_fifo(state);
3ca195
+        }
3ca195
+
3ca195
+        if (state->fd >= 0) {
3ca195
+            if (write_fifo(state, str) == RPMRC_OK) {
3ca195
+
3ca195
+                /* write was successful after few reopens */
3ca195
+                if (reload)
3ca195
+                    rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has resumed\n");
3ca195
+
3ca195
+                break;
3ca195
+            }
3ca195
+        }
3ca195
+
3ca195
+        /* failed write or reopen */
3ca195
+        reload = 1;
3ca195
+        sleep(1);
3ca195
+
3ca195
+        /* the last iteration */
3ca195
+        /* consider failure */
3ca195
+        if (i == timeout-1) {
3ca195
+            rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has not resumed\n");
3ca195
+            rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: continuing without the service\n");
3ca195
+        }
3ca195
+
3ca195
+    }
3ca195
+
3ca195
+}
3ca195
+
3ca195
+
3ca195
 static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
3ca195
 {
3ca195
     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
3ca195
@@ -102,10 +161,7 @@ static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
3ca195
 
3ca195
 static void fapolicyd_cleanup(rpmPlugin plugin)
3ca195
 {
3ca195
-    if (fapolicyd_state.fd > 0)
3ca195
-        (void) close(fapolicyd_state.fd);
3ca195
-
3ca195
-    fapolicyd_state.fd = -1;
3ca195
+    (void) close_fifo(&fapolicyd_state);
3ca195
 }
3ca195
 
3ca195
 static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
3ca195
@@ -116,9 +172,9 @@ static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
3ca195
     /* we are ready */
3ca195
     if (fapolicyd_state.fd > 0) {
3ca195
         /* send a signal that transaction is over */
3ca195
-        (void) write_fifo(&fapolicyd_state, "1\n");
3ca195
+        (void) try_to_write_to_fifo(&fapolicyd_state, "1\n");
3ca195
         /* flush cache */
3ca195
-        (void) write_fifo(&fapolicyd_state, "2\n");
3ca195
+        (void) try_to_write_to_fifo(&fapolicyd_state, "2\n");
3ca195
     }
3ca195
 
3ca195
  end:
3ca195
@@ -133,7 +189,7 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
3ca195
 
3ca195
     if (fapolicyd_state.changed_files > 0) {
3ca195
         /* send signal to flush cache */
3ca195
-        (void) write_fifo(&fapolicyd_state, "2\n");
3ca195
+        (void) try_to_write_to_fifo(&fapolicyd_state, "2\n");
3ca195
 
3ca195
         /* optimize flushing */
3ca195
         /* flush only when there was an actual change */
3ca195
@@ -176,7 +232,7 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
3ca195
     char * sha = rpmfiFDigestHex(fi, NULL);
3ca195
 
3ca195
     snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
3ca195
-    (void) write_fifo(&fapolicyd_state, buffer);
3ca195
+    (void) try_to_write_to_fifo(&fapolicyd_state, buffer);
3ca195
 
3ca195
     free(sha);
3ca195
 
3ca195
-- 
3ca195
2.37.3
3ca195