Added the rc-abort command, #175106 thanks to Daniel Drake.

This commit is contained in:
Roy Marples 2007-04-20 13:12:21 +00:00
parent a316a1fa72
commit c52f216450
7 changed files with 128 additions and 117 deletions

View File

@ -7,6 +7,8 @@
20 Apr 2007; Roy Marples <uberlord@gentoo.org>: 20 Apr 2007; Roy Marples <uberlord@gentoo.org>:
Added the rc-abort command, #175106 thanks to Daniel Drake.
Plugins now run in a forked process for extra resliance. Plugins now run in a forked process for extra resliance.
17 Apr 2007; Roy Marples <uberlord@gentoo.org>: 17 Apr 2007; Roy Marples <uberlord@gentoo.org>:

View File

@ -51,13 +51,8 @@ do_checkfs() {
if [ ${retval} -gt 3 ] ; then if [ ${retval} -gt 3 ] ; then
eend 2 "Fsck could not correct all errors, manual repair needed" eend 2 "Fsck could not correct all errors, manual repair needed"
if [ "${RC_SYS}" = "VPS" ] ; then rc-abort
halt -f exit 1
elif [ -x /sbin/sulogin ] ; then
sulogin "${CONSOLE}"
else
return 1
fi
fi fi
fi fi

View File

@ -104,8 +104,8 @@ start() {
retval=$? retval=$?
else else
eend 2 "Filesystem couldn't be fixed :(" eend 2 "Filesystem couldn't be fixed :("
[ "${RC_UNAME}" = "Linux" ] || return 1 rc-abort
sulogin "${CONSOLE}" exit 1
fi fi
if [ ${retval} != "0" ] ; then if [ ${retval} != "0" ] ; then
einfo "Unmounting filesystems" einfo "Unmounting filesystems"

View File

@ -5,6 +5,9 @@ CC ?= gcc
CFLAGS ?= -Wall -O2 -pipe CFLAGS ?= -Wall -O2 -pipe
check_gcc=$(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \
then echo "$(1)"; else echo "$(2)"; fi)
# Loads of nice flags to ensure our code is good # Loads of nice flags to ensure our code is good
CFLAGS += -pedantic -std=c99 \ CFLAGS += -pedantic -std=c99 \
-Wall -Wunused -Wimplicit -Wshadow -Wformat=2 \ -Wall -Wunused -Wimplicit -Wshadow -Wformat=2 \
@ -48,7 +51,7 @@ RCLINKS = einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
mark_service_stopping mark_service_stopped \ mark_service_stopping mark_service_stopped \
mark_service_inactive mark_service_wasinactive \ mark_service_inactive mark_service_wasinactive \
mark_service_coldplugged \ mark_service_coldplugged \
get_options save_options \ get_options save_options rc-abort \
is_runlevel_start is_runlevel_stop service_started_daemon is_runlevel_start is_runlevel_stop service_started_daemon
# Quick hack to make my life easier on BSD and Linux # Quick hack to make my life easier on BSD and Linux

View File

@ -469,22 +469,22 @@ static pid_t _exec_service (const char *service, const char *arg)
return (-1); return (-1);
} }
if ((pid = fork ()) == 0) { if ((pid = vfork ()) == 0) {
char *myarg = rc_xstrdup (arg);
int e = 0; int e = 0;
execl (file, file, myarg, (char *) NULL); execl (file, file, arg, (char *) NULL);
e = errno; e = errno;
free (myarg);
unlink (fifo); unlink (fifo);
free (fifo); free (fifo);
eerrorx ("unable to exec `%s': %s", file, strerror (errno)); eerror ("unable to exec `%s': %s", file, strerror (errno));
free (file);
_exit (EXIT_FAILURE);
} }
free (fifo); free (fifo);
free (file); free (file);
if (pid == -1) { if (pid == -1) {
eerror ("unable to fork: %s", strerror (errno)); eerror ("vfork: %s", strerror (errno));
return (pid); return (pid);
} }

175
src/rc.c
View File

