Plugins now run in a forked process for extra resliance.

This commit is contained in:
Roy Marples 2007-04-20 09:39:47 +00:00
parent 49b8b30ab7
commit f269f1961b
5 changed files with 75 additions and 10 deletions

View File

@ -1,6 +1,10 @@
# ChangeLog for Gentoo System Intialization ("rc") scripts
# Copyright 1999-2007 Gentoo Foundation; Distributed under the GPLv2
20 Apr 2007; Roy Marples <uberlord@gentoo.org>:
Plugins now run in a forked process for extra resliance.
17 Apr 2007; Roy Marples <uberlord@gentoo.org>:
Fix bridge, vlan and bonding modules to work together, #174792.

View File

@ -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",

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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. */