diff options
author | Roy Marples <roy@marples.name> | 2008-02-02 00:17:35 +0000 |
---|---|---|
committer | Roy Marples <roy@marples.name> | 2008-02-02 00:17:35 +0000 |
commit | ad045176238549c3267fff3e8c0014dd5e9ffbdf (patch) | |
tree | 8332746190f8e9fc47007090a3beac0a64d133c6 /src/rc/rc-plugin.c | |
parent | fef5d0af591c6c8a91f69bba5e62c99df1a732c9 (diff) |
Block signals to avoid fork /signal races.
Diffstat (limited to 'src/rc/rc-plugin.c')
-rw-r--r-- | src/rc/rc-plugin.c | 158 |
1 files changed, 92 insertions, 66 deletions
diff --git a/src/rc/rc-plugin.c b/src/rc/rc-plugin.c index 29bd43c2..e4b4e0eb 100644 --- a/src/rc/rc-plugin.c +++ b/src/rc/rc-plugin.c @@ -143,84 +143,110 @@ int rc_waitpid (pid_t pid) void rc_plugin_run (rc_hook_t hook, const char *value) { plugin_t *plugin = plugins; + struct sigaction sa; + sigset_t empty; + sigset_t full; + sigset_t old; /* Don't run plugins if we're in one */ if (rc_in_plugin) return; + /* We need to block signals until we have forked */ + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sigemptyset (&sa.sa_mask); + sigemptyset (&empty); + sigfillset (&full); + while (plugin) { - if (plugin->hook) { - int i; - int flags; - int pfd[2]; - pid_t pid; - - /* We create a pipe so that plugins can affect our environment - * vars, which in turn influence our scripts. */ - if (pipe (pfd) == -1) { - eerror ("pipe: %s", strerror (errno)); - return; - } + int i; + int flags; + int pfd[2]; + pid_t pid; + char *buffer; + char *token; + char *p; + ssize_t nr; + + if (! plugin->hook) { + plugin = plugin->next; + continue; + } - /* Stop any scripts from inheriting us. - * This is actually quite important as without this, the splash - * plugin will probably hang when running in silent mode. */ - for (i = 0; i < 2; i++) - if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 || - fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0) - eerror ("fcntl: %s", strerror (errno)); - - /* We run the plugin in a new process so we never crash - * or otherwise affected by it */ - if ((pid = fork ()) == -1) { - eerror ("fork: %s", strerror (errno)); - return; - } + /* We create a pipe so that plugins can affect our environment + * vars, which in turn influence our scripts. */ + if (pipe (pfd) == -1) { + eerror ("pipe: %s", strerror (errno)); + return; + } - if (pid == 0) { - int retval; - - rc_in_plugin = true; - close (pfd[0]); - rc_environ_fd = fdopen (pfd[1], "w"); - retval = plugin->hook (hook, value); - fclose (rc_environ_fd); - rc_environ_fd = NULL; - - /* Just in case the plugin sets this to false */ - rc_in_plugin = true; - exit (retval); - } else { - char *buffer; - char *token; - char *p; - ssize_t nr; - - close (pfd[1]); - buffer = xmalloc (sizeof (char) * BUFSIZ); - memset (buffer, 0, BUFSIZ); - - while ((nr = read (pfd[0], buffer, BUFSIZ)) > 0) { - p = buffer; - while (*p && p - buffer < nr) { - token = strsep (&p, "="); - if (token) { - unsetenv (token); - if (*p) { - setenv (token, p, 1); - p += strlen (p) + 1; - } else - p++; - } - } - } + /* Stop any scripts from inheriting us. + * This is actually quite important as without this, the splash + * plugin will probably hang when running in silent mode. */ + for (i = 0; i < 2; i++) + if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 || + fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0) + eerror ("fcntl: %s", strerror (errno)); + + sigprocmask (SIG_SETMASK, &full, &old); + + /* We run the plugin in a new process so we never crash + * or otherwise affected by it */ + if ((pid = fork ()) == -1) { + eerror ("fork: %s", strerror (errno)); + break; + } - free (buffer); - close (pfd[0]); + if (pid == 0) { + int retval; + + /* Restore default handlers */ + sigaction (SIGCHLD, &sa, NULL); + sigaction (SIGHUP, &sa, NULL); + sigaction (SIGINT, &sa, NULL); + sigaction (SIGQUIT, &sa, NULL); + sigaction (SIGTERM, &sa, NULL); + sigaction (SIGUSR1, &sa, NULL); + sigaction (SIGWINCH, &sa, NULL); + sigprocmask (SIG_SETMASK, &old, NULL); + + rc_in_plugin = true; + close (pfd[0]); + rc_environ_fd = fdopen (pfd[1], "w"); + retval = plugin->hook (hook, value); + fclose (rc_environ_fd); + rc_environ_fd = NULL; + + /* Just in case the plugin sets this to false */ + rc_in_plugin = true; + exit (retval); + } - rc_waitpid (pid); + sigprocmask (SIG_SETMASK, &old, NULL); + close (pfd[1]); + buffer = xmalloc (sizeof (char) * BUFSIZ); + memset (buffer, 0, BUFSIZ); + + while ((nr = read (pfd[0], buffer, BUFSIZ)) > 0) { + p = buffer; + while (*p && p - buffer < nr) { + token = strsep (&p, "="); + if (token) { + unsetenv (token); + if (*p) { + setenv (token, p, 1); + p += strlen (p) + 1; + } else + p++; + } } } + + free (buffer); + close (pfd[0]); + + rc_waitpid (pid); plugin = plugin->next; } } |