@ -56,16 +56,14 @@ extern char **environ;
static char *applet = NULL; static char *applet = NULL;
static char **env = NULL; static char **env = NULL;
static char **newenv = NULL; static char **newenv = NULL;
static char **coldplugged_services; static char **coldplugged_services = NULL;
static char **stop_services = NULL; static char **stop_services = NULL;
static char **start_services = NULL; static char **start_services = NULL;
static rc_depinfo_t *deptree = NULL; static rc_depinfo_t *deptree = NULL;
static char **types = NULL; static char **types = NULL;
static char *mycmd = NULL;
static char *myarg = NULL;
static char *tmp = NULL; static char *tmp = NULL;
struct termios *termios_orig; struct termios *termios_orig = NULL;
static void cleanup (void) static void cleanup (void)
{ {
@ -76,24 +74,13 @@ static void cleanup (void)
free (termios_orig); free (termios_orig);
} }
if (env) rc_strlist_free (env);
rc_strlist_free (env); rc_strlist_free (newenv);
if (newenv) rc_strlist_free (coldplugged_services);
rc_strlist_free (newenv); rc_strlist_free (stop_services);
if (coldplugged_services) rc_strlist_free (start_services);
rc_strlist_free (coldplugged_services); rc_free_deptree (deptree);
if (stop_services) rc_strlist_free (types);
rc_strlist_free (stop_services);
if (start_services)
rc_strlist_free (start_services);
if (deptree)
rc_free_deptree (deptree);
if (types)
rc_strlist_free (types);
if (mycmd)
free (mycmd);
if (myarg)
free (myarg);
/* Clean runlevel start, stop markers */ /* Clean runlevel start, stop markers */
if (rc_is_dir (RC_SVCDIR "softscripts.new")) if (rc_is_dir (RC_SVCDIR "softscripts.new"))
@ -101,8 +88,7 @@ static void cleanup (void)
if (rc_is_dir (RC_SVCDIR "softscripts.old")) if (rc_is_dir (RC_SVCDIR "softscripts.old"))
rc_rm_dir (RC_SVCDIR "softscripts.old", true); rc_rm_dir (RC_SVCDIR "softscripts.old", true);
if (applet) free (applet);
free (applet);
} }
static int do_e (int argc, char **argv) static int do_e (int argc, char **argv)
@ -335,6 +321,10 @@ static char read_key (bool block)
struct termios termios; struct termios termios;
char c = 0; char c = 0;
/* This locks up rc for some reason!
* Why? it used to work fine... */
return 0;
if (! isatty (STDIN_FILENO)) if (! isatty (STDIN_FILENO))
return (false); return (false);
@ -378,33 +368,54 @@ static void mark_interactive (void)
static void sulogin (bool cont) static void sulogin (bool cont)
{ {
#ifdef __linux__ #ifdef __linux__
char *e = getenv ("RC_SYS");
/* VPS systems cannot do an sulogin */
if (e && strcmp (e, "VPS") == 0) {
execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
}
if (cont) { if (cont) {
int status = 0; int status = 0;
pid_t pid = fork(); pid_t pid = vfork();
if (pid == -1) if (pid == -1)
eerrorx ("%s: fork: %s", applet, strerror (errno)); eerrorx ("%s: vfork: %s", applet, strerror (errno));
if (pid == 0) { if (pid == 0) {
newenv = rc_filter_env (); newenv = rc_filter_env ();
mycmd = rc_xstrdup ("/sbin/sulogin"); execl ("/sbin/sulogin", "/sbin/sulogin",
myarg = rc_xstrdup (getenv ("CONSOLE")); getenv ("CONSOLE"), (char *) NULL, newenv);
execle (mycmd, mycmd, myarg, (char *) NULL, newenv); eerror ("%s: unable to exec `/sbin/sulogin': %s", applet,
eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); strerror (errno));
_exit (EXIT_FAILURE);
} }
waitpid (pid, &status, 0); waitpid (pid, &status, 0);
} else { } else {
newenv = rc_filter_env (); newenv = rc_filter_env ();
mycmd = rc_xstrdup ("/sbin/sulogin"); execl ("/sbin/sulogin", "/sbin/sulogin",
myarg = rc_xstrdup (getenv ("CONSOLE")); getenv ("CONSOLE"), (char *) NULL, newenv);
execle (mycmd, mycmd, myarg, (char *) NULL, newenv);
eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
} }
#else #else
/* Appease gcc */
exit (cont ? EXIT_FAILURE : EXIT_SUCCESS); exit (cont ? EXIT_FAILURE : EXIT_SUCCESS);
#endif #endif
} }
static void single_user (void)
{
#ifdef __linux__
execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
eerrorx ("%s: unable to exec `/sbin/telinit': %s",
applet, strerror (errno));
#else
if (kill (1, SIGTERM) != 0)
eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
applet, strerror (errno));
exit (EXIT_SUCCESS);
#endif
}
static void set_ksoftlevel (const char *runlevel) static void set_ksoftlevel (const char *runlevel)
{ {
FILE *fp; FILE *fp;
@ -457,6 +468,18 @@ static void handle_signal (int sig)
if (! signame[0]) if (! signame[0])
snprintf (signame, sizeof (signame), "SIGQUIT"); snprintf (signame, sizeof (signame), "SIGQUIT");
eerrorx ("%s: caught %s, aborting", applet, signame); eerrorx ("%s: caught %s, aborting", applet, signame);
case SIGUSR1:
eerror ("rc: Aborting!");
/* Kill any running services we have started */
signal (SIGTERM, SIG_IGN);
killpg (getpgrp (), SIGTERM);
/* If we're in boot runlevel then change into single-user mode */
if (strcmp (rc_get_runlevel (), RC_LEVEL_BOOT) == 0)
single_user ();
exit (EXIT_FAILURE);
break;
default: default:
eerror ("%s: caught unknown signal %d", applet, sig); eerror ("%s: caught unknown signal %d", applet, sig);
@ -480,6 +503,7 @@ int main (int argc, char **argv)
bool interactive = false; bool interactive = false;
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
char ksoftbuffer [PATH_MAX]; char ksoftbuffer [PATH_MAX];
char pidstr[6];
if (argv[0]) if (argv[0])
applet = rc_xstrdup (basename (argv[0])); applet = rc_xstrdup (basename (argv[0]));
@ -509,6 +533,19 @@ int main (int argc, char **argv)
else if (strcmp (applet, "is_runlevel_stop") == 0) else if (strcmp (applet, "is_runlevel_stop") == 0)
exit (rc_runlevel_stopping () ? 0 : 1); exit (rc_runlevel_stopping () ? 0 : 1);
if (strcmp (applet, "rc-abort") == 0) {
char *p = getenv ("RC_PID");
pid_t pid = 0;
if (p && sscanf (p, "%d", &pid) == 1) {
if (kill (pid, SIGUSR1) != 0)
eerrorx ("rc-abort: failed to signal parent %d: %s",
pid, strerror (errno));
exit (EXIT_SUCCESS);
}
exit (EXIT_FAILURE);
}
if (strcmp (applet, "rc" ) != 0) if (strcmp (applet, "rc" ) != 0)
eerrorx ("%s: unknown applet", applet); eerrorx ("%s: unknown applet", applet);
@ -520,10 +557,14 @@ int main (int argc, char **argv)
atexit (cleanup); atexit (cleanup);
newlevel = argv[0]; newlevel = argv[0];
/* Start a new process group */
setpgrp();
/* Setup a signal handler */ /* Setup a signal handler */
signal (SIGINT, handle_signal); signal (SIGINT, handle_signal);
signal (SIGQUIT, handle_signal); signal (SIGQUIT, handle_signal);
signal (SIGTERM, handle_signal); signal (SIGTERM, handle_signal);
signal (SIGUSR1, handle_signal);
/* Ensure our environment is pure /* Ensure our environment is pure
Also, add our configuration to it */ Also, add our configuration to it */
@ -563,6 +604,10 @@ int main (int argc, char **argv)
/* Enable logging */ /* Enable logging */
setenv ("RC_ELOG", "rc", 1); setenv ("RC_ELOG", "rc", 1);
/* Export our PID */
snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
setenv ("RC_PID", pidstr, 1);
interactive = rc_exists (INTERACTIVE); interactive = rc_exists (INTERACTIVE);
rc_plugin_load (); rc_plugin_load ();
@ -599,14 +644,14 @@ int main (int argc, char **argv)
setenv ("RC_SOFTLEVEL", newlevel, 1); setenv ("RC_SOFTLEVEL", newlevel, 1);
rc_plugin_run (rc_hook_runlevel_start_in, newlevel); rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
if ((pid = fork ()) == -1) if ((pid = vfork ()) == -1)
eerrorx ("%s: fork: %s", applet, strerror (errno)); eerrorx ("%s: vfork: %s", applet, strerror (errno));
if (pid == 0) { if (pid == 0) {
mycmd = rc_xstrdup (INITSH); execl (INITSH, INITSH, (char *) NULL);
execl (mycmd, mycmd, (char *) NULL); eerror ("%s: unable to exec `" INITSH "': %s",
eerrorx ("%s: unable to exec `" INITSH "': %s", applet, strerror (errno));
applet, strerror (errno)); _exit (EXIT_FAILURE);
} }
do { do {
@ -695,9 +740,7 @@ int main (int argc, char **argv)
eerrorx ("%s: couldn't find a runlevel called `%s'", eerrorx ("%s: couldn't find a runlevel called `%s'",
applet, newlevel); applet, newlevel);
} else { } else {
mycmd = rc_xstrdup ("/sbin/telinit"); execl ("/sbin/telinit", "/sbin/telinit", lvl, (char *) NULL);
myarg = rc_xstrdup (lvl);
execl (mycmd, mycmd, myarg, (char *) NULL);
eerrorx ("%s: unable to exec `/sbin/telinit': %s", eerrorx ("%s: unable to exec `/sbin/telinit': %s",
applet, strerror (errno)); applet, strerror (errno));
} }
@ -712,11 +755,6 @@ int main (int argc, char **argv)
rc reboot rc reboot
*/ */
if (newlevel) { if (newlevel) {
if (myarg) {
free (myarg);
myarg = NULL;
}
if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) { if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
if (! RUNLEVEL || if (! RUNLEVEL ||
(strcmp (RUNLEVEL, "S") != 0 && (strcmp (RUNLEVEL, "S") != 0 &&
@ -724,44 +762,29 @@ int main (int argc, char **argv)
{ {
/* Remember the current runlevel for when we come back */ /* Remember the current runlevel for when we come back */
set_ksoftlevel (runlevel); set_ksoftlevel (runlevel);
#ifdef __linux__ single_user ();
mycmd = rc_xstrdup ("/sbin/telinit");
myarg = rc_xstrdup ("S");
execl (mycmd, mycmd, myarg, (char *) NULL);
eerrorx ("%s: unable to exec `/%s': %s",
mycmd, applet, strerror (errno));
#else
if (kill (1, SIGTERM) != 0)
eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
applet, strerror (errno));
exit (EXIT_SUCCESS);
#endif
} }
} else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) { } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
if (! RUNLEVEL || if (! RUNLEVEL ||
strcmp (RUNLEVEL, "6") != 0) strcmp (RUNLEVEL, "6") != 0)
{ {
mycmd = rc_xstrdup ("/sbin/shutdown"); execl ("/sbin/shutdown", "/sbin/shutdown", "-r", "now", (char *) NULL);
myarg = rc_xstrdup ("-r"); eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
tmp = rc_xstrdup ("now"); applet, strerror (errno));
execl (mycmd, mycmd, myarg, tmp, (char *) NULL);
eerrorx ("%s: unable to exec `%s': %s",
mycmd, applet, strerror (errno));
} }
} else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) { } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
if (! RUNLEVEL || if (! RUNLEVEL ||
strcmp (RUNLEVEL, "0") != 0) strcmp (RUNLEVEL, "0") != 0)
{ {
mycmd = rc_xstrdup ("/sbin/shutdown"); execl ("/sbin/shutdown", "/sbin/shutdown",
#ifdef __linux__ #ifdef __linux
myarg = rc_xstrdup ("-h"); "-h",
#else #else
myarg = rc_xstrdup ("-p"); "-p",
#endif #endif
tmp = rc_xstrdup ("now"); "now", (char *) NULL);
execl (mycmd, mycmd, myarg, tmp, (char *) NULL); eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
eerrorx ("%s: unable to exec `%s': %s", applet, strerror (errno));
mycmd, applet, strerror (errno));
} }
} }
} }
@ -1060,9 +1083,7 @@ int main (int argc, char **argv)
if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp (runlevel, RC_LEVEL_REBOOT) == 0) strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
{ {
mycmd = rc_xstrdup (HALTSH); execl (HALTSH, HALTSH, runlevel, (char *) NULL);
myarg = rc_xstrdup (runlevel);
execl (mycmd, mycmd, myarg, (char *) NULL);
eerrorx ("%s: unable to exec `%s': %s", eerrorx ("%s: unable to exec `%s': %s",
applet, HALTSH, strerror (errno)); applet, HALTSH, strerror (errno));
} }

