aboutsummaryrefslogtreecommitdiff
path: root/src/rc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rc.c')
-rw-r--r--src/rc.c1574
1 files changed, 0 insertions, 1574 deletions
diff --git a/src/rc.c b/src/rc.c
deleted file mode 100644
index a33b6dcf..00000000
--- a/src/rc.c
+++ /dev/null
@@ -1,1574 +0,0 @@
-/*
- rc.c
- rc - manager for init scripts which control the startup, shutdown
- and the running of daemons.
-
- Also a multicall binary for various commands that can be used in shell
- scripts to query service state, mark service state and provide the
- einfo family of informational functions.
- */
-
-/*
- * Copyright 2007-2008 Roy Marples
- * All rights reserved
-
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
-
-#define SYSLOG_NAMES
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <strings.h>
-#include <syslog.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "builtins.h"
-#include "einfo.h"
-#include "rc.h"
-#include "rc-logger.h"
-#include "rc-misc.h"
-#include "rc-plugin.h"
-#include "strlist.h"
-
-#include "version.h"
-
-#define INITSH RC_LIBDIR "/sh/init.sh"
-#define INITEARLYSH RC_LIBDIR "/sh/init-early.sh"
-#define HALTSH RC_INITDIR "/halt.sh"
-
-#define SHUTDOWN "/sbin/shutdown"
-#define SULOGIN "/sbin/sulogin"
-
-#define INTERACTIVE RC_SVCDIR "/interactive"
-
-#define DEVBOOT "/dev/.rcboot"
-
-/* Cleanup anything in main */
-#define CHAR_FREE(_item) if (_item) { \
- free (_item); \
- _item = NULL; \
-}
-
-extern char **environ;
-
-static char *RUNLEVEL = NULL;
-static char *PREVLEVEL = NULL;
-
-static const char *applet = NULL;
-static char *runlevel = NULL;
-static char **env = NULL;
-static char **newenv = NULL;
-static char **coldplugged_services = NULL;
-static char **stop_services = NULL;
-static char **start_services = NULL;
-static rc_depinfo_t *deptree = NULL;
-static char *tmp = NULL;
-
-struct termios *termios_orig = NULL;
-
-typedef struct pidlist
-{
- pid_t pid;
- struct pidlist *next;
-} pidlist_t;
-static pidlist_t *service_pids = NULL;
-
-static const char *const types_n[] = { "needsme", NULL };
-static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
-
-static void clean_failed (void)
-{
- DIR *dp;
- struct dirent *d;
- int i;
- char *path;
-
- /* Clean the failed services state dir now */
- if ((dp = opendir (RC_SVCDIR "/failed"))) {
- while ((d = readdir (dp))) {
- if (d->d_name[0] == '.' &&
- (d->d_name[1] == '\0' ||
- (d->d_name[1] == '.' && d->d_name[2] == '\0')))
- continue;
-
- i = strlen (RC_SVCDIR "/failed/") + strlen (d->d_name) + 1;
- path = xmalloc (sizeof (char) * i);
- snprintf (path, i, RC_SVCDIR "/failed/%s", d->d_name);
- if (path) {
- if (unlink (path))
- eerror ("%s: unlink `%s': %s", applet, path,
- strerror (errno));
- free (path);
- }
- }
- closedir (dp);
- }
-}
-
-static void cleanup (void)
-{
- if (applet && strcmp (applet, "rc") == 0) {
- pidlist_t *pl = service_pids;
-
- rc_plugin_unload ();
-
- if (! rc_in_plugin && termios_orig) {
- tcsetattr (fileno (stdin), TCSANOW, termios_orig);
- free (termios_orig);
- }
-
- while (pl) {
- pidlist_t *p = pl->next;
- free (pl);
- pl = p;
- }
-
- rc_strlist_free (env);
- rc_strlist_free (newenv);
- rc_strlist_free (coldplugged_services);
- rc_strlist_free (stop_services);
- rc_strlist_free (start_services);
- rc_deptree_free (deptree);
-
- /* Clean runlevel start, stop markers */
- if (! rc_in_plugin && ! rc_in_logger) {
- rmdir (RC_STARTING);
- rmdir (RC_STOPPING);
- clean_failed ();
-
- rc_logger_close ();
- }
-
- free (runlevel);
- }
-}
-
-static int syslog_decode (char *name, CODE *codetab)
-{
- CODE *c;
-
- if (isdigit (*name))
- return (atoi (name));
-
- for (c = codetab; c->c_name; c++)
- if (! strcasecmp (name, c->c_name))
- return (c->c_val);
-
- return (-1);
-}
-
-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;
- int level = 0;
-
- if (strcmp (applet, "eval_ecolors") == 0) {
- printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
- ecolor (ECOLOR_GOOD),
- ecolor (ECOLOR_WARN),
- ecolor (ECOLOR_BAD),
- ecolor (ECOLOR_HILITE),
- ecolor (ECOLOR_BRACKET),
- ecolor (ECOLOR_NORMAL));
- exit (EXIT_SUCCESS);
- }
-
- if (argc > 0) {
-
- if (strcmp (applet, "eend") == 0 ||
- strcmp (applet, "ewend") == 0 ||
- strcmp (applet, "veend") == 0 ||
- strcmp (applet, "vweend") == 0)
- {
- errno = 0;
- retval = strtol (argv[0], NULL, 0);
- if (errno != 0)
- retval = EXIT_FAILURE;
- else {
- argc--;
- argv++;
- }
- } else if (strcmp (applet, "esyslog") == 0 ||
- strcmp (applet, "elog") == 0) {
- char *dot = strchr (argv[0], '.');
- if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
- eerrorx ("%s: invalid log level `%s'", applet, argv[0]);
-
- if (argc < 3)
- eerrorx ("%s: not enough arguments", applet);
-
- unsetenv ("EINFO_LOG");
- setenv ("EINFO_LOG", argv[1], 1);
-
- argc -= 2;
- argv += 2;
- }
- }
-
- if (argc > 0) {
- for (i = 0; i < argc; i++)
- l += strlen (argv[i]) + 1;
-
- message = 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 = xstrdup ("%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, "esyslog") == 0)
- elog (level, 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 {
- 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;
- char *service = NULL;
-
- if (argc > 0)
- service = argv[0];
- else
- service = getenv ("SVCNAME");
-
- if (! service || strlen (service) == 0)
- eerrorx ("%s: no service specified", applet);
-
- if (strcmp (applet, "service_started") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_STARTED);
- else if (strcmp (applet, "service_stopped") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_STOPPED);
- else if (strcmp (applet, "service_inactive") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_INACTIVE);
- else if (strcmp (applet, "service_starting") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_STARTING);
- else if (strcmp (applet, "service_stopping") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_STOPPING);
- else if (strcmp (applet, "service_coldplugged") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_COLDPLUGGED);
- else if (strcmp (applet, "service_wasinactive") == 0)
- ok = (rc_service_state (service) & RC_SERVICE_WASINACTIVE);
- else if (strcmp (applet, "service_started_daemon") == 0) {
- int idx = 0;
- char *d = argv[0];
-
- service = getenv ("SVCNAME");
- if (argc > 2) {
- service = argv[0];
- d = argv[1];
- sscanf (argv[2], "%d", &idx);
- } else if (argc == 2) {
- sscanf (argv[1], "%d", &idx);
- }
- exit (rc_service_started_daemon (service, d, 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");
- char *service = NULL;
-
- if (argc > 0)
- service = argv[0];
- else
- service = getenv ("SVCNAME");
-
- if (! service || strlen (service) == 0)
- eerrorx ("%s: no service specified", applet);
-
- if (strcmp (applet, "mark_service_started") == 0)
- ok = rc_service_mark (service, RC_SERVICE_STARTED);
- else if (strcmp (applet, "mark_service_stopped") == 0)
- ok = rc_service_mark (service, RC_SERVICE_STOPPED);
- else if (strcmp (applet, "mark_service_inactive") == 0)
- ok = rc_service_mark (service, RC_SERVICE_INACTIVE);
- else if (strcmp (applet, "mark_service_starting") == 0)
- ok = rc_service_mark (service, RC_SERVICE_STARTING);
- else if (strcmp (applet, "mark_service_stopping") == 0)
- ok = rc_service_mark (service, RC_SERVICE_STOPPING);
- else if (strcmp (applet, "mark_service_coldplugged") == 0)
- ok = rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
- else if (strcmp (applet, "mark_service_failed") == 0)
- ok = rc_service_mark (service, RC_SERVICE_FAILED);
- 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, service) == 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 exclusive time test. This ensures that it's not
- in control as well */
- l = strlen (RC_SVCDIR "exclusive") +
- strlen (svcname) +
- strlen (runscript_pid) +
- 4;
- mtime = xmalloc (l);
- snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
- svcname, runscript_pid);
- if (exists (mtime) && unlink (mtime) != 0)
- eerror ("%s: unlink: %s", applet, strerror (errno));
- free (mtime);
- }
-
- return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
-}
-
-static int do_value (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, "service_get_value") == 0 ||
- strcmp (applet, "get_options") == 0)
- {
- char *option = rc_service_value_get (service, argv[0]);
- if (option) {
- printf ("%s", option);
- free (option);
- ok = true;
- }
- } else if (strcmp (applet, "service_set_value") == 0 ||
- strcmp (applet, "save_options") == 0)
- ok = rc_service_value_set (service, argv[0], argv[1]);
- else
- eerrorx ("%s: unknown applet", applet);
-
- return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
-}
-
-static int do_shell_var (int argc, char **argv)
-{
- int i;
-
- for (i = 0; i < argc; i++) {
- char *p = argv[i];
-
- if (i != 0)
- putchar (' ');
-
- while (*p) {
- char c = *p++;
- if (! isalnum (c))
- c = '_';
- putchar (c);
- }
- }
- putchar ('\n');
-
- return (EXIT_SUCCESS);
-}
-
-#ifdef __linux__
-static char *proc_getent (const char *ent)
-{
- FILE *fp;
- char *buffer;
- char *p;
- char *value = NULL;
- int i;
-
- if (! exists ("/proc/cmdline"))
- return (NULL);
-
- if (! (fp = fopen ("/proc/cmdline", "r"))) {
- eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
- return (NULL);
- }
-
- buffer = xmalloc (sizeof (char) * RC_LINEBUFFER);
- memset (buffer, 0, RC_LINEBUFFER);
- if (fgets (buffer, RC_LINEBUFFER, fp) &&
- (p = strstr (buffer, ent)))
- {
- i = p - buffer;
- if (i == '\0' || buffer[i - 1] == ' ') {
- /* Trim the trailing carriage return if present */
- i = strlen (buffer) - 1;
- if (buffer[i] == '\n')
- buffer[i] = 0;
-
- p += strlen (ent);
- if (*p == '=')
- p++;
- value = xstrdup (strsep (&p, " "));
- }
- } else
- errno = ENOENT;
- free (buffer);
- fclose (fp);
-
- return (value);
-}
-#endif
-
-static char read_key (bool block)
-{
- struct termios termios;
- char c = 0;
- int fd = fileno (stdin);
-
- if (! isatty (fd))
- 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 = xmalloc (sizeof (struct termios));
- tcgetattr (fd, termios_orig);
- }
-
- tcgetattr (fd, &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 (fd, TCSANOW, &termios);
-
- read (fd, &c, 1);
-
- tcsetattr (fd, TCSANOW, termios_orig);
-
- return (c);
-}
-
-static bool want_interactive (void)
-{
- char c;
- static bool gotinteractive;
- static bool interactive;
-
- if (rc_yesno (getenv ("EINFO_QUIET")))
- return (false);
-
- if (PREVLEVEL &&
- strcmp (PREVLEVEL, "N") != 0 &&
- strcmp (PREVLEVEL, "S") != 0 &&
- strcmp (PREVLEVEL, "1") != 0)
- return (false);
-
- if (! gotinteractive) {
- gotinteractive = true;
- interactive = rc_conf_yesno ("rc_interactive");
- }
- if (! interactive)
- return (false);
-
- 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);
-}
-
-static void sulogin (bool cont)
-{
-#ifdef __linux__
- char *e = getenv ("RC_SYS");
-
- /* VPS systems cannot do a 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));
- }
-#endif
-
- newenv = env_filter ();
-
- if (cont) {
- int status = 0;
-#ifdef __linux__
- char *tty = ttyname (STDOUT_FILENO);
-#endif
-
- pid_t pid = vfork ();
-
- if (pid == -1)
- eerrorx ("%s: vfork: %s", applet, strerror (errno));
- if (pid == 0) {
-#ifdef __linux__
- if (tty)
- execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
- else
- execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
-
- eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
- strerror (errno));
-#else
- execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
- eerror ("%s: unable to exec `/bin/sh': %s", applet,
- strerror (errno));
-#endif
- _exit (EXIT_FAILURE);
- }
- waitpid (pid, &status, 0);
- } else {
- rc_logger_close ();
-
-#ifdef __linux__
- execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
- eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
-#else
- exit (EXIT_SUCCESS);
-#endif
- }
-}
-
-static void single_user (void)
-{
- rc_logger_close ();
-
-#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 bool set_ksoftlevel (const char *level)
-{
- FILE *fp;
-
- if (! level ||
- strcmp (level, getenv ("RC_BOOTLEVEL")) == 0 ||
- strcmp (level, RC_LEVEL_SINGLE) == 0 ||
- strcmp (level, RC_LEVEL_SYSINIT) == 0)
- {
- if (exists (RC_KSOFTLEVEL) &&
- unlink (RC_KSOFTLEVEL) != 0)
- eerror ("unlink `%s': %s", RC_KSOFTLEVEL, strerror (errno));
- return (false);
- }
-
- if (! (fp = fopen (RC_KSOFTLEVEL, "w"))) {
- eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
- return (false);
- }
-
- fprintf (fp, "%s", level);
- fclose (fp);
- return (true);
-}
-
-static int get_ksoftlevel (char *buffer, int buffer_len)
-{
- FILE *fp;
- int i = 0;
-
- if (! exists (RC_KSOFTLEVEL))
- return (0);
-
- if (! (fp = fopen (RC_KSOFTLEVEL, "r"))) {
- eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
- return (-1);
- }
-
- if (fgets (buffer, buffer_len, fp)) {
- i = strlen (buffer) - 1;
- if (buffer[i] == '\n')
- buffer[i] = 0;
- }
-
- fclose (fp);
- return (i);
-}
-
-static void add_pid (pid_t pid)
-{
- pidlist_t *sp = service_pids;
- if (sp) {
- while (sp->next)
- sp = sp->next;
- sp->next = xmalloc (sizeof (pidlist_t));
- sp = sp->next;
- } else
- sp = service_pids = xmalloc (sizeof (pidlist_t));
- memset (sp, 0, sizeof (pidlist_t));
- sp->pid = pid;
-}
-
-static void remove_pid (pid_t pid)
-{
- pidlist_t *last = NULL;
- pidlist_t *pl;
-
- for (pl = service_pids; pl; pl = pl->next) {
- if (pl->pid == pid) {
- if (last)
- last->next = pl->next;
- else
- service_pids = pl->next;
- free (pl);
- break;
- }
- last = pl;
- }
-}
-
-static void wait_for_services ()
-{
- while (waitpid (0, 0, 0) != -1);
-}
-
-static void handle_signal (int sig)
-{
- int serrno = errno;
- char signame[10] = { '\0' };
- pidlist_t *pl;
- pid_t pid;
- int status = 0;
- struct winsize ws;
-
- switch (sig) {
- case SIGCHLD:
- do {
- pid = waitpid (-1, &status, WNOHANG);
- if (pid < 0) {
- if (errno != ECHILD)
- eerror ("waitpid: %s", strerror (errno));
- return;
- }
- } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
-
- /* Remove that pid from our list */
- if (pid > 0)
- remove_pid (pid);
- break;
-
- case SIGWINCH:
- if (rc_logger_tty >= 0) {
- ioctl (STDIN_FILENO, TIOCGWINSZ, &ws);
- ioctl (rc_logger_tty, TIOCSWINSZ, &ws);
- }
- break;
-
- 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);
- case SIGUSR1:
- eerror ("rc: Aborting!");
- /* Kill any running services we have started */
-
- signal (SIGCHLD, SIG_IGN);
- for (pl = service_pids; pl; pl = pl->next)
- kill (pl->pid, SIGTERM);
-
- /* Notify plugins we are aborting */
- rc_plugin_run (RC_HOOK_ABORT, NULL);
-
- /* Only drop into single user mode if we're booting */
- if ((PREVLEVEL &&
- (strcmp (PREVLEVEL, "S") == 0 ||
- strcmp (PREVLEVEL, "1") == 0)) ||
- (RUNLEVEL &&
- (strcmp (RUNLEVEL, "S") == 0 ||
- strcmp (RUNLEVEL, "1") == 0)))
- single_user ();
-
- exit (EXIT_FAILURE);
- break;
-
- default:
- eerror ("%s: caught unknown signal %d", applet, sig);
- }
-
- /* Restore errno */
- errno = serrno;
-}
-
-static void run_script (const char *script)
-{
- int status = 0;
- pid_t pid = vfork ();
-
- if (pid < 0)
- eerrorx ("%s: vfork: %s", applet, strerror (errno));
- else if (pid == 0) {
- execl (script, script, (char *) NULL);
- eerror ("%s: unable to exec `%s': %s",
- script, applet, strerror (errno));
- _exit (EXIT_FAILURE);
- }
-
- do {
- pid_t wpid = waitpid (pid, &status, 0);
- if (wpid < 1)
- eerror ("waitpid: %s", strerror (errno));
- } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
-
- if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
- eerrorx ("%s: failed to exec `%s'", applet, script);
-}
-
-#include "_usage.h"
-#define getoptstring "o:" getoptstring_COMMON
-static struct option longopts[] = {
- { "override", 1, NULL, 'o' },
- longopts_COMMON
-};
-static const char * const longopts_help[] = {
- "override the next runlevel to change into\nwhen leaving single user or boot runlevels",
- longopts_help_COMMON
-};
-#include "_usage.c"
-
-int main (int argc, char **argv)
-{
- const char *bootlevel = NULL;
- char *newlevel = NULL;
- char *service = NULL;
- char **deporder = NULL;
- char **tmplist;
- 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];
- char pidstr[6];
- int opt;
- DIR *dp;
- struct dirent *d;
- bool parallel;
- int regen = 0;
-
- applet = basename_c (argv[0]);
- atexit (cleanup);
- if (! applet)
- eerrorx ("arguments required");
-
- if (argc > 1 && (strcmp (argv[1], "--version") == 0)) {
- printf ("%s (OpenRC"
-#ifdef BRANDING
- " " BRANDING
-#endif
- ") version " VERSION "\n", applet);
- exit (EXIT_SUCCESS);
- }
-
- /* These used to be programs in their own right, so we shouldn't
- * touch argc or argv for them */
- if (strcmp (applet, "fstabinfo") == 0)
- exit (fstabinfo (argc, argv));
- else if (strcmp (applet, "mountinfo") == 0)
- exit (mountinfo (argc, argv));
- else if (strcmp (applet, "rc-depend") == 0)
- exit (rc_depend (argc, argv));
- else if (strcmp (applet, "rc-status") == 0)
- exit (rc_status (argc, argv));
- else if (strcmp (applet, "rc-update") == 0 ||
- strcmp (applet, "update-rc") == 0)
- exit (rc_update (argc, argv));
- else if (strcmp (applet, "runscript") == 0)
- exit (runscript (argc, argv));
- else if (strcmp (applet, "start-stop-daemon") == 0)
- exit (start_stop_daemon (argc, argv));
- else if (strcmp (applet, "checkpath") == 0)
- exit (checkpath (argc, argv));
-
- argc--;
- argv++;
-
- /* Handle multicall stuff */
- if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
- exit (do_e (argc, argv));
-
- if (strcmp (applet, "service_get_value") == 0 ||
- strcmp (applet, "service_set_value") == 0 ||
- strcmp (applet, "get_options") == 0 ||
- strcmp (applet, "save_options") == 0)
- exit (do_value (argc, argv));
-
- if (strncmp (applet, "service_", strlen ("service_")) == 0)
- exit (do_service (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);
-
- if (strcmp (applet, "shell_var") == 0)
- exit (do_shell_var (argc, argv));
-
- 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)
- eerrorx ("%s: unknown applet", applet);
-
- /* Change dir to / to ensure all scripts don't use stuff in pwd */
- chdir ("/");
-
- /* 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");
-
- /* Ensure our environment is pure
- Also, add our configuration to it */
- env = env_filter ();
- tmplist = env_config ();
- rc_strlist_join (&env, tmplist);
- rc_strlist_free (tmplist);
-
- if (env) {
- char *p;
-
-#ifdef __linux__
- /* 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 = 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 */
- }
-
- argc++;
- argv--;
- while ((opt = getopt_long (argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'o':
- if (strlen (optarg) == 0)
- optarg = NULL;
- exit (set_ksoftlevel (optarg) ? EXIT_SUCCESS : EXIT_FAILURE);
- case_RC_COMMON_GETOPT
- }
- }
-
- newlevel = argv[optind++];
-
- /* 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);
-
- /* Enable logging */
- setenv ("EINFO_LOG", "rc", 1);
-
- /* Export our PID */
- snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
- setenv ("RC_PID", pidstr, 1);
-
- /* Load current softlevel */
- bootlevel = getenv ("RC_BOOTLEVEL");
- runlevel = rc_runlevel_get ();
-
- rc_logger_open (newlevel ? newlevel : runlevel);
-
- /* Setup a signal handler */
- signal (SIGINT, handle_signal);
- signal (SIGQUIT, handle_signal);
- signal (SIGTERM, handle_signal);
- signal (SIGUSR1, handle_signal);
- signal (SIGWINCH, handle_signal);
-
- if (! rc_yesno (getenv ("EINFO_QUIET")))
- interactive = exists (INTERACTIVE);
- rc_plugin_load ();
-
- /* Check we're in the runlevel requested, ie from
- rc single
- rc shutdown
- rc reboot
- */
- if (newlevel) {
- if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
- RUNLEVEL &&
- (strcmp (RUNLEVEL, "S") == 0 ||
- strcmp (RUNLEVEL, "1") == 0))
- {
- /* OK, we're either in runlevel 1 or single user mode */
- struct utsname uts;
-#ifdef __linux__
- char *cmd;
-#endif
-
- /* exec init-early.sh if it exists
- * This should just setup the console to use the correct
- * font. Maybe it should setup the keyboard too? */
- if (exists (INITEARLYSH))
- run_script (INITEARLYSH);
-
- uname (&uts);
- printf ("\n %sOpenRC %s" VERSION "%s is starting up %s",
-#ifdef BRANDING
- BRANDING
-#else
- ""
-#endif
- "\n\n",
- ecolor (ECOLOR_GOOD), ecolor (ECOLOR_HILITE),
- ecolor (ECOLOR_NORMAL));
-
- if (! rc_yesno (getenv ("EINFO_QUIET")) &&
- rc_conf_yesno ("rc_interactive"))
- printf ("Press %sI%s to enter interactive boot mode\n\n",
- ecolor (ECOLOR_GOOD), ecolor (ECOLOR_NORMAL));
-
- setenv ("RC_SOFTLEVEL", newlevel, 1);
- rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, newlevel);
- run_script (INITSH);
-
-#ifdef __linux__
- /* If we requested a softlevel, save it now */
- set_ksoftlevel (NULL);
- if ((cmd = proc_getent ("softlevel"))) {
- set_ksoftlevel (cmd);
- free (cmd);
- }
-#endif
-
- rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, newlevel);
-
- if (want_interactive ())
- mark_interactive ();
-
- exit (EXIT_SUCCESS);
- } else 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);
- single_user ();
- }
- } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
- if (! RUNLEVEL ||
- strcmp (RUNLEVEL, "6") != 0)
- {
- rc_logger_close ();
- execl (SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
- eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
- applet, strerror (errno));
- }
- } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
- if (! RUNLEVEL ||
- strcmp (RUNLEVEL, "0") != 0)
- {
- rc_logger_close ();
- execl (SHUTDOWN, SHUTDOWN,
-#ifdef __linux__
- "-h",
-#else
- "-p",
-#endif
- "now", (char *) NULL);
- eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
- applet, strerror (errno));
- }
- }
- }
-
- /* Now we start handling our children */
- signal (SIGCHLD, handle_signal);
-
- /* 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))
- {
- /* Try not to join boot and ksoftlevels together */
- if (! newlevel ||
- strcmp (newlevel, getenv ("RC_BOOTLEVEL")) != 0)
- if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
- newlevel = ksoftbuffer;
- } else if (! RUNLEVEL ||
- (strcmp (RUNLEVEL, "1") != 0 &&
- strcmp (RUNLEVEL, "S") != 0 &&
- strcmp (RUNLEVEL, "N") != 0))
- {
- 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_runlevel_set (newlevel);
- setenv ("RC_SOFTLEVEL", newlevel, 1);
-
-#ifdef __FreeBSD__
- /* FIXME: we shouldn't have todo this */
- /* For some reason, wait_for_services waits for the logger proccess
- * to finish as well, but only on FreeBSD. We cannot allow this so
- * we stop logging now. */
- rc_logger_close ();
-#endif
-
- 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) {
- if (! rc_runlevel_exists (newlevel))
- eerrorx ("%s: is not a valid runlevel", newlevel);
- }
-
- /* Load our deptree now */
- if ((deptree = _rc_deptree_load (&regen)) == NULL)
- eerrorx ("failed to load deptree");
-
- /* Clean the failed services state dir now */
- clean_failed ();
-
- mkdir (RC_STOPPING, 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 ((dp = opendir (DEVBOOT))) {
- while ((d = readdir (dp))) {
- if (d->d_name[0] == '.' &&
- (d->d_name[1] == '\0' ||
- (d->d_name[1] == '.' && d->d_name[2] == '\0')))
- continue;
-
- if (rc_service_exists (d->d_name) &&
- rc_service_plugable (d->d_name))
- rc_service_mark (d->d_name, RC_SERVICE_COLDPLUGGED);
-
- i = strlen (DEVBOOT "/") + strlen (d->d_name) + 1;
- tmp = xmalloc (sizeof (char) * i);
- snprintf (tmp, i, DEVBOOT "/%s", d->d_name);
- if (tmp) {
- if (unlink (tmp))
- eerror ("%s: unlink `%s': %s", applet, tmp,
- strerror (errno));
- free (tmp);
- }
- }
- closedir (dp);
- rmdir (DEVBOOT);
- }
-#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, bootlevel) == 0 &&
- (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
- strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
- rc_conf_yesno ("rc_coldplug"))
- {
-#if defined(__DragonFly__) || defined(__FreeBSD__)
- /* The net interfaces are easy - they're all in net /dev/net :) */
- if ((dp = opendir ("/dev/net"))) {
- while ((d = readdir (dp))) {
- i = (strlen ("net.") + strlen (d->d_name) + 1);
- tmp = xmalloc (sizeof (char) * i);
- snprintf (tmp, i, "net.%s", d->d_name);
- if (rc_service_exists (tmp) &&
- rc_service_plugable (tmp))
- rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
- CHAR_FREE (tmp);
- }
- closedir (dp);
- }
-#endif
-
- /* The mice are a little more tricky.
- If we coldplug anything else, we'll probably do it here. */
- if ((dp == opendir ("/dev"))) {
- while ((d = readdir (dp))) {
- if (strncmp (d->d_name, "psm", 3) == 0 ||
- strncmp (d->d_name, "ums", 3) == 0)
- {
- char *p = d->d_name + 3;
- if (p && isdigit (*p)) {
- i = (strlen ("moused.") + strlen (d->d_name) + 1);
- tmp = xmalloc (sizeof (char) * i);
- snprintf (tmp, i, "moused.%s", d->d_name);
- if (rc_service_exists (tmp) &&
- rc_service_plugable (tmp))
- rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
- CHAR_FREE (tmp);
- }
- }
- }
- closedir (dp);
- }
- }
-#endif
-
- /* Build a list of all services to stop and then work out the
- correct order for stopping them */
- stop_services = rc_services_in_state (RC_SERVICE_STARTING);
-
- tmplist = rc_services_in_state (RC_SERVICE_INACTIVE);
- rc_strlist_join (&stop_services, tmplist);
- rc_strlist_free (tmplist);
-
- tmplist = rc_services_in_state (RC_SERVICE_STARTED);
- rc_strlist_join (&stop_services, tmplist);
- rc_strlist_free (tmplist);
-
- deporder = rc_deptree_depends (deptree, types_nua,
- (const char **) stop_services,
- runlevel, depoptions | RC_DEP_STOP);
-
- rc_strlist_free (stop_services);
- stop_services = deporder;
- deporder = NULL;
- rc_strlist_reverse (stop_services);
-
- /* Load our list of coldplugged services */
- coldplugged_services = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
-
- /* Load our start services now.
- We have different rules dependent on runlevel. */
- if (newlevel && strcmp (newlevel, bootlevel) == 0) {
- if (coldplugged_services) {
- bool quiet = rc_yesno (getenv ("EINFO_QUIET"));
-
- if (! quiet)
- einfon ("Device initiated services:");
- STRLIST_FOREACH (coldplugged_services, service, i) {
- if (! quiet)
- printf (" %s", service);
- rc_strlist_add (&start_services, service);
- }
- if (! quiet)
- printf ("\n");
- }
- tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
- rc_strlist_join (&start_services, tmplist);
- rc_strlist_free (tmplist);
- } else {
- /* Store our list of coldplugged services */
- tmplist = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
- rc_strlist_join (&coldplugged_services, tmplist);
- rc_strlist_free (tmplist);
- 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 */
- tmplist = rc_services_in_runlevel (bootlevel);
- rc_strlist_join (&start_services, tmplist);
- rc_strlist_free (tmplist);
- tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
- rc_strlist_join (&start_services, tmplist);
- rc_strlist_free (tmplist);
-
- STRLIST_FOREACH (coldplugged_services, service, i)
- rc_strlist_add (&start_services, service);
-
- }
- }
-
- /* Save out softlevel now */
- if (going_down)
- rc_runlevel_set (newlevel);
-
- parallel = rc_conf_yesno ("rc_parallel");
-
- /* 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) {
- pid_t pid = rc_service_stop (service);
- if (pid > 0 && ! parallel)
- rc_waitpid (pid);
- 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 = xmalloc (sizeof (char) * len);
- snprintf (tmp, len, "%s.%s", service, runlevel);
- conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
- found = exists (conf);
- CHAR_FREE (conf);
- CHAR_FREE (tmp);
- if (! found) {
- len = strlen (service) + strlen (newlevel) + 2;
- tmp = xmalloc (sizeof (char) * len);
- snprintf (tmp, len, "%s.%s", service, newlevel);
- conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
- found = 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 */
- rc_strlist_add (&stopdeps, service);
- deporder = rc_deptree_depends (deptree, types_n,
- (const char **) 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) {
- pid_t pid;
-
- if ((pid = rc_service_stop (service)) > 0) {
- add_pid (pid);
-
- if (! parallel) {
- rc_waitpid (pid);
- remove_pid (pid);
- }
- }
- }
- }
-
- /* Wait for our services to finish */
- wait_for_services ();
-
- /* Notify the plugins we have finished */
- rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_OUT, runlevel);
-
- rmdir (RC_STOPPING);
-
- /* Store the new runlevel */
- if (newlevel) {
- rc_runlevel_set (newlevel);
- free (runlevel);
- runlevel = xstrdup (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)
- {
- rc_logger_close ();
- execl (HALTSH, HALTSH, runlevel, (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 (exists (INTERACTIVE))
- unlink (INTERACTIVE);
- sulogin (false);
- }
-
- mkdir (RC_STARTING, 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_service_mark (service, RC_SERVICE_COLDPLUGGED);
-
- /* Order the services to start */
- deporder = rc_deptree_depends (deptree, types_nua,
- (const char **) start_services,
- runlevel, depoptions | RC_DEP_START);
- rc_strlist_free (start_services);
- start_services = deporder;
- deporder = NULL;
-
-#ifdef __linux__
- /* mark any services skipped as started */
- if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
- if ((service = proc_getent ("noinitd"))) {
- char *p = service;
- char *token;
-
- while ((token = strsep (&p, ",")))
- rc_service_mark (token, RC_SERVICE_STARTED);
- free (service);
- }
- }
-#endif
-
- STRLIST_FOREACH (start_services, service, i) {
- if (rc_service_state (service) & RC_SERVICE_STOPPED) {
- pid_t pid;
-
- 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 ();
-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;
- }
- }
-
- /* Remember the pid if we're running in parallel */
- if ((pid = rc_service_start (service)) > 0) {
- add_pid (pid);
-
- if (! parallel) {
- rc_waitpid (pid);
- remove_pid (pid);
- }
- }
- }
- }
-
- /* Wait for our services to finish */
- wait_for_services ();
-
- rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, runlevel);
-
-#ifdef __linux__
- /* mark any services skipped as stopped */
- if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
- if ((service = proc_getent ("noinitd"))) {
- char *p = service;
- char *token;
-
- while ((token = strsep (&p, ",")))
- rc_service_mark (token, RC_SERVICE_STOPPED);
- free (service);
- }
- }
-#endif
-
- /* Store our interactive status for boot */
- if (interactive && strcmp (runlevel, bootlevel) == 0)
- mark_interactive ();
- else {
- if (exists (INTERACTIVE))
- unlink (INTERACTIVE);
- }
-
- /* If we're in the boot runlevel and we regenerated our dependencies
- * we need to delete them so that they are regenerated again in the
- * default runlevel as they may depend on things that are now available */
- if (regen && strcmp (runlevel, bootlevel) == 0)
- unlink (RC_DEPTREE);
-
- return (EXIT_SUCCESS);
-}
-