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