View File

@ -43,9 +43,6 @@ static char **types = NULL;
static char **restart_services = NULL; static char **restart_services = NULL;
static char **need_services = NULL; static char **need_services = NULL;
static char **env = NULL; static char **env = NULL;
static char *mycmd = NULL;
static char *myarg1 = NULL;
static char *myarg2 = NULL;
static char *tmp = NULL; static char *tmp = NULL;
static char *softlevel = NULL; static char *softlevel = NULL;
static bool sighup = false; static bool sighup = false;
@ -69,10 +66,12 @@ void setup_selinux (int argc, char **argv)
lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL); lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
if (lib_handle) { if (lib_handle) {
/* FIXME: the below code generates the warning /*
ISO C forbids assignment between function pointer and 'void *' * FIXME: the below code generates the warning
which sucks ass * ISO C forbids assignment between function pointer and 'void *'
http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html */ * which sucks ass
* http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html
*/
selinux_run_init_old = dlsym (lib_handle, "selinux_runscript"); selinux_run_init_old = dlsym (lib_handle, "selinux_runscript");
selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2"); selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2");
@ -216,12 +215,6 @@ static void cleanup (void)
rc_strlist_free (need_services); rc_strlist_free (need_services);
if (tmplist) if (tmplist)
rc_strlist_free (tmplist); rc_strlist_free (tmplist);
if (mycmd)
free (mycmd);
if (myarg1)
free (myarg1);
if (myarg2)
free (myarg2);
if (ibsave) if (ibsave)
free (ibsave); free (ibsave);
@ -273,26 +266,23 @@ static bool svc_exec (const char *service, const char *arg1, const char *arg2)
until our script returns. */ until our script returns. */
signal (SIGCHLD, NULL); signal (SIGCHLD, NULL);
pid = fork(); pid = vfork();
if (pid == -1) if (pid == -1)
eerrorx ("%s: fork: %s", service, strerror (errno)); eerrorx ("%s: vfork: %s", service, strerror (errno));
if (pid == 0) { if (pid == 0) {
mycmd = rc_xstrdup (service);
myarg1 = rc_xstrdup (arg1);
if (arg2)
myarg2 = rc_xstrdup (arg2);
if (rc_exists (RC_SVCDIR "runscript.sh")) { if (rc_exists (RC_SVCDIR "runscript.sh")) {
execl (RC_SVCDIR "runscript.sh", mycmd, mycmd, myarg1, myarg2, execl (RC_SVCDIR "runscript.sh", service, service, arg1, arg2,
(char *) NULL); (char *) NULL);
eerrorx ("%s: exec `" RC_SVCDIR "runscript.sh': %s", eerror ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
service, strerror (errno)); service, strerror (errno));
_exit (EXIT_FAILURE);
} else { } else {
execl (RC_LIBDIR "sh/runscript.sh", mycmd, mycmd, myarg1, myarg2, execl (RC_LIBDIR "sh/runscript.sh", service, service, arg1, arg2,
(char *) NULL); (char *) NULL);
eerrorx ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s", eerror ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
service, strerror (errno)); service, strerror (errno));
_exit (EXIT_FAILURE);
} }
} }