diff options
Diffstat (limited to 'src/rc.c')
-rw-r--r-- | src/rc.c | 2048 |
1 files changed, 985 insertions, 1063 deletions
@@ -46,11 +46,9 @@ #define DEVBOOT "/dev/.rcboot" /* Cleanup anything in main */ -#define CHAR_FREE(_item) \ - if (_item) \ -{ \ - free (_item); \ - _item = NULL; \ +#define CHAR_FREE(_item) if (_item) { \ + free (_item); \ + _item = NULL; \ } extern char **environ; @@ -71,1142 +69,1066 @@ struct termios *termios_orig; static void cleanup (void) { - rc_plugin_unload (); - - if (termios_orig) - { - tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); - free (termios_orig); - } - - if (env) - rc_strlist_free (env); - if (newenv) - rc_strlist_free (newenv); - if (coldplugged_services) - rc_strlist_free (coldplugged_services); - if (stop_services) - 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 */ - if (rc_is_dir (RC_SVCDIR "softscripts.new")) - rc_rm_dir (RC_SVCDIR "softscripts.new", true); - if (rc_is_dir (RC_SVCDIR "softscripts.old")) - rc_rm_dir (RC_SVCDIR "softscripts.old", true); - - if (applet) - free (applet); + rc_plugin_unload (); + + if (termios_orig) { + tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); + free (termios_orig); + } + + if (env) + rc_strlist_free (env); + if (newenv) + rc_strlist_free (newenv); + if (coldplugged_services) + rc_strlist_free (coldplugged_services); + if (stop_services) + 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 */ + if (rc_is_dir (RC_SVCDIR "softscripts.new")) + rc_rm_dir (RC_SVCDIR "softscripts.new", true); + if (rc_is_dir (RC_SVCDIR "softscripts.old")) + rc_rm_dir (RC_SVCDIR "softscripts.old", true); + + if (applet) + free (applet); } static int do_e (int argc, char **argv) { - int retval = EXIT_SUCCESS; - int i; - int l = 0; - char *message = NULL; - char *p; - char *fmt = NULL; - - if (strcmp (applet, "eend") == 0 || - strcmp (applet, "ewend") == 0 || - strcmp (applet, "veend") == 0 || - strcmp (applet, "vweend") == 0) - { - if (argc > 0) - { - errno = 0; - retval = strtol (argv[0], NULL, 0); - if (errno != 0) - retval = EXIT_FAILURE; - else - { - argc--; - argv++; - } - } - else - retval = EXIT_FAILURE; - } - - if (argc > 0) - { - for (i = 0; i < argc; i++) - l += strlen (argv[i]) + 1; - - message = rc_xmalloc (l); - p = message; - - for (i = 0; i < argc; i++) - { - if (i > 0) - *p++ = ' '; - memcpy (p, argv[i], strlen (argv[i])); - p += strlen (argv[i]); - } - *p = 0; - } - - if (message) - fmt = strdup ("%s"); - - if (strcmp (applet, "einfo") == 0) - einfo (fmt, message); - else if (strcmp (applet, "einfon") == 0) - einfon (fmt, message); - else if (strcmp (applet, "ewarn") == 0) - ewarn (fmt, message); - else if (strcmp (applet, "ewarnn") == 0) - ewarnn (fmt, message); - else if (strcmp (applet, "eerror") == 0) - { - eerror (fmt, message); - retval = 1; - } - else if (strcmp (applet, "eerrorn") == 0) - { - eerrorn (fmt, message); - retval = 1; - } - else if (strcmp (applet, "ebegin") == 0) - ebegin (fmt, message); - else if (strcmp (applet, "eend") == 0) - eend (retval, fmt, message); - else if (strcmp (applet, "ewend") == 0) - ewend (retval, fmt, message); - else if (strcmp (applet, "veinfo") == 0) - einfov (fmt, message); - else if (strcmp (applet, "veinfon") == 0) - einfovn (fmt, message); - else if (strcmp (applet, "vewarn") == 0) - ewarnv (fmt, message); - else if (strcmp (applet, "vewarnn") == 0) - ewarnvn (fmt, message); - else if (strcmp (applet, "vebegin") == 0) - ebeginv (fmt, message); - else if (strcmp (applet, "veend") == 0) - eendv (retval, fmt, message); - else if (strcmp (applet, "vewend") == 0) - ewendv (retval, fmt, message); - else if (strcmp (applet, "eindent") == 0) - eindent (); - else if (strcmp (applet, "eoutdent") == 0) - eoutdent (); - else if (strcmp (applet, "veindent") == 0) - eindentv (); - else if (strcmp (applet, "veoutdent") == 0) - eoutdentv (); - else if (strcmp (applet, "eflush") == 0) - eflush (); - else - { - eerror ("%s: unknown applet", applet); - retval = EXIT_FAILURE; - } - - if (fmt) - free (fmt); - if (message) - free (message); - return (retval); + int retval = EXIT_SUCCESS; + int i; + int l = 0; + char *message = NULL; + char *p; + char *fmt = NULL; + + if (strcmp (applet, "eend") == 0 || + strcmp (applet, "ewend") == 0 || + strcmp (applet, "veend") == 0 || + strcmp (applet, "vweend") == 0) + { + if (argc > 0) { + errno = 0; + retval = strtol (argv[0], NULL, 0); + if (errno != 0) + retval = EXIT_FAILURE; + else { + argc--; + argv++; + } + } + else + retval = EXIT_FAILURE; + } + + if (argc > 0) { + for (i = 0; i < argc; i++) + l += strlen (argv[i]) + 1; + + message = rc_xmalloc (l); + p = message; + + for (i = 0; i < argc; i++) { + if (i > 0) + *p++ = ' '; + memcpy (p, argv[i], strlen (argv[i])); + p += strlen (argv[i]); + } + *p = 0; + } + + if (message) + fmt = strdup ("%s"); + + if (strcmp (applet, "einfo") == 0) + einfo (fmt, message); + else if (strcmp (applet, "einfon") == 0) + einfon (fmt, message); + else if (strcmp (applet, "ewarn") == 0) + ewarn (fmt, message); + else if (strcmp (applet, "ewarnn") == 0) + ewarnn (fmt, message); + else if (strcmp (applet, "eerror") == 0) { + eerror (fmt, message); + retval = 1; + } else if (strcmp (applet, "eerrorn") == 0) { + eerrorn (fmt, message); + retval = 1; + } else if (strcmp (applet, "ebegin") == 0) + ebegin (fmt, message); + else if (strcmp (applet, "eend") == 0) + eend (retval, fmt, message); + else if (strcmp (applet, "ewend") == 0) + ewend (retval, fmt, message); + else if (strcmp (applet, "veinfo") == 0) + einfov (fmt, message); + else if (strcmp (applet, "veinfon") == 0) + einfovn (fmt, message); + else if (strcmp (applet, "vewarn") == 0) + ewarnv (fmt, message); + else if (strcmp (applet, "vewarnn") == 0) + ewarnvn (fmt, message); + else if (strcmp (applet, "vebegin") == 0) + ebeginv (fmt, message); + else if (strcmp (applet, "veend") == 0) + eendv (retval, fmt, message); + else if (strcmp (applet, "vewend") == 0) + ewendv (retval, fmt, message); + else if (strcmp (applet, "eindent") == 0) + eindent (); + else if (strcmp (applet, "eoutdent") == 0) + eoutdent (); + else if (strcmp (applet, "veindent") == 0) + eindentv (); + else if (strcmp (applet, "veoutdent") == 0) + eoutdentv (); + else if (strcmp (applet, "eflush") == 0) + eflush (); + else { + eerror ("%s: unknown applet", applet); + retval = EXIT_FAILURE; + } + + if (fmt) + free (fmt); + if (message) + free (message); + return (retval); } static int do_service (int argc, char **argv) { - bool ok = false; - - if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) - eerrorx ("%s: no service specified", applet); - - if (strcmp (applet, "service_started") == 0) - ok = rc_service_state (argv[0], rc_service_started); - else if (strcmp (applet, "service_stopped") == 0) - ok = rc_service_state (argv[0], rc_service_stopped); - else if (strcmp (applet, "service_inactive") == 0) - ok = rc_service_state (argv[0], rc_service_inactive); - else if (strcmp (applet, "service_starting") == 0) - ok = rc_service_state (argv[0], rc_service_starting); - else if (strcmp (applet, "service_stopping") == 0) - ok = rc_service_state (argv[0], rc_service_stopping); - else if (strcmp (applet, "service_coldplugged") == 0) - ok = rc_service_state (argv[0], rc_service_coldplugged); - else if (strcmp (applet, "service_wasinactive") == 0) - ok = rc_service_state (argv[0], rc_service_wasinactive); - else if (strcmp (applet, "service_started_daemon") == 0) - { - int idx = 0; - if (argc > 2) - sscanf (argv[2], "%d", &idx); - exit (rc_service_started_daemon (argv[0], argv[1], idx) - ? 0 : 1); - } - else - eerrorx ("%s: unknown applet", applet); - - return (ok ? EXIT_SUCCESS : EXIT_FAILURE); + bool ok = false; + + if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) + eerrorx ("%s: no service specified", applet); + + if (strcmp (applet, "service_started") == 0) + ok = rc_service_state (argv[0], rc_service_started); + else if (strcmp (applet, "service_stopped") == 0) + ok = rc_service_state (argv[0], rc_service_stopped); + else if (strcmp (applet, "service_inactive") == 0) + ok = rc_service_state (argv[0], rc_service_inactive); + else if (strcmp (applet, "service_starting") == 0) + ok = rc_service_state (argv[0], rc_service_starting); + else if (strcmp (applet, "service_stopping") == 0) + ok = rc_service_state (argv[0], rc_service_stopping); + else if (strcmp (applet, "service_coldplugged") == 0) + ok = rc_service_state (argv[0], rc_service_coldplugged); + else if (strcmp (applet, "service_wasinactive") == 0) + ok = rc_service_state (argv[0], rc_service_wasinactive); + else if (strcmp (applet, "service_started_daemon") == 0) { + int idx = 0; + if (argc > 2) + sscanf (argv[2], "%d", &idx); + exit (rc_service_started_daemon (argv[0], argv[1], idx) + ? 0 : 1); + } else + eerrorx ("%s: unknown applet", applet); + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static int do_mark_service (int argc, char **argv) { - bool ok = false; - char *svcname = getenv ("SVCNAME"); - - if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) - eerrorx ("%s: no service specified", applet); - - if (strcmp (applet, "mark_service_started") == 0) - ok = rc_mark_service (argv[0], rc_service_started); - else if (strcmp (applet, "mark_service_stopped") == 0) - ok = rc_mark_service (argv[0], rc_service_stopped); - else if (strcmp (applet, "mark_service_inactive") == 0) - ok = rc_mark_service (argv[0], rc_service_inactive); - else if (strcmp (applet, "mark_service_starting") == 0) - ok = rc_mark_service (argv[0], rc_service_starting); - else if (strcmp (applet, "mark_service_stopping") == 0) - ok = rc_mark_service (argv[0], rc_service_stopping); - else if (strcmp (applet, "mark_service_coldplugged") == 0) - ok = rc_mark_service (argv[0], rc_service_coldplugged); - else - eerrorx ("%s: unknown applet", applet); - - /* If we're marking ourselves then we need to inform our parent runscript - process so they do not mark us based on our exit code */ - if (ok && svcname && strcmp (svcname, argv[0]) == 0) - { - char *runscript_pid = getenv ("RC_RUNSCRIPT_PID"); - char *mtime; - pid_t pid = 0; - int l; - - if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1) - if (kill (pid, SIGHUP) != 0) - eerror ("%s: failed to signal parent %d: %s", - applet, pid, strerror (errno)); - - /* Remove the exclsive time test. This ensures that it's not - in control as well */ - l = strlen (RC_SVCDIR "exclusive") + - strlen (svcname) + - strlen (runscript_pid) + - 4; - mtime = rc_xmalloc (l); - snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s", - svcname, runscript_pid); - if (rc_exists (mtime) && unlink (mtime) != 0) - eerror ("%s: unlink: %s", applet, strerror (errno)); - free (mtime); - } - - return (ok ? EXIT_SUCCESS : EXIT_FAILURE); + bool ok = false; + char *svcname = getenv ("SVCNAME"); + + if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) + eerrorx ("%s: no service specified", applet); + + if (strcmp (applet, "mark_service_started") == 0) + ok = rc_mark_service (argv[0], rc_service_started); + else if (strcmp (applet, "mark_service_stopped") == 0) + ok = rc_mark_service (argv[0], rc_service_stopped); + else if (strcmp (applet, "mark_service_inactive") == 0) + ok = rc_mark_service (argv[0], rc_service_inactive); + else if (strcmp (applet, "mark_service_starting") == 0) + ok = rc_mark_service (argv[0], rc_service_starting); + else if (strcmp (applet, "mark_service_stopping") == 0) + ok = rc_mark_service (argv[0], rc_service_stopping); + else if (strcmp (applet, "mark_service_coldplugged") == 0) + ok = rc_mark_service (argv[0], rc_service_coldplugged); + else + eerrorx ("%s: unknown applet", applet); + + /* If we're marking ourselves then we need to inform our parent runscript + process so they do not mark us based on our exit code */ + if (ok && svcname && strcmp (svcname, argv[0]) == 0) { + char *runscript_pid = getenv ("RC_RUNSCRIPT_PID"); + char *mtime; + pid_t pid = 0; + int l; + + if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1) + if (kill (pid, SIGHUP) != 0) + eerror ("%s: failed to signal parent %d: %s", + applet, pid, strerror (errno)); + + /* Remove the exclsive time test. This ensures that it's not + in control as well */ + l = strlen (RC_SVCDIR "exclusive") + + strlen (svcname) + + strlen (runscript_pid) + + 4; + mtime = rc_xmalloc (l); + snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s", + svcname, runscript_pid); + if (rc_exists (mtime) && unlink (mtime) != 0) + eerror ("%s: unlink: %s", applet, strerror (errno)); + free (mtime); + } + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static int do_options (int argc, char **argv) { - bool ok = false; - char *service = getenv ("SVCNAME"); - - if (! service) - eerrorx ("%s: no service specified", applet); - - if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) - eerrorx ("%s: no option specified", applet); - - if (strcmp (applet, "get_options") == 0) - { - char buffer[1024]; - memset (buffer, 0, 1024); - ok = rc_get_service_option (service, argv[0], buffer); - if (ok) - printf ("%s", buffer); - } - else if (strcmp (applet, "save_options") == 0) - ok = rc_set_service_option (service, argv[0], argv[1]); - else - eerrorx ("%s: unknown applet", applet); - - return (ok ? EXIT_SUCCESS : EXIT_FAILURE); + bool ok = false; + char *service = getenv ("SVCNAME"); + + if (! service) + eerrorx ("%s: no service specified", applet); + + if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) + eerrorx ("%s: no option specified", applet); + + if (strcmp (applet, "get_options") == 0) { + char buffer[1024]; + memset (buffer, 0, 1024); + ok = rc_get_service_option (service, argv[0], buffer); + if (ok) + printf ("%s", buffer); + } else if (strcmp (applet, "save_options") == 0) + ok = rc_set_service_option (service, argv[0], argv[1]); + else + eerrorx ("%s: unknown applet", applet); + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static char read_key (bool block) { - struct termios termios; - char c = 0; - - if (! isatty (STDIN_FILENO)) - return (false); - - /* Now save our terminal settings. We need to restore them at exit as we - will be changing it for non-blocking reads for Interactive */ - if (! termios_orig) - { - termios_orig = rc_xmalloc (sizeof (struct termios)); - tcgetattr (STDIN_FILENO, termios_orig); - } - - tcgetattr (STDIN_FILENO, &termios); - termios.c_lflag &= ~(ICANON | ECHO); - if (block) - termios.c_cc[VMIN] = 1; - else - { - termios.c_cc[VMIN] = 0; - termios.c_cc[VTIME] = 0; - } - tcsetattr (STDIN_FILENO, TCSANOW, &termios); - - read (STDIN_FILENO, &c, 1); - - tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); - - return (c); + struct termios termios; + char c = 0; + + if (! isatty (STDIN_FILENO)) + return (false); + + /* Now save our terminal settings. We need to restore them at exit as we + will be changing it for non-blocking reads for Interactive */ + if (! termios_orig) { + termios_orig = rc_xmalloc (sizeof (struct termios)); + tcgetattr (STDIN_FILENO, termios_orig); + } + + tcgetattr (STDIN_FILENO, &termios); + termios.c_lflag &= ~(ICANON | ECHO); + if (block) + termios.c_cc[VMIN] = 1; + else { + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 0; + } + tcsetattr (STDIN_FILENO, TCSANOW, &termios); + + read (STDIN_FILENO, &c, 1); + + tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); + + return (c); } static bool want_interactive (void) { - char c = read_key (false); - return ((c == 'I' || c == 'i') ? true : false); + char c = read_key (false); + return ((c == 'I' || c == 'i') ? true : false); } static void mark_interactive (void) { - FILE *fp = fopen (INTERACTIVE, "w"); - if (fp) - fclose (fp); + FILE *fp = fopen (INTERACTIVE, "w"); + if (fp) + fclose (fp); } static void sulogin (bool cont) { #ifdef __linux__ - if (cont) - { - int status = 0; - pid_t pid = fork(); - - if (pid == -1) - eerrorx ("%s: fork: %s", applet, strerror (errno)); - if (pid == 0) - { - newenv = rc_filter_env (); - mycmd = rc_xstrdup ("/sbin/sulogin"); - myarg = rc_xstrdup (getenv ("CONSOLE")); - execle (mycmd, mycmd, myarg, (char *) NULL, newenv); - eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); - } - waitpid (pid, &status, 0); - } - else - { - - newenv = rc_filter_env (); - mycmd = rc_xstrdup ("/sbin/sulogin"); - myarg = rc_xstrdup (getenv ("CONSOLE")); - execle (mycmd, mycmd, myarg, (char *) NULL, newenv); - eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); - } + if (cont) { + int status = 0; + pid_t pid = fork(); + + if (pid == -1) + eerrorx ("%s: fork: %s", applet, strerror (errno)); + if (pid == 0) { + newenv = rc_filter_env (); + mycmd = rc_xstrdup ("/sbin/sulogin"); + myarg = rc_xstrdup (getenv ("CONSOLE")); + execle (mycmd, mycmd, myarg, (char *) NULL, newenv); + eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); + } + waitpid (pid, &status, 0); + } else { + newenv = rc_filter_env (); + mycmd = rc_xstrdup ("/sbin/sulogin"); + myarg = rc_xstrdup (getenv ("CONSOLE")); + execle (mycmd, mycmd, myarg, (char *) NULL, newenv); + eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); + } #else - /* Appease gcc */ - cont = cont; - exit (EXIT_SUCCESS); + /* Appease gcc */ + exit (cont ? EXIT_FAILURE : EXIT_SUCCESS); #endif } static void set_ksoftlevel (const char *runlevel) { - FILE *fp; - - if (! runlevel || - strcmp (runlevel, RC_LEVEL_BOOT) == 0 || - strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || - strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) - { - if (rc_exists (RC_SVCDIR "ksoftlevel") && - unlink (RC_SVCDIR "ksoftlevel") != 0) - eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); - return; - } - - if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w"))) - { - eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); - return; - } - - fprintf (fp, "%s", runlevel); - fclose (fp); + FILE *fp; + + if (! runlevel || + strcmp (runlevel, RC_LEVEL_BOOT) == 0 || + strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || + strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) + { + if (rc_exists (RC_SVCDIR "ksoftlevel") && + unlink (RC_SVCDIR "ksoftlevel") != 0) + eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); + return; + } + + if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w"))) { + eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); + return; + } + + fprintf (fp, "%s", runlevel); + fclose (fp); } static void wait_for_services () { - int status = 0; - struct timeval tv; - while (wait (&status) != -1); - - /* Wait for a little bit to flush our ebuffer */ - tv.tv_usec = 50000; - tv.tv_sec = 0; - select (0, NULL, NULL, NULL, &tv); + int status = 0; + struct timeval tv; + while (wait (&status) != -1); + + /* Wait for a little bit to flush our ebuffer */ + tv.tv_usec = 50000; + tv.tv_sec = 0; + select (0, NULL, NULL, NULL, &tv); } static void handle_signal (int sig) { - int serrno = errno; - char signame[10] = { '\0' }; - - switch (sig) - { - case SIGINT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGINT"); - case SIGTERM: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGTERM"); - case SIGQUIT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGQUIT"); - eerrorx ("%s: caught %s, aborting", applet, signame); - - default: - eerror ("%s: caught unknown signal %d", applet, sig); - } - - /* Restore errno */ - errno = serrno; + int serrno = errno; + char signame[10] = { '\0' }; + + switch (sig) { + case SIGINT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGINT"); + case SIGTERM: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGTERM"); + case SIGQUIT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGQUIT"); + eerrorx ("%s: caught %s, aborting", applet, signame); + + default: + eerror ("%s: caught unknown signal %d", applet, sig); + } + + /* Restore errno */ + errno = serrno; } int main (int argc, char **argv) { - char *RUNLEVEL = NULL; - char *PREVLEVEL = NULL; - char *runlevel = NULL; - char *newlevel = NULL; - char *service = NULL; - char **deporder = NULL; - int i = 0; - int j = 0; - bool going_down = false; - bool interactive = false; - int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; - char ksoftbuffer [PATH_MAX]; - - if (argv[0]) - applet = strdup (basename (argv[0])); - - if (! applet) - eerrorx ("arguments required"); - - argc--; - argv++; - - /* Handle multicall stuff */ - if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e')) - exit (do_e (argc, argv)); - - if (strncmp (applet, "service_", strlen ("service_")) == 0) - exit (do_service (argc, argv)); - - if (strcmp (applet, "get_options") == 0 || - strcmp (applet, "save_options") == 0) - exit (do_options (argc, argv)); - - if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0) - exit (do_mark_service (argc, argv)); - - if (strcmp (applet, "is_runlevel_start") == 0) - exit (rc_runlevel_starting () ? 0 : 1); - else if (strcmp (applet, "is_runlevel_stop") == 0) - exit (rc_runlevel_stopping () ? 0 : 1); - else if (strcmp (applet, "color_terminal") == 0) - exit (colour_terminal () ? 0 : 1); - - if (strcmp (applet, "rc" ) != 0) - eerrorx ("%s: unknown applet", applet); - - /* OK, so we really are the main RC process - Only root should be able to run us */ - if (geteuid () != 0) - eerrorx ("%s: root access required", applet); - - atexit (cleanup); - newlevel = argv[0]; - - /* Setup a signal handler */ - signal (SIGINT, handle_signal); - signal (SIGQUIT, handle_signal); - signal (SIGTERM, handle_signal); - - /* Ensure our environment is pure - Also, add our configuration to it */ - env = rc_filter_env (); - env = rc_config_env (env); - - if (env) - { - char *p; + char *RUNLEVEL = NULL; + char *PREVLEVEL = NULL; + char *runlevel = NULL; + char *newlevel = NULL; + char *service = NULL; + char **deporder = NULL; + int i = 0; + int j = 0; + bool going_down = false; + bool interactive = false; + int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; + char ksoftbuffer [PATH_MAX]; + + if (argv[0]) + applet = strdup (basename (argv[0])); + + if (! applet) + eerrorx ("arguments required"); + + argc--; + argv++; + + /* Handle multicall stuff */ + if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e')) + exit (do_e (argc, argv)); + + if (strncmp (applet, "service_", strlen ("service_")) == 0) + exit (do_service (argc, argv)); + + if (strcmp (applet, "get_options") == 0 || + strcmp (applet, "save_options") == 0) + exit (do_options (argc, argv)); + + if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0) + exit (do_mark_service (argc, argv)); + + if (strcmp (applet, "is_runlevel_start") == 0) + exit (rc_runlevel_starting () ? 0 : 1); + else if (strcmp (applet, "is_runlevel_stop") == 0) + exit (rc_runlevel_stopping () ? 0 : 1); + else if (strcmp (applet, "color_terminal") == 0) + exit (colour_terminal () ? 0 : 1); + + if (strcmp (applet, "rc" ) != 0) + eerrorx ("%s: unknown applet", applet); + + /* OK, so we really are the main RC process + Only root should be able to run us */ + if (geteuid () != 0) + eerrorx ("%s: root access required", applet); + + atexit (cleanup); + newlevel = argv[0]; + + /* Setup a signal handler */ + signal (SIGINT, handle_signal); + signal (SIGQUIT, handle_signal); + signal (SIGTERM, handle_signal); + + /* Ensure our environment is pure + Also, add our configuration to it */ + env = rc_filter_env (); + env = rc_config_env (env); + + if (env) { + char *p; #ifdef __linux__ - /* clearenv isn't portable, but there's no harm in using it - if we have it */ - clearenv (); + /* clearenv isn't portable, but there's no harm in using it + if we have it */ + clearenv (); #else - char *var; - /* No clearenv present here then. - We could manipulate environ directly ourselves, but it seems that - some kernels bitch about this according to the environ man pages - so we walk though environ and call unsetenv for each value. */ - while (environ[0]) - { - tmp = rc_xstrdup (environ[0]); - p = tmp; - var = strsep (&p, "="); - unsetenv (var); - free (tmp); - } - tmp = NULL; + char *var; + /* No clearenv present here then. + We could manipulate environ directly ourselves, but it seems that + some kernels bitch about this according to the environ man pages + so we walk though environ and call unsetenv for each value. */ + while (environ[0]) { + tmp = rc_xstrdup (environ[0]); + p = tmp; + var = strsep (&p, "="); + unsetenv (var); + free (tmp); + } + tmp = NULL; #endif - STRLIST_FOREACH (env, p, i) - if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0) - putenv (p); - - /* We don't free our list as that would be null in environ */ - } - - /* Enable logging */ - setenv ("RC_ELOG", "rc", 1); - - interactive = rc_exists (INTERACTIVE); - rc_plugin_load (); - - /* RUNLEVEL is set by sysvinit as is a magic number - RC_SOFTLEVEL is set by us and is the name for this magic number - even though all our userland documentation refers to runlevel */ - RUNLEVEL = getenv ("RUNLEVEL"); - PREVLEVEL = getenv ("PREVLEVEL"); - - if (RUNLEVEL && newlevel) - { - if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0) - { - /* OK, we're either in runlevel 1 or single user mode */ - if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0) - { - struct utsname uts; - pid_t pid; - pid_t wpid; - int status = 0; + STRLIST_FOREACH (env, p, i) + if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0) + putenv (p); + + /* We don't free our list as that would be null in environ */ + } + + /* Enable logging */ + setenv ("RC_ELOG", "rc", 1); + + interactive = rc_exists (INTERACTIVE); + rc_plugin_load (); + + /* RUNLEVEL is set by sysvinit as is a magic number + RC_SOFTLEVEL is set by us and is the name for this magic number + even though all our userland documentation refers to runlevel */ + RUNLEVEL = getenv ("RUNLEVEL"); + PREVLEVEL = getenv ("PREVLEVEL"); + + if (RUNLEVEL && newlevel) { + if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0) { + /* OK, we're either in runlevel 1 or single user mode */ + if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0) { + struct utsname uts; + pid_t pid; + pid_t wpid; + int status = 0; #ifdef __linux__ - FILE *fp; + FILE *fp; #endif - uname (&uts); - - printf ("\n"); - PEINFO_GOOD; - printf (" Gentoo/%s; ", uts.sysname); - PEINFO_BRACKET; - printf ("http://www.gentoo.org/"); - PEINFO_NORMAL; - printf ("\n Copyright 1999-2007 Gentoo Foundation; " - "Distributed under the GPLv2\n\n"); - - printf ("Press "); - PEINFO_GOOD; - printf ("I"); - PEINFO_NORMAL; - printf (" to enter interactive boot mode\n\n"); - - setenv ("RC_SOFTLEVEL", newlevel, 1); - rc_plugin_run (rc_hook_runlevel_start_in, newlevel); - - if ((pid = fork ()) == -1) - eerrorx ("%s: fork: %s", applet, strerror (errno)); - - if (pid == 0) - { - mycmd = rc_xstrdup (INITSH); - execl (mycmd, mycmd, (char *) NULL); - eerrorx ("%s: unable to exec `" INITSH "': %s", - applet, strerror (errno)); - } - - do - { - wpid = waitpid (pid, &status, 0); - if (wpid < 1) - eerror ("waitpid: %s", strerror (errno)); - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - - if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0) - exit (EXIT_FAILURE); - - /* If we requested a softlevel, save it now */ + uname (&uts); + + printf ("\n"); + PEINFO_GOOD; + printf (" Gentoo/%s; ", uts.sysname); + PEINFO_BRACKET; + printf ("http://www.gentoo.org/"); + PEINFO_NORMAL; + printf ("\n Copyright 1999-2007 Gentoo Foundation; " + "Distributed under the GPLv2\n\n"); + + printf ("Press "); + PEINFO_GOOD; + printf ("I"); + PEINFO_NORMAL; + printf (" to enter interactive boot mode\n\n"); + + setenv ("RC_SOFTLEVEL", newlevel, 1); + rc_plugin_run (rc_hook_runlevel_start_in, newlevel); + + if ((pid = fork ()) == -1) + eerrorx ("%s: fork: %s", applet, strerror (errno)); + + if (pid == 0) { + mycmd = rc_xstrdup (INITSH); + execl (mycmd, mycmd, (char *) NULL); + eerrorx ("%s: unable to exec `" INITSH "': %s", + applet, strerror (errno)); + } + + do { + wpid = waitpid (pid, &status, 0); + if (wpid < 1) + eerror ("waitpid: %s", strerror (errno)); + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + + if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0) + exit (EXIT_FAILURE); + + /* If we requested a softlevel, save it now */ #ifdef __linux__ - set_ksoftlevel (NULL); - - if ((fp = fopen ("/proc/cmdline", "r"))) - { - char buffer[RC_LINEBUFFER]; - char *soft; - - memset (buffer, 0, sizeof (buffer)); - if (fgets (buffer, RC_LINEBUFFER, fp) && - (soft = strstr (buffer, "softlevel="))) - { - i = soft - buffer; - if (i == 0 || buffer[i - 1] == ' ') - { - char *level; - - /* Trim the trailing carriage return if present */ - i = strlen (buffer) - 1; - if (buffer[i] == '\n') - buffer[i] = 0; - - soft += strlen ("softlevel="); - level = strsep (&soft, " "); - set_ksoftlevel (level); - } - } - fclose (fp); - } + set_ksoftlevel (NULL); + + if ((fp = fopen ("/proc/cmdline", "r"))) { + char buffer[RC_LINEBUFFER]; + char *soft; + + memset (buffer, 0, sizeof (buffer)); + if (fgets (buffer, RC_LINEBUFFER, fp) && + (soft = strstr (buffer, "softlevel="))) + { + i = soft - buffer; + if (i == 0 || buffer[i - 1] == ' ') { + char *level; + + /* Trim the trailing carriage return if present */ + i = strlen (buffer) - 1; + if (buffer[i] == '\n') + buffer[i] = 0; + + soft += strlen ("softlevel="); + level = strsep (&soft, " "); + set_ksoftlevel (level); + } + } + fclose (fp); + } #endif - rc_plugin_run (rc_hook_runlevel_start_out, newlevel); + rc_plugin_run (rc_hook_runlevel_start_out, newlevel); - if (want_interactive ()) - mark_interactive (); + if (want_interactive ()) + mark_interactive (); - exit (EXIT_SUCCESS); - } + exit (EXIT_SUCCESS); + } #ifdef __linux__ - /* Parse the inittab file so we can work out the level to telinit */ - if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 && - strcmp (newlevel, RC_LEVEL_SINGLE) != 0) - { - char **inittab = rc_get_list (NULL, "/etc/inittab"); - char *line; - char *p; - char *token; - char lvl[2] = {0, 0}; - - STRLIST_FOREACH (inittab, line, i) - { - p = line; - token = strsep (&p, ":"); - if (! token || token[0] != 'l') - continue; - - if ((token = strsep (&p, ":")) == NULL) - continue; - - /* Snag the level */ - lvl[0] = token[0]; - - /* The name is spaced after this */ - if ((token = strsep (&p, " ")) == NULL) - continue; - - if ((token = strsep (&p, " ")) == NULL) - continue; - - if (strcmp (token, newlevel) == 0) - break; - } - rc_strlist_free (inittab); - - /* We have a level, so telinit into it */ - if (lvl[0] == 0) - { - eerrorx ("%s: couldn't find a runlevel called `%s'", - applet, newlevel); - } - else - { - mycmd = rc_xstrdup ("/sbin/telinit"); - myarg = rc_xstrdup (lvl); - execl (mycmd, mycmd, myarg, (char *) NULL); - eerrorx ("%s: unable to exec `/sbin/telinit': %s", - applet, strerror (errno)); - } - } + /* Parse the inittab file so we can work out the level to telinit */ + if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 && + strcmp (newlevel, RC_LEVEL_SINGLE) != 0) + { + char **inittab = rc_get_list (NULL, "/etc/inittab"); + char *line; + char *p; + char *token; + char lvl[2] = {0, 0}; + + STRLIST_FOREACH (inittab, line, i) { + p = line; + token = strsep (&p, ":"); + if (! token || token[0] != 'l') + continue; + + if ((token = strsep (&p, ":")) == NULL) + continue; + + /* Snag the level */ + lvl[0] = token[0]; + + /* The name is spaced after this */ + if ((token = strsep (&p, " ")) == NULL) + continue; + + if ((token = strsep (&p, " ")) == NULL) + continue; + + if (strcmp (token, newlevel) == 0) + break; + } + rc_strlist_free (inittab); + + /* We have a level, so telinit into it */ + if (lvl[0] == 0) { + eerrorx ("%s: couldn't find a runlevel called `%s'", + applet, newlevel); + } else { + mycmd = rc_xstrdup ("/sbin/telinit"); + myarg = rc_xstrdup (lvl); + execl (mycmd, mycmd, myarg, (char *) NULL); + eerrorx ("%s: unable to exec `/sbin/telinit': %s", + applet, strerror (errno)); + } + } #endif - } - } - - /* Check we're in the runlevel requested, ie from - rc single - rc shutdown - rc reboot - */ - if (newlevel) - { - if (myarg) - { - free (myarg); - myarg = NULL; - } - - if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) - { - if (! RUNLEVEL || - (strcmp (RUNLEVEL, "S") != 0 && - strcmp (RUNLEVEL, "1") != 0)) - { - /* Remember the current runlevel for when we come back */ - set_ksoftlevel (runlevel); + } + } + + /* Check we're in the runlevel requested, ie from + rc single + rc shutdown + rc reboot + */ + if (newlevel) { + if (myarg) { + free (myarg); + myarg = NULL; + } + + if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) { + if (! RUNLEVEL || + (strcmp (RUNLEVEL, "S") != 0 && + strcmp (RUNLEVEL, "1") != 0)) + { + /* Remember the current runlevel for when we come back */ + set_ksoftlevel (runlevel); #ifdef __linux__ - 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)); + 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); + 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) - { - if (! RUNLEVEL || - strcmp (RUNLEVEL, "6") != 0) - { - mycmd = rc_xstrdup ("/sbin/shutdown"); - myarg = rc_xstrdup ("-r"); - tmp = rc_xstrdup ("now"); - 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) - { - if (! RUNLEVEL || - strcmp (RUNLEVEL, "0") != 0) - { - mycmd = rc_xstrdup ("/sbin/shutdown"); + } + } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) { + if (! RUNLEVEL || + strcmp (RUNLEVEL, "6") != 0) + { + mycmd = rc_xstrdup ("/sbin/shutdown"); + myarg = rc_xstrdup ("-r"); + tmp = rc_xstrdup ("now"); + 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) { + if (! RUNLEVEL || + strcmp (RUNLEVEL, "0") != 0) + { + mycmd = rc_xstrdup ("/sbin/shutdown"); #ifdef __linux__ - myarg = rc_xstrdup ("-h"); + myarg = rc_xstrdup ("-h"); #else - myarg = rc_xstrdup ("-p"); + myarg = rc_xstrdup ("-p"); #endif - tmp = rc_xstrdup ("now"); - execl (mycmd, mycmd, myarg, tmp, (char *) NULL); - eerrorx ("%s: unable to exec `%s': %s", - mycmd, applet, strerror (errno)); - } - } - } - - /* Export our current softlevel */ - runlevel = rc_get_runlevel (); - - /* If we're in the default runlevel and ksoftlevel exists, we should use - that instead */ - if (newlevel && - rc_exists (RC_SVCDIR "ksoftlevel") && - strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) - { - /* We should only use ksoftlevel if we were in single user mode - If not, we need to erase ksoftlevel now. */ - if (PREVLEVEL && - (strcmp (PREVLEVEL, "1") == 0 || - strcmp (PREVLEVEL, "S") == 0 || - strcmp (PREVLEVEL, "N") == 0)) - { - FILE *fp; - - if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) - eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", - strerror (errno)); - else - { - if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp)) - { - i = strlen (ksoftbuffer) - 1; - if (ksoftbuffer[i] == '\n') - ksoftbuffer[i] = 0; - newlevel = ksoftbuffer; - } - fclose (fp); - } - } - else - set_ksoftlevel (NULL); - } - - if (newlevel && - (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 || - strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 || - strcmp (newlevel, RC_LEVEL_SINGLE) == 0)) - { - going_down = true; - rc_set_runlevel (newlevel); - setenv ("RC_SOFTLEVEL", newlevel, 1); - rc_plugin_run (rc_hook_runlevel_stop_in, newlevel); - } - else - { - rc_plugin_run (rc_hook_runlevel_stop_in, runlevel); - } - - /* Check if runlevel is valid if we're changing */ - if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) - { - tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL); - if (! rc_is_dir (tmp)) - eerrorx ("%s: is not a valid runlevel", newlevel); - CHAR_FREE (tmp); - } - - /* Load our deptree now */ - if ((deptree = rc_load_deptree ()) == NULL) - eerrorx ("failed to load deptree"); - - /* Clean the failed services state dir now */ - if (rc_is_dir (RC_SVCDIR "failed")) - rc_rm_dir (RC_SVCDIR "failed", false); - - mkdir (RC_SVCDIR "/softscripts.new", 0755); + tmp = rc_xstrdup ("now"); + execl (mycmd, mycmd, myarg, tmp, (char *) NULL); + eerrorx ("%s: unable to exec `%s': %s", + mycmd, applet, strerror (errno)); + } + } + } + + /* Export our current softlevel */ + runlevel = rc_get_runlevel (); + + /* If we're in the default runlevel and ksoftlevel exists, we should use + that instead */ + if (newlevel && + rc_exists (RC_SVCDIR "ksoftlevel") && + strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) + { + /* We should only use ksoftlevel if we were in single user mode + If not, we need to erase ksoftlevel now. */ + if (PREVLEVEL && + (strcmp (PREVLEVEL, "1") == 0 || + strcmp (PREVLEVEL, "S") == 0 || + strcmp (PREVLEVEL, "N") == 0)) + { + FILE *fp; + + if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) + eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", + strerror (errno)); + else { + if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp)) { + i = strlen (ksoftbuffer) - 1; + if (ksoftbuffer[i] == '\n') + ksoftbuffer[i] = 0; + newlevel = ksoftbuffer; + } + fclose (fp); + } + } else + set_ksoftlevel (NULL); + } + + if (newlevel && + (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 || + strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp (newlevel, RC_LEVEL_SINGLE) == 0)) + { + going_down = true; + rc_set_runlevel (newlevel); + setenv ("RC_SOFTLEVEL", newlevel, 1); + rc_plugin_run (rc_hook_runlevel_stop_in, newlevel); + } else { + rc_plugin_run (rc_hook_runlevel_stop_in, runlevel); + } + + /* Check if runlevel is valid if we're changing */ + if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) { + tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL); + if (! rc_is_dir (tmp)) + eerrorx ("%s: is not a valid runlevel", newlevel); + CHAR_FREE (tmp); + } + + /* Load our deptree now */ + if ((deptree = rc_load_deptree ()) == NULL) + eerrorx ("failed to load deptree"); + + /* Clean the failed services state dir now */ + if (rc_is_dir (RC_SVCDIR "failed")) + rc_rm_dir (RC_SVCDIR "failed", false); + + mkdir (RC_SVCDIR "/softscripts.new", 0755); #ifdef __linux__ - /* udev likes to start services before we're ready when it does - its coldplugging thing. runscript knows when we're not ready so it - stores a list of coldplugged services in DEVBOOT for us to pick up - here when we are ready for them */ - if (rc_is_dir (DEVBOOT)) - { - start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD); - rc_rm_dir (DEVBOOT, true); - - STRLIST_FOREACH (start_services, service, i) - if (rc_allow_plug (service)) - rc_mark_service (service, rc_service_coldplugged); - /* We need to dump this list now. - This may seem redunant, but only Linux needs this and saves on - code bloat. */ - rc_strlist_free (start_services); - start_services = NULL; - } + /* udev likes to start services before we're ready when it does + its coldplugging thing. runscript knows when we're not ready so it + stores a list of coldplugged services in DEVBOOT for us to pick up + here when we are ready for them */ + if (rc_is_dir (DEVBOOT)) { + start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD); + rc_rm_dir (DEVBOOT, true); + + STRLIST_FOREACH (start_services, service, i) + if (rc_allow_plug (service)) + rc_mark_service (service, rc_service_coldplugged); + /* We need to dump this list now. + This may seem redunant, but only Linux needs this and saves on + code bloat. */ + rc_strlist_free (start_services); + start_services = NULL; + } #else - /* BSD's on the other hand populate /dev automagically and use devd. - The only downside of this approach and ours is that we have to hard code - the device node to the init script to simulate the coldplug into - runlevel for our dependency tree to work. */ - if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 && - (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || - strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) && - rc_is_env ("RC_COLDPLUG", "yes")) - { - /* The net interfaces are easy - they're all in net /dev/net :) */ - start_services = rc_ls_dir (NULL, "/dev/net", 0); - STRLIST_FOREACH (start_services, service, i) - { - j = (strlen ("net.") + strlen (service) + 1); - tmp = rc_xmalloc (sizeof (char *) * j); - snprintf (tmp, j, "net.%s", service); - if (rc_service_exists (tmp) && rc_allow_plug (tmp)) - rc_mark_service (tmp, rc_service_coldplugged); - CHAR_FREE (tmp); - } - rc_strlist_free (start_services); - - /* The mice are a little more tricky. - If we coldplug anything else, we'll probably do it here. */ - start_services = rc_ls_dir (NULL, "/dev", 0); - STRLIST_FOREACH (start_services, service, i) - { - if (strncmp (service, "psm", 3) == 0 || - strncmp (service, "ums", 3) == 0) - { - char *p = service + 3; - if (p && isdigit (*p)) - { - j = (strlen ("moused.") + strlen (service) + 1); - tmp = rc_xmalloc (sizeof (char *) * j); - snprintf (tmp, j, "moused.%s", service); - if (rc_service_exists (tmp) && rc_allow_plug (tmp)) - rc_mark_service (tmp, rc_service_coldplugged); - CHAR_FREE (tmp); - } - } - } - rc_strlist_free (start_services); - start_services = NULL; - } + /* BSD's on the other hand populate /dev automagically and use devd. + The only downside of this approach and ours is that we have to hard code + the device node to the init script to simulate the coldplug into + runlevel for our dependency tree to work. */ + if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 && + (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || + strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) && + rc_is_env ("RC_COLDPLUG", "yes")) + { + /* The net interfaces are easy - they're all in net /dev/net :) */ + start_services = rc_ls_dir (NULL, "/dev/net", 0); + STRLIST_FOREACH (start_services, service, i) { + j = (strlen ("net.") + strlen (service) + 1); + tmp = rc_xmalloc (sizeof (char *) * j); + snprintf (tmp, j, "net.%s", service); + if (rc_service_exists (tmp) && rc_allow_plug (tmp)) + rc_mark_service (tmp, rc_service_coldplugged); + CHAR_FREE (tmp); + } + rc_strlist_free (start_services); + + /* The mice are a little more tricky. + If we coldplug anything else, we'll probably do it here. */ + start_services = rc_ls_dir (NULL, "/dev", 0); + STRLIST_FOREACH (start_services, service, i) { + if (strncmp (service, "psm", 3) == 0 || + strncmp (service, "ums", 3) == 0) + { + char *p = service + 3; + if (p && isdigit (*p)) { + j = (strlen ("moused.") + strlen (service) + 1); + tmp = rc_xmalloc (sizeof (char *) * j); + snprintf (tmp, j, "moused.%s", service); + if (rc_service_exists (tmp) && rc_allow_plug (tmp)) + rc_mark_service (tmp, rc_service_coldplugged); + CHAR_FREE (tmp); + } + } + } + rc_strlist_free (start_services); + start_services = NULL; + } #endif - /* Build a list of all services to stop and then work out the - correct order for stopping them */ - stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD); - stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD); - stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD); - - types = rc_strlist_add (NULL, "ineed"); - types = rc_strlist_add (types, "iuse"); - types = rc_strlist_add (types, "iafter"); - deporder = rc_get_depends (deptree, types, stop_services, - runlevel, depoptions); - rc_strlist_free (stop_services); - rc_strlist_free (types); - stop_services = deporder; - deporder = NULL; - types = NULL; - rc_strlist_reverse (stop_services); - - /* Load our list of coldplugged services */ - coldplugged_services = rc_ls_dir (coldplugged_services, - RC_SVCDIR_COLDPLUGGED, RC_LS_INITD); - - /* Load our start services now. - We have different rules dependent on runlevel. */ - if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0) - { - if (coldplugged_services) - { - einfon ("Device initiated services:"); - STRLIST_FOREACH (coldplugged_services, service, i) - { - printf (" %s", service); - start_services = rc_strlist_add (start_services, service); - } - printf ("\n"); - } - tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel, - (char *) NULL); - start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); - CHAR_FREE (tmp); - } - else - { - /* Store our list of coldplugged services */ - coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED, - RC_LS_INITD); - if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 && - strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && - strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) - { - /* We need to include the boot runlevel services if we're not in it */ - start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT, - RC_LS_INITD); - STRLIST_FOREACH (coldplugged_services, service, i) - start_services = rc_strlist_add (start_services, service); - - tmp = rc_strcatpaths (RC_RUNLEVELDIR, - newlevel ? newlevel : runlevel, (char *) NULL); - start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); - CHAR_FREE (tmp); - } - } - - /* Save out softlevel now */ - if (going_down) - rc_set_runlevel (newlevel); - - types = rc_strlist_add (NULL, "needsme"); - types = rc_strlist_add (types, "usesme"); - /* Now stop the services that shouldn't be running */ - STRLIST_FOREACH (stop_services, service, i) - { - bool found = false; - char *conf = NULL; - char **stopdeps = NULL; - char *svc1 = NULL; - char *svc2 = NULL; - int k; - - if (rc_service_state (service, rc_service_stopped)) - continue; - - /* We always stop the service when in these runlevels */ - if (going_down) - { - rc_stop_service (service); - continue; - } - - /* If we're in the start list then don't bother stopping us */ - STRLIST_FOREACH (start_services, svc1, j) - if (strcmp (svc1, service) == 0) - { - found = true; - break; - } - - /* Unless we would use a different config file */ - if (found) - { - int len; - if (! newlevel) - continue; - - len = strlen (service) + strlen (runlevel) + 2; - tmp = rc_xmalloc (sizeof (char *) * len); - snprintf (tmp, len, "%s.%s", service, runlevel); - conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); - found = rc_exists (conf); - CHAR_FREE (conf); - CHAR_FREE (tmp); - if (! found) - { - len = strlen (service) + strlen (newlevel) + 2; - tmp = rc_xmalloc (sizeof (char *) * len); - snprintf (tmp, len, "%s.%s", service, newlevel); - conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); - found = rc_exists (conf); - CHAR_FREE (conf); - CHAR_FREE (tmp); - if (!found) - continue; - } - } - else - /* Allow coldplugged services not to be in the runlevels list */ - { - if (rc_service_state (service, rc_service_coldplugged)) - continue; - } - - /* We got this far! Or last check is to see if any any service that - going to be started depends on us */ - stopdeps = rc_strlist_add (stopdeps, service); - deporder = rc_get_depends (deptree, types, stopdeps, - runlevel, RC_DEP_STRICT); - rc_strlist_free (stopdeps); - stopdeps = NULL; - found = false; - STRLIST_FOREACH (deporder, svc1, j) - { - STRLIST_FOREACH (start_services, svc2, k) - if (strcmp (svc1, svc2) == 0) - { - found = true; - break; - } - if (found) - break; - } - rc_strlist_free (deporder); - deporder = NULL; - - /* After all that we can finally stop the blighter! */ - if (! found) - rc_stop_service (service); - } - rc_strlist_free (types); - types = NULL; - - /* Wait for our services to finish */ - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - wait_for_services (); - - /* Notify the plugins we have finished */ - rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); - - rmdir (RC_SVCDIR "/softscripts.new"); - - /* Store the new runlevel */ - if (newlevel) - { - rc_set_runlevel (newlevel); - runlevel = newlevel; - setenv ("RC_SOFTLEVEL", runlevel, 1); - } - - /* Run the halt script if needed */ - if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || - strcmp (runlevel, RC_LEVEL_REBOOT) == 0) - { - mycmd = rc_xstrdup (HALTSH); - myarg = rc_xstrdup (runlevel); - execl (mycmd, mycmd, myarg, (char *) NULL); - eerrorx ("%s: unable to exec `%s': %s", - applet, HALTSH, strerror (errno)); - } - - /* Single user is done now */ - if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) - { - if (rc_exists (INTERACTIVE)) - unlink (INTERACTIVE); - sulogin (false); - } - - mkdir (RC_SVCDIR "softscripts.old", 0755); - rc_plugin_run (rc_hook_runlevel_start_in, runlevel); - - /* Re-add our coldplugged services if they stopped */ - STRLIST_FOREACH (coldplugged_services, service, i) - rc_mark_service (service, rc_service_coldplugged); - - /* Order the services to start */ - types = rc_strlist_add (NULL, "ineed"); - types = rc_strlist_add (types, "iuse"); - types = rc_strlist_add (types, "iafter"); - deporder = rc_get_depends (deptree, types, start_services, - runlevel, depoptions); - rc_strlist_free (types); - types = NULL; - rc_strlist_free (start_services); - start_services = deporder; - deporder = NULL; - - STRLIST_FOREACH (start_services, service, i) - { - if (rc_service_state (service, rc_service_stopped)) - { - if (! interactive) - interactive = want_interactive (); - - if (interactive) - { + /* Build a list of all services to stop and then work out the + correct order for stopping them */ + stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD); + stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD); + stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD); + + types = rc_strlist_add (NULL, "ineed"); + types = rc_strlist_add (types, "iuse"); + types = rc_strlist_add (types, "iafter"); + deporder = rc_get_depends (deptree, types, stop_services, + runlevel, depoptions); + rc_strlist_free (stop_services); + rc_strlist_free (types); + stop_services = deporder; + deporder = NULL; + types = NULL; + rc_strlist_reverse (stop_services); + + /* Load our list of coldplugged services */ + coldplugged_services = rc_ls_dir (coldplugged_services, + RC_SVCDIR_COLDPLUGGED, RC_LS_INITD); + + /* Load our start services now. + We have different rules dependent on runlevel. */ + if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0) { + if (coldplugged_services) { + einfon ("Device initiated services:"); + STRLIST_FOREACH (coldplugged_services, service, i) { + printf (" %s", service); + start_services = rc_strlist_add (start_services, service); + } + printf ("\n"); + } + tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel, + (char *) NULL); + start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); + CHAR_FREE (tmp); + } else { + /* Store our list of coldplugged services */ + coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED, + RC_LS_INITD); + if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 && + strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && + strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) + { + /* We need to include the boot runlevel services if we're not in it */ + start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT, + RC_LS_INITD); + STRLIST_FOREACH (coldplugged_services, service, i) + start_services = rc_strlist_add (start_services, service); + + tmp = rc_strcatpaths (RC_RUNLEVELDIR, + newlevel ? newlevel : runlevel, (char *) NULL); + start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); + CHAR_FREE (tmp); + } + } + + /* Save out softlevel now */ + if (going_down) + rc_set_runlevel (newlevel); + + types = rc_strlist_add (NULL, "needsme"); + types = rc_strlist_add (types, "usesme"); + /* Now stop the services that shouldn't be running */ + STRLIST_FOREACH (stop_services, service, i) { + bool found = false; + char *conf = NULL; + char **stopdeps = NULL; + char *svc1 = NULL; + char *svc2 = NULL; + int k; + + if (rc_service_state (service, rc_service_stopped)) + continue; + + /* We always stop the service when in these runlevels */ + if (going_down) { + rc_stop_service (service); + continue; + } + + /* If we're in the start list then don't bother stopping us */ + STRLIST_FOREACH (start_services, svc1, j) + if (strcmp (svc1, service) == 0) { + found = true; + break; + } + + /* Unless we would use a different config file */ + if (found) { + int len; + if (! newlevel) + continue; + + len = strlen (service) + strlen (runlevel) + 2; + tmp = rc_xmalloc (sizeof (char *) * len); + snprintf (tmp, len, "%s.%s", service, runlevel); + conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); + found = rc_exists (conf); + CHAR_FREE (conf); + CHAR_FREE (tmp); + if (! found) { + len = strlen (service) + strlen (newlevel) + 2; + tmp = rc_xmalloc (sizeof (char *) * len); + snprintf (tmp, len, "%s.%s", service, newlevel); + conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); + found = rc_exists (conf); + CHAR_FREE (conf); + CHAR_FREE (tmp); + if (!found) + continue; + } + } else { + /* Allow coldplugged services not to be in the runlevels list */ + if (rc_service_state (service, rc_service_coldplugged)) + continue; + } + + /* We got this far! Or last check is to see if any any service that + going to be started depends on us */ + stopdeps = rc_strlist_add (stopdeps, service); + deporder = rc_get_depends (deptree, types, stopdeps, + runlevel, RC_DEP_STRICT); + rc_strlist_free (stopdeps); + stopdeps = NULL; + found = false; + STRLIST_FOREACH (deporder, svc1, j) { + STRLIST_FOREACH (start_services, svc2, k) + if (strcmp (svc1, svc2) == 0) { + found = true; + break; + } + if (found) + break; + } + rc_strlist_free (deporder); + deporder = NULL; + + /* After all that we can finally stop the blighter! */ + if (! found) + rc_stop_service (service); + } + rc_strlist_free (types); + types = NULL; + + /* Wait for our services to finish */ + if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) + wait_for_services (); + + /* Notify the plugins we have finished */ + rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); + + rmdir (RC_SVCDIR "/softscripts.new"); + + /* Store the new runlevel */ + if (newlevel) { + rc_set_runlevel (newlevel); + runlevel = newlevel; + setenv ("RC_SOFTLEVEL", runlevel, 1); + } + + /* Run the halt script if needed */ + if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp (runlevel, RC_LEVEL_REBOOT) == 0) + { + mycmd = rc_xstrdup (HALTSH); + myarg = rc_xstrdup (runlevel); + execl (mycmd, mycmd, myarg, (char *) NULL); + eerrorx ("%s: unable to exec `%s': %s", + applet, HALTSH, strerror (errno)); + } + + /* Single user is done now */ + if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) { + if (rc_exists (INTERACTIVE)) + unlink (INTERACTIVE); + sulogin (false); + } + + mkdir (RC_SVCDIR "softscripts.old", 0755); + rc_plugin_run (rc_hook_runlevel_start_in, runlevel); + + /* Re-add our coldplugged services if they stopped */ + STRLIST_FOREACH (coldplugged_services, service, i) + rc_mark_service (service, rc_service_coldplugged); + + /* Order the services to start */ + types = rc_strlist_add (NULL, "ineed"); + types = rc_strlist_add (types, "iuse"); + types = rc_strlist_add (types, "iafter"); + deporder = rc_get_depends (deptree, types, start_services, + runlevel, depoptions); + rc_strlist_free (types); + types = NULL; + rc_strlist_free (start_services); + start_services = deporder; + deporder = NULL; + + STRLIST_FOREACH (start_services, service, i) { + if (rc_service_state (service, rc_service_stopped)) { + if (! interactive) + interactive = want_interactive (); + + if (interactive) { interactive_retry: - printf ("\n"); - einfo ("About to start the service %s", service); - eindent (); - einfo ("1) Start the service\t\t2) Skip the service"); - einfo ("3) Continue boot process\t\t4) Exit to shell"); - eoutdent (); + printf ("\n"); + einfo ("About to start the service %s", service); + eindent (); + einfo ("1) Start the service\t\t2) Skip the service"); + einfo ("3) Continue boot process\t\t4) Exit to shell"); + eoutdent (); interactive_option: - switch (read_key (true)) - { - case '1': break; - case '2': continue; - case '3': interactive = false; break; - case '4': sulogin (true); goto interactive_retry; - default: goto interactive_option; - } - } - rc_start_service (service); - } - } - - /* Wait for our services to finish */ - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - wait_for_services (); - - rc_plugin_run (rc_hook_runlevel_start_out, runlevel); - - /* Store our interactive status for boot */ - if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0) - mark_interactive (); - else - { - if (rc_exists (INTERACTIVE)) - unlink (INTERACTIVE); - } - - return (EXIT_SUCCESS); + switch (read_key (true)) { + case '1': break; + case '2': continue; + case '3': interactive = false; break; + case '4': sulogin (true); goto interactive_retry; + default: goto interactive_option; + } + } + rc_start_service (service); + } + } + + /* Wait for our services to finish */ + if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) + wait_for_services (); + + rc_plugin_run (rc_hook_runlevel_start_out, runlevel); + + /* Store our interactive status for boot */ + if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0) + mark_interactive (); + else { + if (rc_exists (INTERACTIVE)) + unlink (INTERACTIVE); + } + + return (EXIT_SUCCESS); } |