summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2025-01-18 12:59:33 -0500
committerTavian Barnes <tavianator@tavianator.com>2025-01-18 12:59:33 -0500
commit62928ddf80fea0291cf40d95877bb5b6f9d110c9 (patch)
tree1db1689d2e145fa5957717cb62133d4a24b0171e /src
parent41f3283ec38e0cc27e350569bef3651e16447ce0 (diff)
downloadbfs-62928ddf80fea0291cf40d95877bb5b6f9d110c9.tar.xz
sighook: New sigreset() function to reset all handlers
Diffstat (limited to 'src')
-rw-r--r--src/sighook.c40
-rw-r--r--src/sighook.h8
2 files changed, 45 insertions, 3 deletions
diff --git a/src/sighook.c b/src/sighook.c
index a1fc30d..820044c 100644
--- a/src/sighook.c
+++ b/src/sighook.c
@@ -525,6 +525,18 @@ static void sigdispatch(int sig, siginfo_t *info, void *context) {
errno = error;
}
+/** A saved signal handler, for sigreset() to restore. */
+struct sigsave {
+ struct rcu_node node;
+ int sig;
+ struct sigaction action;
+};
+
+/** The list of saved signal handlers. */
+static struct rcu_list saved;
+/** `saved` initialization status (since rcu_list_init() isn't atomic). */
+static atomic bool initialized = false;
+
/** Make sure our signal handler is installed for a given signal. */
static int siginit(int sig) {
#ifdef SA_RESTART
@@ -539,9 +551,8 @@ static int siginit(int sig) {
};
static sigset_t signals;
- static bool initialized = false;
- if (!initialized) {
+ if (!load(&initialized, relaxed)) {
if (sigemptyset(&signals) != 0
|| sigemptyset(&action.sa_mask) != 0) {
return -1;
@@ -551,7 +562,8 @@ static int siginit(int sig) {
rcu_list_init(&sighooks[i]);
}
- initialized = true;
+ rcu_list_init(&saved);
+ store(&initialized, true, release);
}
int installed = sigismember(&signals, sig);
@@ -561,6 +573,18 @@ static int siginit(int sig) {
return 0;
}
+ struct sigsave *save = ALLOC(struct sigsave);
+ if (!save) {
+ return -1;
+ }
+
+ save->sig = sig;
+ if (sigaction(sig, NULL, &save->action) != 0) {
+ free(save);
+ return -1;
+ }
+ rcu_list_append(&saved, &save->node);
+
if (sigaction(sig, &action, NULL) != 0) {
return -1;
}
@@ -639,3 +663,13 @@ void sigunhook(struct sighook *hook) {
free(hook);
}
+
+int sigreset(void) {
+ for_rcu (struct sigsave, save, &saved) {
+ if (sigaction(save->sig, &save->action, NULL) != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/sighook.h b/src/sighook.h
index 87bba4e..7149229 100644
--- a/src/sighook.h
+++ b/src/sighook.h
@@ -72,4 +72,12 @@ struct sighook *atsigexit(sighook_fn *fn, void *arg);
*/
void sigunhook(struct sighook *hook);
+/**
+ * Restore all signal handlers to their original dispositions (e.g. after fork()).
+ *
+ * @return
+ * 0 on success, -1 on failure.
+ */
+int sigreset(void);
+
#endif // BFS_SIGHOOK_H