aboutsummaryrefslogtreecommitdiff
path: root/src/rc/rc-plugin.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2008-02-02 00:17:35 +0000
committerRoy Marples <roy@marples.name>2008-02-02 00:17:35 +0000
commitad045176238549c3267fff3e8c0014dd5e9ffbdf (patch)
tree8332746190f8e9fc47007090a3beac0a64d133c6 /src/rc/rc-plugin.c
parentfef5d0af591c6c8a91f69bba5e62c99df1a732c9 (diff)
Block signals to avoid fork /signal races.
Diffstat (limited to 'src/rc/rc-plugin.c')
-rw-r--r--src/rc/rc-plugin.c158
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;
}
}