diff options
author | Roy Marples <roy@marples.name> | 2007-04-20 09:39:47 +0000 |
---|---|---|
committer | Roy Marples <roy@marples.name> | 2007-04-20 09:39:47 +0000 |
commit | f269f1961b0b4adc094093301f712294a45dccc8 (patch) | |
tree | 4a9777b44c61fd7d04658bed2e8544d584a61ce0 /src | |
parent | 49b8b30ab7e35d8ad3cbe295eba3a93ba21a3509 (diff) |
Plugins now run in a forked process for extra resliance.
Diffstat (limited to 'src')
-rw-r--r-- | src/librc.c | 3 | ||||
-rw-r--r-- | src/rc-plugin.c | 73 | ||||
-rw-r--r-- | src/rc.c | 3 | ||||
-rw-r--r-- | src/rc.h | 4 |
4 files changed, 72 insertions, 11 deletions
diff --git a/src/librc.c b/src/librc.c index a0d09c7d..9172ee7c 100644 --- a/src/librc.c +++ b/src/librc.c @@ -15,6 +15,9 @@ #define SOFTLEVEL RC_SVCDIR "softlevel" +/* File stream used for plugins to write environ vars to */ +FILE *rc_environ_fd = NULL; + static const char *rc_service_state_names[] = { "started", "stopped", diff --git a/src/rc-plugin.c b/src/rc-plugin.c index 8a39e97d..aca20239 100644 --- a/src/rc-plugin.c +++ b/src/rc-plugin.c @@ -6,6 +6,8 @@ */ #include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -43,12 +45,7 @@ void rc_plugin_load (void) files = rc_ls_dir (NULL, RC_PLUGINDIR, 0); STRLIST_FOREACH (files, file, i) { char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL); - /* - * We load the use RTLD_NOW so that we know it works - * as if we have any unknown symbols when we run then the - * program bails out in rc_plugin_run which is very very bad. - */ - void *h = dlopen (p, RTLD_NOW); + void *h = dlopen (p, RTLD_LAZY); char *func; void *f; int len; @@ -94,9 +91,67 @@ void rc_plugin_run (rc_hook_t hook, const char *value) plugin_t *plugin = plugins; while (plugin) { - if (plugin->hook) - plugin->hook (hook, value); - + 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; + } + + /* 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; + } + + if (pid == 0) { + int retval; + + close (pfd[0]); + rc_environ_fd = fdopen (pfd[1], "w"); + retval = plugin->hook (hook, value); + fclose (rc_environ_fd); + rc_environ_fd = NULL; + _exit (retval); + } else { + char buffer[RC_LINEBUFFER]; + char *token; + char *p; + + close (pfd[1]); + memset (buffer, 0, sizeof (buffer)); + + /* Not the best implementation in the world. + * We should be able to handle >1 env var. + * Maybe split the strings with a NULL character? */ + while (read (pfd[0], buffer, sizeof (buffer)) > 0) { + p = buffer; + token = strsep (&p, "="); + if (token) { + unsetenv (token); + if (p) + setenv (token, p, 1); + } + } + + close (pfd[0]); + } + } plugin = plugin->next; } } @@ -1120,8 +1120,7 @@ interactive_option: } /* Wait for our services to finish */ - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - wait_for_services (); + wait_for_services (); rc_plugin_run (rc_hook_runlevel_start_out, runlevel); @@ -149,6 +149,10 @@ typedef enum rc_hook_service_start_out } rc_hook_t; +/* Plugins should write FOO=BAR to this fd to set any environment variables + * they wish. At this time we only support the setting of one env var. */ +extern FILE *rc_environ_fd; + /* RC utility functions. Although not directly related to RC in general, they are used by RC itself and the supporting applications. */ |