2007-04-05 16:48:42 +05:30
|
|
|
/*
|
2008-01-29 19:22:54 +05:30
|
|
|
* 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.
|
|
|
|
*/
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-01-14 10:35:22 +05:30
|
|
|
/*
|
2008-01-04 16:36:58 +05:30
|
|
|
* Copyright 2007-2008 Roy Marples
|
2007-11-14 20:52:04 +05:30
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2008-01-04 16:36:58 +05:30
|
|
|
const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
2007-11-19 22:11:36 +05:30
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <sys/types.h>
|
2007-10-31 21:16:56 +05:30
|
|
|
#include <sys/ioctl.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <errno.h>
|
2007-10-05 15:46:14 +05:30
|
|
|
#include <dirent.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <ctype.h>
|
2007-06-28 21:14:14 +05:30
|
|
|
#include <getopt.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <limits.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
2007-10-09 18:22:09 +05:30
|
|
|
#include <strings.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <termios.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2007-07-31 21:35:56 +05:30
|
|
|
#include "builtins.h"
|
2008-01-06 19:17:39 +05:30
|
|
|
#include "einfo.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
#include "rc.h"
|
2007-10-31 21:16:56 +05:30
|
|
|
#include "rc-logger.h"
|
2008-01-06 19:17:39 +05:30
|
|
|
#include "rc-misc.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
#include "rc-plugin.h"
|
2008-01-06 19:17:39 +05:30
|
|
|
#include "strlist.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-11-19 22:11:36 +05:30
|
|
|
#include "version.h"
|
|
|
|
|
2007-08-09 20:03:20 +05:30
|
|
|
#define INITSH RC_LIBDIR "/sh/init.sh"
|
|
|
|
#define INITEARLYSH RC_LIBDIR "/sh/init-early.sh"
|
|
|
|
#define HALTSH RC_INITDIR "/halt.sh"
|
2007-08-28 14:47:04 +05:30
|
|
|
|
|
|
|
#define SHUTDOWN "/sbin/shutdown"
|
2007-05-03 19:16:38 +05:30
|
|
|
#define SULOGIN "/sbin/sulogin"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-08-09 20:03:20 +05:30
|
|
|
#define INTERACTIVE RC_SVCDIR "/interactive"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-17 15:02:18 +05:30
|
|
|
#define DEVBOOT "/dev/.rcboot"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
|
|
|
/* Cleanup anything in main */
|
2007-04-11 18:14:47 +05:30
|
|
|
#define CHAR_FREE(_item) if (_item) { \
|
|
|
|
free (_item); \
|
|
|
|
_item = NULL; \
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
extern char **environ;
|
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
static char *RUNLEVEL = NULL;
|
|
|
|
static char *PREVLEVEL = NULL;
|
|
|
|
|
2008-01-14 19:54:20 +05:30
|
|
|
const char *applet = NULL;
|
2007-09-29 22:50:52 +05:30
|
|
|
static char *runlevel = NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
static char **env = NULL;
|
|
|
|
static char **newenv = NULL;
|
2007-04-20 18:42:21 +05:30
|
|
|
static char **coldplugged_services = NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
static char **stop_services = NULL;
|
|
|
|
static char **start_services = NULL;
|
|
|
|
static rc_depinfo_t *deptree = NULL;
|
|
|
|
static char *tmp = NULL;
|
|
|
|
|
2007-04-20 18:42:21 +05:30
|
|
|
struct termios *termios_orig = NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-21 00:28:42 +05:30
|
|
|
typedef struct pidlist
|
|
|
|
{
|
|
|
|
pid_t pid;
|
|
|
|
struct pidlist *next;
|
|
|
|
} pidlist_t;
|
|
|
|
static pidlist_t *service_pids = NULL;
|
|
|
|
|
2007-12-20 20:32:04 +05:30
|
|
|
static const char *const types_n[] = { "needsme", NULL };
|
|
|
|
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
|
2007-10-15 20:10:53 +05:30
|
|
|
|
2007-12-30 00:29:24 +05:30
|
|
|
static void clean_failed (void)
|
|
|
|
{
|
|
|
|
DIR *dp;
|
|
|
|
struct dirent *d;
|
2008-01-22 16:37:39 +05:30
|
|
|
size_t l;
|
2007-12-30 00:29:24 +05:30
|
|
|
char *path;
|
|
|
|
|
|
|
|
/* Clean the failed services state dir now */
|
|
|
|
if ((dp = opendir (RC_SVCDIR "/failed"))) {
|
|
|
|
while ((d = readdir (dp))) {
|
|
|
|
if (d->d_name[0] == '.' &&
|
2008-01-11 21:21:40 +05:30
|
|
|
(d->d_name[1] == '\0' ||
|
|
|
|
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
|
2007-12-30 00:29:24 +05:30
|
|
|
continue;
|
|
|
|
|
2008-01-22 16:37:39 +05:30
|
|
|
l = strlen (RC_SVCDIR "/failed/") + strlen (d->d_name) + 1;
|
|
|
|
path = xmalloc (sizeof (char) * l);
|
|
|
|
snprintf (path, l, RC_SVCDIR "/failed/%s", d->d_name);
|
2007-12-30 00:29:24 +05:30
|
|
|
if (path) {
|
|
|
|
if (unlink (path))
|
|
|
|
eerror ("%s: unlink `%s': %s", applet, path,
|
2008-01-11 21:21:40 +05:30
|
|
|
strerror (errno));
|
2007-12-30 00:29:24 +05:30
|
|
|
free (path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir (dp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
static void cleanup (void)
|
|
|
|
{
|
2007-07-31 21:35:56 +05:30
|
|
|
if (applet && strcmp (applet, "rc") == 0) {
|
|
|
|
pidlist_t *pl = service_pids;
|
2007-04-21 00:28:42 +05:30
|
|
|
|
2007-07-31 21:35:56 +05:30
|
|
|
rc_plugin_unload ();
|
2008-01-11 21:21:40 +05:30
|
|
|
|
2007-07-31 21:35:56 +05:30
|
|
|
if (! rc_in_plugin && termios_orig) {
|
|
|
|
tcsetattr (fileno (stdin), TCSANOW, termios_orig);
|
|
|
|
free (termios_orig);
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-07-31 21:35:56 +05:30
|
|
|
while (pl) {
|
|
|
|
pidlist_t *p = pl->next;
|
|
|
|
free (pl);
|
|
|
|
pl = p;
|
|
|
|
}
|
2007-04-21 00:28:42 +05:30
|
|
|
|
2007-07-31 21:35:56 +05:30
|
|
|
rc_strlist_free (env);
|
|
|
|
rc_strlist_free (newenv);
|
|
|
|
rc_strlist_free (coldplugged_services);
|
|
|
|
rc_strlist_free (stop_services);
|
|
|
|
rc_strlist_free (start_services);
|
2007-09-29 22:12:08 +05:30
|
|
|
rc_deptree_free (deptree);
|
2007-07-31 21:35:56 +05:30
|
|
|
|
|
|
|
/* Clean runlevel start, stop markers */
|
2007-10-31 21:16:56 +05:30
|
|
|
if (! rc_in_plugin && ! rc_in_logger) {
|
2007-10-04 22:24:29 +05:30
|
|
|
rmdir (RC_STARTING);
|
|
|
|
rmdir (RC_STOPPING);
|
2007-12-30 00:29:24 +05:30
|
|
|
clean_failed ();
|
2007-10-31 21:16:56 +05:30
|
|
|
|
|
|
|
rc_logger_close ();
|
2007-07-31 21:35:56 +05:30
|
|
|
}
|
2007-09-29 22:50:52 +05:30
|
|
|
|
|
|
|
free (runlevel);
|
2007-07-04 21:32:01 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2007-07-23 17:06:12 +05:30
|
|
|
#ifdef __linux__
|
|
|
|
static char *proc_getent (const char *ent)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
2008-01-07 17:59:30 +05:30
|
|
|
char *proc;
|
2007-07-23 17:06:12 +05:30
|
|
|
char *p;
|
|
|
|
char *value = NULL;
|
|
|
|
int i;
|
2007-08-22 19:40:46 +05:30
|
|
|
|
2007-10-08 16:41:21 +05:30
|
|
|
if (! exists ("/proc/cmdline"))
|
2007-08-22 19:40:46 +05:30
|
|
|
return (NULL);
|
|
|
|
|
2007-07-23 17:06:12 +05:30
|
|
|
if (! (fp = fopen ("/proc/cmdline", "r"))) {
|
|
|
|
eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2008-01-07 17:59:30 +05:30
|
|
|
if ((proc = rc_getline (fp)) &&
|
2008-01-11 21:21:40 +05:30
|
|
|
(p = strstr (proc, ent)))
|
2008-01-14 10:35:22 +05:30
|
|
|
{
|
2008-01-07 17:59:30 +05:30
|
|
|
i = p - proc;
|
|
|
|
if (i == '\0' || proc[i - 1] == ' ') {
|
2007-07-23 17:06:12 +05:30
|
|
|
p += strlen (ent);
|
|
|
|
if (*p == '=')
|
|
|
|
p++;
|
2007-10-08 16:46:22 +05:30
|
|
|
value = xstrdup (strsep (&p, " "));
|
2007-07-23 17:06:12 +05:30
|
|
|
}
|
|
|
|
} else
|
|
|
|
errno = ENOENT;
|
2008-01-07 17:59:30 +05:30
|
|
|
free (proc);
|
2007-07-23 17:06:12 +05:30
|
|
|
fclose (fp);
|
|
|
|
|
|
|
|
return (value);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
static char read_key (bool block)
|
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
struct termios termios;
|
|
|
|
char c = 0;
|
2007-07-11 18:32:05 +05:30
|
|
|
int fd = fileno (stdin);
|
2007-10-05 15:46:14 +05:30
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
if (! isatty (fd))
|
2007-04-11 18:14:47 +05:30
|
|
|
return (false);
|
|
|
|
|
|
|
|
/* Now save our terminal settings. We need to restore them at exit as we
|
2008-01-29 19:22:54 +05:30
|
|
|
* will be changing it for non-blocking reads for Interactive */
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! termios_orig) {
|
2007-10-08 16:41:21 +05:30
|
|
|
termios_orig = xmalloc (sizeof (struct termios));
|
2007-07-11 18:32:05 +05:30
|
|
|
tcgetattr (fd, termios_orig);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
tcgetattr (fd, &termios);
|
2007-04-11 18:14:47 +05:30
|
|
|
termios.c_lflag &= ~(ICANON | ECHO);
|
|
|
|
if (block)
|
|
|
|
termios.c_cc[VMIN] = 1;
|
|
|
|
else {
|
|
|
|
termios.c_cc[VMIN] = 0;
|
|
|
|
termios.c_cc[VTIME] = 0;
|
|
|
|
}
|
2007-07-11 18:32:05 +05:30
|
|
|
tcsetattr (fd, TCSANOW, &termios);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
read (fd, &c, 1);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
tcsetattr (fd, TCSANOW, termios_orig);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
return (c);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static bool want_interactive (void)
|
|
|
|
{
|
2007-05-14 18:18:37 +05:30
|
|
|
char c;
|
2007-11-23 17:34:11 +05:30
|
|
|
static bool gotinteractive;
|
|
|
|
static bool interactive;
|
2007-05-14 18:18:37 +05:30
|
|
|
|
2007-12-06 16:46:27 +05:30
|
|
|
if (rc_yesno (getenv ("EINFO_QUIET")))
|
|
|
|
return (false);
|
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
if (PREVLEVEL &&
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (PREVLEVEL, "N") != 0 &&
|
|
|
|
strcmp (PREVLEVEL, "S") != 0 &&
|
|
|
|
strcmp (PREVLEVEL, "1") != 0)
|
2007-07-11 18:32:05 +05:30
|
|
|
return (false);
|
|
|
|
|
2007-11-23 17:34:11 +05:30
|
|
|
if (! gotinteractive) {
|
|
|
|
gotinteractive = true;
|
|
|
|
interactive = rc_conf_yesno ("rc_interactive");
|
|
|
|
}
|
|
|
|
if (! interactive)
|
2007-05-14 18:18:37 +05:30
|
|
|
return (false);
|
|
|
|
|
|
|
|
c = read_key (false);
|
2007-04-11 18:14:47 +05:30
|
|
|
return ((c == 'I' || c == 'i') ? true : false);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void mark_interactive (void)
|
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
FILE *fp = fopen (INTERACTIVE, "w");
|
|
|
|
if (fp)
|
|
|
|
fclose (fp);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void sulogin (bool cont)
|
|
|
|
{
|
|
|
|
#ifdef __linux__
|
2007-04-20 18:42:21 +05:30
|
|
|
char *e = getenv ("RC_SYS");
|
|
|
|
|
2007-10-31 21:16:56 +05:30
|
|
|
/* VPS systems cannot do a sulogin */
|
2007-04-20 18:42:21 +05:30
|
|
|
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));
|
|
|
|
}
|
2007-04-21 00:28:42 +05:30
|
|
|
#endif
|
2007-04-20 18:42:21 +05:30
|
|
|
|
2007-10-08 16:37:39 +05:30
|
|
|
newenv = env_filter ();
|
2007-04-25 18:00:24 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
if (cont) {
|
|
|
|
int status = 0;
|
2007-05-03 19:16:38 +05:30
|
|
|
#ifdef __linux__
|
2007-10-31 21:16:56 +05:30
|
|
|
char *tty = ttyname (STDOUT_FILENO);
|
2007-05-03 19:16:38 +05:30
|
|
|
#endif
|
|
|
|
|
2007-04-25 18:00:24 +05:30
|
|
|
pid_t pid = vfork ();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
if (pid == -1)
|
2007-04-20 18:42:21 +05:30
|
|
|
eerrorx ("%s: vfork: %s", applet, strerror (errno));
|
2007-04-11 18:14:47 +05:30
|
|
|
if (pid == 0) {
|
2007-04-21 00:28:42 +05:30
|
|
|
#ifdef __linux__
|
2007-05-03 19:16:38 +05:30
|
|
|
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,
|
2008-01-11 21:21:40 +05:30
|
|
|
strerror (errno));
|
2007-04-21 00:28:42 +05:30
|
|
|
#else
|
|
|
|
execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
|
|
|
|
eerror ("%s: unable to exec `/bin/sh': %s", applet,
|
2008-01-11 21:21:40 +05:30
|
|
|
strerror (errno));
|
2007-04-21 00:28:42 +05:30
|
|
|
#endif
|
2007-04-20 18:42:21 +05:30
|
|
|
_exit (EXIT_FAILURE);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
waitpid (pid, &status, 0);
|
|
|
|
} else {
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_logger_close ();
|
|
|
|
|
2007-08-28 18:40:07 +05:30
|
|
|
#ifdef __linux__
|
2007-04-25 21:18:54 +05:30
|
|
|
execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
|
2007-04-11 18:14:47 +05:30
|
|
|
eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
|
2007-04-05 16:48:42 +05:30
|
|
|
#else
|
2007-04-21 00:28:42 +05:30
|
|
|
exit (EXIT_SUCCESS);
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
2007-04-21 00:28:42 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2007-04-20 18:42:21 +05:30
|
|
|
static void single_user (void)
|
|
|
|
{
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_logger_close ();
|
|
|
|
|
2007-04-20 18:42:21 +05:30
|
|
|
#ifdef __linux__
|
|
|
|
execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
|
|
|
|
eerrorx ("%s: unable to exec `/sbin/telinit': %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, strerror (errno));
|
2007-04-20 18:42:21 +05:30
|
|
|
#else
|
|
|
|
if (kill (1, SIGTERM) != 0)
|
|
|
|
eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, strerror (errno));
|
2007-04-20 18:42:21 +05:30
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-10-29 21:32:18 +05:30
|
|
|
static bool set_ksoftlevel (const char *level)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
FILE *fp;
|
|
|
|
|
2007-09-29 22:50:52 +05:30
|
|
|
if (! level ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (level, getenv ("RC_BOOTLEVEL")) == 0 ||
|
|
|
|
strcmp (level, RC_LEVEL_SINGLE) == 0 ||
|
|
|
|
strcmp (level, RC_LEVEL_SYSINIT) == 0)
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
2007-10-08 16:41:21 +05:30
|
|
|
if (exists (RC_KSOFTLEVEL) &&
|
2008-01-11 21:21:40 +05:30
|
|
|
unlink (RC_KSOFTLEVEL) != 0)
|
2007-08-28 14:43:46 +05:30
|
|
|
eerror ("unlink `%s': %s", RC_KSOFTLEVEL, strerror (errno));
|
2007-10-29 21:32:18 +05:30
|
|
|
return (false);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2007-08-28 14:43:46 +05:30
|
|
|
if (! (fp = fopen (RC_KSOFTLEVEL, "w"))) {
|
|
|
|
eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
|
2007-10-29 21:32:18 +05:30
|
|
|
return (false);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2007-09-29 22:50:52 +05:30
|
|
|
fprintf (fp, "%s", level);
|
2007-04-11 18:14:47 +05:30
|
|
|
fclose (fp);
|
2007-10-29 21:32:18 +05:30
|
|
|
return (true);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
static int get_ksoftlevel (char *buffer, int buffer_len)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
int i = 0;
|
|
|
|
|
2007-10-08 16:41:21 +05:30
|
|
|
if (! exists (RC_KSOFTLEVEL))
|
2007-08-28 14:20:04 +05:30
|
|
|
return (0);
|
2007-07-10 17:12:56 +05:30
|
|
|
|
2007-08-28 14:43:46 +05:30
|
|
|
if (! (fp = fopen (RC_KSOFTLEVEL, "r"))) {
|
|
|
|
eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
|
2007-08-28 14:20:04 +05:30
|
|
|
return (-1);
|
2007-07-10 17:12:56 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (fgets (buffer, buffer_len, fp)) {
|
|
|
|
i = strlen (buffer) - 1;
|
|
|
|
if (buffer[i] == '\n')
|
|
|
|
buffer[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose (fp);
|
2007-08-28 14:20:04 +05:30
|
|
|
return (i);
|
2007-07-10 17:12:56 +05:30
|
|
|
}
|
|
|
|
|
2007-04-21 00:28:42 +05:30
|
|
|
static void add_pid (pid_t pid)
|
|
|
|
{
|
|
|
|
pidlist_t *sp = service_pids;
|
|
|
|
if (sp) {
|
|
|
|
while (sp->next)
|
|
|
|
sp = sp->next;
|
2007-10-08 16:41:21 +05:30
|
|
|
sp->next = xmalloc (sizeof (pidlist_t));
|
2007-04-21 00:28:42 +05:30
|
|
|
sp = sp->next;
|
|
|
|
} else
|
2007-10-08 16:41:21 +05:30
|
|
|
sp = service_pids = xmalloc (sizeof (pidlist_t));
|
2007-04-21 00:28:42 +05:30
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:16:56 +05:30
|
|
|
static void wait_for_services ()
|
|
|
|
{
|
|
|
|
while (waitpid (0, 0, 0) != -1);
|
|
|
|
}
|
|
|
|
|
2007-04-09 22:23:21 +05:30
|
|
|
static void handle_signal (int sig)
|
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
int serrno = errno;
|
|
|
|
char signame[10] = { '\0' };
|
2007-04-21 00:28:42 +05:30
|
|
|
pidlist_t *pl;
|
|
|
|
pid_t pid;
|
|
|
|
int status = 0;
|
2007-10-31 21:16:56 +05:30
|
|
|
struct winsize ws;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
switch (sig) {
|
2007-04-21 00:28:42 +05:30
|
|
|
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;
|
2007-04-21 00:33:56 +05:30
|
|
|
|
2007-10-31 21:16:56 +05:30
|
|
|
case SIGWINCH:
|
|
|
|
if (rc_logger_tty >= 0) {
|
|
|
|
ioctl (STDIN_FILENO, TIOCGWINSZ, &ws);
|
|
|
|
ioctl (rc_logger_tty, TIOCSWINSZ, &ws);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
case SIGINT:
|
|
|
|
if (! signame[0])
|
|
|
|
snprintf (signame, sizeof (signame), "SIGINT");
|
2008-01-22 16:37:39 +05:30
|
|
|
/* FALLTHROUGH */
|
2007-04-11 18:14:47 +05:30
|
|
|
case SIGTERM:
|
|
|
|
if (! signame[0])
|
|
|
|
snprintf (signame, sizeof (signame), "SIGTERM");
|
2008-01-22 16:37:39 +05:30
|
|
|
/* FALLTHROUGH */
|
2007-04-11 18:14:47 +05:30
|
|
|
case SIGQUIT:
|
|
|
|
if (! signame[0])
|
|
|
|
snprintf (signame, sizeof (signame), "SIGQUIT");
|
|
|
|
eerrorx ("%s: caught %s, aborting", applet, signame);
|
2008-01-22 16:37:39 +05:30
|
|
|
/* NOTREACHED */
|
2007-04-20 18:42:21 +05:30
|
|
|
case SIGUSR1:
|
|
|
|
eerror ("rc: Aborting!");
|
|
|
|
/* Kill any running services we have started */
|
2007-04-21 00:33:56 +05:30
|
|
|
|
2007-04-21 00:28:42 +05:30
|
|
|
signal (SIGCHLD, SIG_IGN);
|
|
|
|
for (pl = service_pids; pl; pl = pl->next)
|
|
|
|
kill (pl->pid, SIGTERM);
|
2007-04-21 00:33:56 +05:30
|
|
|
|
2007-04-20 20:32:13 +05:30
|
|
|
/* Notify plugins we are aborting */
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_ABORT, NULL);
|
2007-04-21 00:33:56 +05:30
|
|
|
|
2007-04-21 00:28:42 +05:30
|
|
|
/* Only drop into single user mode if we're booting */
|
2007-07-11 18:32:05 +05:30
|
|
|
if ((PREVLEVEL &&
|
2008-01-11 21:21:40 +05:30
|
|
|
(strcmp (PREVLEVEL, "S") == 0 ||
|
|
|
|
strcmp (PREVLEVEL, "1") == 0)) ||
|
|
|
|
(RUNLEVEL &&
|
|
|
|
(strcmp (RUNLEVEL, "S") == 0 ||
|
|
|
|
strcmp (RUNLEVEL, "1") == 0)))
|
2007-04-20 18:42:21 +05:30
|
|
|
single_user ();
|
|
|
|
|
|
|
|
exit (EXIT_FAILURE);
|
2008-01-22 16:37:39 +05:30
|
|
|
/* NOTREACHED */
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
default:
|
|
|
|
eerror ("%s: caught unknown signal %d", applet, sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore errno */
|
|
|
|
errno = serrno;
|
2007-04-09 22:23:21 +05:30
|
|
|
}
|
|
|
|
|
2007-10-31 21:16:56 +05:30
|
|
|
static void run_script (const char *script)
|
|
|
|
{
|
2007-05-22 17:55:43 +05:30
|
|
|
int status = 0;
|
|
|
|
pid_t pid = vfork ();
|
2007-07-10 17:12:56 +05:30
|
|
|
|
2007-05-22 17:55:43 +05:30
|
|
|
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",
|
2008-01-11 21:21:40 +05:30
|
|
|
script, applet, strerror (errno));
|
2007-05-22 17:55:43 +05:30
|
|
|
_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)
|
2007-08-05 02:05:05 +05:30
|
|
|
eerrorx ("%s: failed to exec `%s'", applet, script);
|
2007-05-22 17:55:43 +05:30
|
|
|
}
|
|
|
|
|
2008-01-29 19:22:54 +05:30
|
|
|
static void do_coldplug (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
DIR *dp;
|
|
|
|
struct dirent *d;
|
|
|
|
char *service;
|
|
|
|
|
|
|
|
if (! rc_conf_yesno ("rc_coldplug") && errno != ENOENT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* We need to ensure our state dirs exist.
|
|
|
|
* We should have a better call than this, but oh well. */
|
|
|
|
rc_deptree_update_needed ();
|
|
|
|
|
|
|
|
#ifdef BSD
|
|
|
|
#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) &&
|
|
|
|
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 ((int) *p)) {
|
|
|
|
size_t len;
|
|
|
|
len = (strlen ("moused.") + strlen (d->d_name) + 1);
|
|
|
|
tmp = xmalloc (sizeof (char) * len);
|
|
|
|
snprintf (tmp, len, "moused.%s", d->d_name);
|
|
|
|
if (rc_service_exists (tmp) &&
|
|
|
|
service_plugable (tmp))
|
|
|
|
rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
|
|
|
|
CHAR_FREE (tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir (dp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif __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) &&
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (rc_yesno (getenv ("EINFO_QUIET")))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Load our list of coldplugged services and display them */
|
|
|
|
einfon ("Device initiated services:%s", ecolor (ECOLOR_HILITE));
|
|
|
|
coldplugged_services = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
|
|
|
|
STRLIST_FOREACH (coldplugged_services, service, i)
|
|
|
|
printf (" %s", service);
|
|
|
|
printf ("%s\n", ecolor (ECOLOR_NORMAL));
|
|
|
|
}
|
|
|
|
|
2007-06-28 21:14:14 +05:30
|
|
|
#include "_usage.h"
|
2007-10-29 21:32:18 +05:30
|
|
|
#define getoptstring "o:" getoptstring_COMMON
|
2007-06-28 21:14:14 +05:30
|
|
|
static struct option longopts[] = {
|
2007-10-29 21:32:18 +05:30
|
|
|
{ "override", 1, NULL, 'o' },
|
2007-06-28 21:14:14 +05:30
|
|
|
longopts_COMMON
|
|
|
|
};
|
2007-09-25 21:51:38 +05:30
|
|
|
static const char * const longopts_help[] = {
|
2007-10-29 21:32:18 +05:30
|
|
|
"override the next runlevel to change into\nwhen leaving single user or boot runlevels",
|
2007-09-25 21:51:38 +05:30
|
|
|
longopts_help_COMMON
|
|
|
|
};
|
2007-06-28 21:14:14 +05:30
|
|
|
#include "_usage.c"
|
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
int main (int argc, char **argv)
|
|
|
|
{
|
2007-07-21 18:19:51 +05:30
|
|
|
const char *bootlevel = NULL;
|
2007-04-11 18:14:47 +05:30
|
|
|
char *newlevel = NULL;
|
|
|
|
char *service = NULL;
|
|
|
|
char **deporder = NULL;
|
2007-09-18 21:13:19 +05:30
|
|
|
char **tmplist;
|
2007-04-11 18:14:47 +05:30
|
|
|
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];
|
2007-04-20 18:42:21 +05:30
|
|
|
char pidstr[6];
|
2007-06-28 21:14:14 +05:30
|
|
|
int opt;
|
2007-11-23 17:34:11 +05:30
|
|
|
bool parallel;
|
2007-12-14 17:53:13 +05:30
|
|
|
int regen = 0;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-12-19 19:23:52 +05:30
|
|
|
applet = basename_c (argv[0]);
|
2007-07-31 21:35:56 +05:30
|
|
|
atexit (cleanup);
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! applet)
|
|
|
|
eerrorx ("arguments required");
|
|
|
|
|
2007-11-19 22:11:36 +05:30
|
|
|
if (argc > 1 && (strcmp (argv[1], "--version") == 0)) {
|
2008-01-03 18:32:03 +05:30
|
|
|
printf ("%s (OpenRC"
|
|
|
|
#ifdef BRANDING
|
2008-01-11 21:21:40 +05:30
|
|
|
" " BRANDING
|
2008-01-03 18:32:03 +05:30
|
|
|
#endif
|
2008-01-11 21:21:40 +05:30
|
|
|
") version " VERSION "\n", applet);
|
2007-11-19 22:11:36 +05:30
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2008-01-14 19:54:20 +05:30
|
|
|
/* Run our built in applets. If we ran one, we don't return. */
|
|
|
|
run_applets (argc, argv);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-01-15 01:23:56 +05:30
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
|
2007-06-26 14:50:42 +05:30
|
|
|
/* Change dir to / to ensure all scripts don't use stuff in pwd */
|
|
|
|
chdir ("/");
|
|
|
|
|
2007-07-11 18:32:05 +05:30
|
|
|
/* RUNLEVEL is set by sysvinit as is a magic number
|
2008-01-29 19:22:54 +05:30
|
|
|
* RC_SOFTLEVEL is set by us and is the name for this magic number
|
|
|
|
* even though all our userland documentation refers to runlevel */
|
2007-07-11 18:32:05 +05:30
|
|
|
RUNLEVEL = getenv ("RUNLEVEL");
|
|
|
|
PREVLEVEL = getenv ("PREVLEVEL");
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Ensure our environment is pure
|
2008-01-29 19:22:54 +05:30
|
|
|
* Also, add our configuration to it */
|
2007-10-08 16:37:39 +05:30
|
|
|
env = env_filter ();
|
|
|
|
tmplist = env_config ();
|
2007-09-18 21:13:19 +05:30
|
|
|
rc_strlist_join (&env, tmplist);
|
|
|
|
rc_strlist_free (tmplist);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
if (env) {
|
|
|
|
char *p;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
|
|
|
#ifdef __linux__
|
2007-04-11 18:14:47 +05:30
|
|
|
/* clearenv isn't portable, but there's no harm in using it
|
2008-01-29 19:22:54 +05:30
|
|
|
* if we have it */
|
2007-04-11 18:14:47 +05:30
|
|
|
clearenv ();
|
2007-04-05 16:48:42 +05:30
|
|
|
#else
|
2007-04-11 18:14:47 +05:30
|
|
|
char *var;
|
|
|
|
/* No clearenv present here then.
|
2008-01-29 19:22:54 +05:30
|
|
|
* 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. */
|
2007-04-11 18:14:47 +05:30
|
|
|
while (environ[0]) {
|
2007-10-08 16:46:22 +05:30
|
|
|
tmp = xstrdup (environ[0]);
|
2007-04-11 18:14:47 +05:30
|
|
|
p = tmp;
|
|
|
|
var = strsep (&p, "=");
|
|
|
|
unsetenv (var);
|
|
|
|
free (tmp);
|
|
|
|
}
|
|
|
|
tmp = NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
2007-06-28 21:14:14 +05:30
|
|
|
argc++;
|
|
|
|
argv--;
|
|
|
|
while ((opt = getopt_long (argc, argv, getoptstring,
|
2008-01-11 21:21:40 +05:30
|
|
|
longopts, (int *) 0)) != -1)
|
2007-06-28 21:14:14 +05:30
|
|
|
{
|
|
|
|
switch (opt) {
|
2007-10-29 21:32:18 +05:30
|
|
|
case 'o':
|
2008-01-21 21:00:40 +05:30
|
|
|
if (*optarg == '\0')
|
2007-10-29 21:32:18 +05:30
|
|
|
optarg = NULL;
|
|
|
|
exit (set_ksoftlevel (optarg) ? EXIT_SUCCESS : EXIT_FAILURE);
|
2008-01-22 16:37:39 +05:30
|
|
|
/* NOTREACHED */
|
2008-01-11 21:21:40 +05:30
|
|
|
case_RC_COMMON_GETOPT
|
2007-06-28 21:14:14 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newlevel = argv[optind++];
|
2007-07-10 17:12:56 +05:30
|
|
|
|
2007-06-28 21:14:14 +05:30
|
|
|
/* OK, so we really are the main RC process
|
2008-01-29 19:22:54 +05:30
|
|
|
* Only root should be able to run us */
|
2007-06-28 21:14:14 +05:30
|
|
|
if (geteuid () != 0)
|
|
|
|
eerrorx ("%s: root access required", applet);
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Enable logging */
|
2007-12-06 16:18:00 +05:30
|
|
|
setenv ("EINFO_LOG", "rc", 1);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-04-20 18:42:21 +05:30
|
|
|
/* Export our PID */
|
|
|
|
snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
|
|
|
|
setenv ("RC_PID", pidstr, 1);
|
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
/* Load current softlevel */
|
2007-07-21 18:19:51 +05:30
|
|
|
bootlevel = getenv ("RC_BOOTLEVEL");
|
2007-10-02 15:27:23 +05:30
|
|
|
runlevel = rc_runlevel_get ();
|
2007-07-10 17:12:56 +05:30
|
|
|
|
2007-10-31 21:16:56 +05:30
|
|
|
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);
|
|
|
|
|
2007-12-06 16:46:27 +05:30
|
|
|
if (! rc_yesno (getenv ("EINFO_QUIET")))
|
|
|
|
interactive = exists (INTERACTIVE);
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_plugin_load ();
|
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
/* Check we're in the runlevel requested, ie from
|
2008-01-29 19:22:54 +05:30
|
|
|
* rc single
|
|
|
|
* rc shutdown
|
|
|
|
* rc reboot
|
|
|
|
*/
|
2007-07-10 17:12:56 +05:30
|
|
|
if (newlevel) {
|
|
|
|
if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
|
2008-01-11 21:21:40 +05:30
|
|
|
RUNLEVEL &&
|
|
|
|
(strcmp (RUNLEVEL, "S") == 0 ||
|
|
|
|
strcmp (RUNLEVEL, "1") == 0))
|
2007-07-10 17:12:56 +05:30
|
|
|
{
|
2008-01-29 15:33:45 +05:30
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
struct utsname uts;
|
2008-01-29 15:33:45 +05:30
|
|
|
/* OK, we're either in runlevel 1 or single user mode */
|
2007-04-05 16:48:42 +05:30
|
|
|
#ifdef __linux__
|
2007-07-23 17:06:12 +05:30
|
|
|
char *cmd;
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
/* 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? */
|
2007-10-08 16:41:21 +05:30
|
|
|
if (exists (INITEARLYSH))
|
2007-07-10 17:12:56 +05:30
|
|
|
run_script (INITEARLYSH);
|
2007-04-26 16:54:07 +05:30
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
uname (&uts);
|
2008-01-29 15:33:45 +05:30
|
|
|
printf ("\n %sOpenRC %s" VERSION "%s is starting up %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
ecolor (ECOLOR_GOOD), ecolor (ECOLOR_HILITE),
|
2008-01-29 15:33:45 +05:30
|
|
|
ecolor (ECOLOR_NORMAL), ecolor (ECOLOR_BRACKET));
|
2008-01-03 18:32:03 +05:30
|
|
|
#ifdef BRANDING
|
2008-01-29 15:33:45 +05:30
|
|
|
printf (BRANDING " (%s)", uts.arch);
|
2008-01-03 18:32:03 +05:30
|
|
|
#else
|
2008-01-29 15:33:45 +05:30
|
|
|
printf ("%s %s (%s)",
|
|
|
|
uts.sysname,
|
|
|
|
uts.release,
|
|
|
|
uts.machine);
|
|
|
|
#endif
|
|
|
|
printf ("%s\n\n", ecolor (ECOLOR_NORMAL));
|
2007-04-17 15:02:18 +05:30
|
|
|
|
2007-12-06 16:46:27 +05:30
|
|
|
if (! rc_yesno (getenv ("EINFO_QUIET")) &&
|
2008-01-11 21:21:40 +05:30
|
|
|
rc_conf_yesno ("rc_interactive"))
|
2007-07-10 17:12:56 +05:30
|
|
|
printf ("Press %sI%s to enter interactive boot mode\n\n",
|
2008-01-11 21:21:40 +05:30
|
|
|
ecolor (ECOLOR_GOOD), ecolor (ECOLOR_NORMAL));
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
setenv ("RC_SOFTLEVEL", newlevel, 1);
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, newlevel);
|
2007-07-10 17:12:56 +05:30
|
|
|
run_script (INITSH);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#ifdef __linux__
|
2007-07-23 17:06:12 +05:30
|
|
|
/* If we requested a softlevel, save it now */
|
2007-07-10 17:12:56 +05:30
|
|
|
set_ksoftlevel (NULL);
|
2007-07-23 17:06:12 +05:30
|
|
|
if ((cmd = proc_getent ("softlevel"))) {
|
|
|
|
set_ksoftlevel (cmd);
|
|
|
|
free (cmd);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
2007-10-31 21:16:56 +05:30
|
|
|
|
2008-01-29 19:22:54 +05:30
|
|
|
do_coldplug ();
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, newlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
if (want_interactive ())
|
|
|
|
mark_interactive ();
|
|
|
|
|
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
} else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! RUNLEVEL ||
|
2008-01-11 21:21:40 +05:30
|
|
|
(strcmp (RUNLEVEL, "S") != 0 &&
|
|
|
|
strcmp (RUNLEVEL, "1") != 0))
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
|
|
|
/* Remember the current runlevel for when we come back */
|
|
|
|
set_ksoftlevel (runlevel);
|
2007-04-20 18:42:21 +05:30
|
|
|
single_user ();
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
} else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
|
|
|
|
if (! RUNLEVEL ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (RUNLEVEL, "6") != 0)
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_logger_close ();
|
2007-08-28 14:47:04 +05:30
|
|
|
execl (SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
|
|
|
|
eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, strerror (errno));
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
} else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
|
|
|
|
if (! RUNLEVEL ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (RUNLEVEL, "0") != 0)
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_logger_close ();
|
2007-08-28 14:47:04 +05:30
|
|
|
execl (SHUTDOWN, SHUTDOWN,
|
2007-08-28 18:40:07 +05:30
|
|
|
#ifdef __linux__
|
2008-01-11 21:21:40 +05:30
|
|
|
"-h",
|
2007-04-05 16:48:42 +05:30
|
|
|
#else
|
2008-01-11 21:21:40 +05:30
|
|
|
"-p",
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
2008-01-11 21:21:40 +05:30
|
|
|
"now", (char *) NULL);
|
2007-08-28 14:47:04 +05:30
|
|
|
eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, strerror (errno));
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-21 00:28:42 +05:30
|
|
|
/* Now we start handling our children */
|
|
|
|
signal (SIGCHLD, handle_signal);
|
|
|
|
|
2007-07-10 17:12:56 +05:30
|
|
|
/* We should only use ksoftlevel if we were in single user mode
|
2008-01-29 19:22:54 +05:30
|
|
|
* If not, we need to erase ksoftlevel now. */
|
2007-07-10 17:12:56 +05:30
|
|
|
if (PREVLEVEL &&
|
2008-01-11 21:21:40 +05:30
|
|
|
(strcmp (PREVLEVEL, "1") == 0 ||
|
|
|
|
strcmp (PREVLEVEL, "S") == 0 ||
|
|
|
|
strcmp (PREVLEVEL, "N") == 0))
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
2007-08-28 18:36:44 +05:30
|
|
|
/* Try not to join boot and ksoftlevels together */
|
|
|
|
if (! newlevel ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (newlevel, getenv ("RC_BOOTLEVEL")) != 0)
|
2007-08-28 18:36:44 +05:30
|
|
|
if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
|
|
|
|
newlevel = ksoftbuffer;
|
2007-07-10 17:12:56 +05:30
|
|
|
} else if (! RUNLEVEL ||
|
2008-01-11 21:21:40 +05:30
|
|
|
(strcmp (RUNLEVEL, "1") != 0 &&
|
|
|
|
strcmp (RUNLEVEL, "S") != 0 &&
|
|
|
|
strcmp (RUNLEVEL, "N") != 0))
|
2007-07-10 17:12:56 +05:30
|
|
|
{
|
|
|
|
set_ksoftlevel (NULL);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (newlevel &&
|
2008-01-11 21:21:40 +05:30
|
|
|
(strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
|
|
|
|
strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
|
|
|
strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
|
|
|
going_down = true;
|
2007-10-02 15:27:23 +05:30
|
|
|
rc_runlevel_set (newlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
setenv ("RC_SOFTLEVEL", newlevel, 1);
|
2007-10-31 21:16:56 +05:30
|
|
|
|
|
|
|
#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
|
|
|
|
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, newlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
} else {
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, runlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if runlevel is valid if we're changing */
|
|
|
|
if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
|
2007-10-04 22:24:29 +05:30
|
|
|
if (! rc_runlevel_exists (newlevel))
|
2007-04-11 18:14:47 +05:30
|
|
|
eerrorx ("%s: is not a valid runlevel", newlevel);
|
|
|
|
}
|
|
|
|
|
2008-01-29 19:22:54 +05:30
|
|
|
/* Load our deptree */
|
2007-12-14 17:53:13 +05:30
|
|
|
if ((deptree = _rc_deptree_load (®en)) == NULL)
|
2007-04-11 18:14:47 +05:30
|
|
|
eerrorx ("failed to load deptree");
|
|
|
|
|
2008-01-29 19:22:54 +05:30
|
|
|
/* Clean the failed services state dir */
|
2007-12-30 00:29:24 +05:30
|
|
|
clean_failed ();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-08-28 14:43:46 +05:30
|
|
|
mkdir (RC_STOPPING, 0755);
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Build a list of all services to stop and then work out the
|
2008-01-29 19:22:54 +05:30
|
|
|
* correct order for stopping them */
|
2007-10-05 15:46:14 +05:30
|
|
|
stop_services = rc_services_in_state (RC_SERVICE_STARTING);
|
|
|
|
|
|
|
|
tmplist = rc_services_in_state (RC_SERVICE_INACTIVE);
|
2007-09-18 21:13:19 +05:30
|
|
|
rc_strlist_join (&stop_services, tmplist);
|
|
|
|
rc_strlist_free (tmplist);
|
|
|
|
|
2007-10-05 15:46:14 +05:30
|
|
|
tmplist = rc_services_in_state (RC_SERVICE_STARTED);
|
2007-09-18 21:13:19 +05:30
|
|
|
rc_strlist_join (&stop_services, tmplist);
|
|
|
|
rc_strlist_free (tmplist);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-10-15 20:10:53 +05:30
|
|
|
deporder = rc_deptree_depends (deptree, types_nua,
|
2008-01-11 21:21:40 +05:30
|
|
|
(const char **) stop_services,
|
|
|
|
runlevel, depoptions | RC_DEP_STOP);
|
2007-09-18 21:13:19 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
rc_strlist_free (stop_services);
|
|
|
|
stop_services = deporder;
|
|
|
|
deporder = NULL;
|
|
|
|
rc_strlist_reverse (stop_services);
|
|
|
|
|
|
|
|
/* Load our list of coldplugged services */
|
2007-10-05 15:46:14 +05:30
|
|
|
coldplugged_services = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
|
2008-01-29 19:22:54 +05:30
|
|
|
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_services_in_runlevel (bootlevel);
|
|
|
|
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
|
2007-09-18 21:13:19 +05:30
|
|
|
tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
|
|
|
|
rc_strlist_join (&start_services, tmplist);
|
|
|
|
rc_strlist_free (tmplist);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2008-01-29 19:22:54 +05:30
|
|
|
|
|
|
|
STRLIST_FOREACH (coldplugged_services, service, i)
|
|
|
|
rc_strlist_add (&start_services, service);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2008-01-29 19:22:54 +05:30
|
|
|
/* Save our softlevel now */
|
2007-04-11 18:14:47 +05:30
|
|
|
if (going_down)
|
2007-10-02 15:27:23 +05:30
|
|
|
rc_runlevel_set (newlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-11-23 17:34:11 +05:30
|
|
|
parallel = rc_conf_yesno ("rc_parallel");
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* 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;
|
|
|
|
|
2007-09-28 20:23:38 +05:30
|
|
|
if (rc_service_state (service) & RC_SERVICE_STOPPED)
|
2007-04-11 18:14:47 +05:30
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We always stop the service when in these runlevels */
|
|
|
|
if (going_down) {
|
2007-09-29 22:24:58 +05:30
|
|
|
pid_t pid = rc_service_stop (service);
|
2007-11-23 17:34:11 +05:30
|
|
|
if (pid > 0 && ! parallel)
|
2007-10-23 01:03:42 +05:30
|
|
|
rc_waitpid (pid);
|
2007-04-26 16:54:07 +05:30
|
|
|
continue;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
2008-01-22 16:37:39 +05:30
|
|
|
size_t len;
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! newlevel)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
len = strlen (service) + strlen (runlevel) + 2;
|
2007-10-12 04:47:53 +05:30
|
|
|
tmp = xmalloc (sizeof (char) * len);
|
2007-04-11 18:14:47 +05:30
|
|
|
snprintf (tmp, len, "%s.%s", service, runlevel);
|
|
|
|
conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
|
2007-10-08 16:41:21 +05:30
|
|
|
found = exists (conf);
|
2007-04-11 18:14:47 +05:30
|
|
|
CHAR_FREE (conf);
|
|
|
|
CHAR_FREE (tmp);
|
|
|
|
if (! found) {
|
|
|
|
len = strlen (service) + strlen (newlevel) + 2;
|
2007-10-12 04:47:53 +05:30
|
|
|
tmp = xmalloc (sizeof (char) * len);
|
2007-04-11 18:14:47 +05:30
|
|
|
snprintf (tmp, len, "%s.%s", service, newlevel);
|
|
|
|
conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
|
2007-10-08 16:41:21 +05:30
|
|
|
found = exists (conf);
|
2007-04-11 18:14:47 +05:30
|
|
|
CHAR_FREE (conf);
|
|
|
|
CHAR_FREE (tmp);
|
|
|
|
if (!found)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Allow coldplugged services not to be in the runlevels list */
|
2007-09-28 20:23:38 +05:30
|
|
|
if (rc_service_state (service) & RC_SERVICE_COLDPLUGGED)
|
2007-04-11 18:14:47 +05:30
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We got this far! Or last check is to see if any any service that
|
2008-01-29 19:22:54 +05:30
|
|
|
* going to be started depends on us */
|
2007-09-18 17:06:55 +05:30
|
|
|
rc_strlist_add (&stopdeps, service);
|
2007-10-15 20:10:53 +05:30
|
|
|
deporder = rc_deptree_depends (deptree, types_n,
|
2008-01-11 21:21:40 +05:30
|
|
|
(const char **) stopdeps,
|
|
|
|
runlevel, RC_DEP_STRICT);
|
2007-04-11 18:14:47 +05:30
|
|
|
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! */
|
2007-04-21 00:28:42 +05:30
|
|
|
if (! found) {
|
2007-10-31 21:16:56 +05:30
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
if ((pid = rc_service_stop (service)) > 0) {
|
|
|
|
add_pid (pid);
|
|
|
|
|
2007-11-23 17:34:11 +05:30
|
|
|
if (! parallel) {
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_waitpid (pid);
|
|
|
|
remove_pid (pid);
|
|
|
|
}
|
|
|
|
}
|
2007-04-21 00:28:42 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for our services to finish */
|
2007-04-21 00:28:42 +05:30
|
|
|
wait_for_services ();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Notify the plugins we have finished */
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_OUT, runlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-08-28 14:43:46 +05:30
|
|
|
rmdir (RC_STOPPING);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Store the new runlevel */
|
|
|
|
if (newlevel) {
|
2007-10-02 15:27:23 +05:30
|
|
|
rc_runlevel_set (newlevel);
|
2007-09-29 22:50:52 +05:30
|
|
|
free (runlevel);
|
2007-10-08 16:46:22 +05:30
|
|
|
runlevel = xstrdup (newlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
setenv ("RC_SOFTLEVEL", runlevel, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Run the halt script if needed */
|
|
|
|
if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_logger_close ();
|
2007-04-20 18:42:21 +05:30
|
|
|
execl (HALTSH, HALTSH, runlevel, (char *) NULL);
|
2007-04-11 18:14:47 +05:30
|
|
|
eerrorx ("%s: unable to exec `%s': %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, HALTSH, strerror (errno));
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Single user is done now */
|
|
|
|
if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
|
2007-10-08 16:41:21 +05:30
|
|
|
if (exists (INTERACTIVE))
|
2007-04-11 18:14:47 +05:30
|
|
|
unlink (INTERACTIVE);
|
|
|
|
sulogin (false);
|
|
|
|
}
|
|
|
|
|
2007-08-28 14:43:46 +05:30
|
|
|
mkdir (RC_STARTING, 0755);
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, runlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Re-add our coldplugged services if they stopped */
|
|
|
|
STRLIST_FOREACH (coldplugged_services, service, i)
|
2007-09-29 22:24:58 +05:30
|
|
|
rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Order the services to start */
|
2007-10-15 20:10:53 +05:30
|
|
|
deporder = rc_deptree_depends (deptree, types_nua,
|
2008-01-11 21:21:40 +05:30
|
|
|
(const char **) start_services,
|
|
|
|
runlevel, depoptions | RC_DEP_START);
|
2007-04-11 18:14:47 +05:30
|
|
|
rc_strlist_free (start_services);
|
|
|
|
start_services = deporder;
|
|
|
|
deporder = NULL;
|
|
|
|
|
2007-07-23 17:06:12 +05:30
|
|
|
#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, ",")))
|
2007-09-29 22:24:58 +05:30
|
|
|
rc_service_mark (token, RC_SERVICE_STARTED);
|
2007-07-23 17:06:12 +05:30
|
|
|
free (service);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
STRLIST_FOREACH (start_services, service, i) {
|
2007-09-28 20:23:38 +05:30
|
|
|
if (rc_service_state (service) & RC_SERVICE_STOPPED) {
|
2007-04-21 00:28:42 +05:30
|
|
|
pid_t pid;
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! interactive)
|
|
|
|
interactive = want_interactive ();
|
|
|
|
|
|
|
|
if (interactive) {
|
2007-04-05 16:48:42 +05:30
|
|
|
interactive_retry:
|
2007-04-11 18:14:47 +05:30
|
|
|
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 ();
|
2007-04-05 16:48:42 +05:30
|
|
|
interactive_option:
|
2007-04-11 18:14:47 +05:30
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2007-04-21 00:28:42 +05:30
|
|
|
|
|
|
|
/* Remember the pid if we're running in parallel */
|
2007-10-31 21:16:56 +05:30
|
|
|
if ((pid = rc_service_start (service)) > 0) {
|
2007-04-21 00:28:42 +05:30
|
|
|
add_pid (pid);
|
|
|
|
|
2007-11-23 17:34:11 +05:30
|
|
|
if (! parallel) {
|
2007-10-31 21:16:56 +05:30
|
|
|
rc_waitpid (pid);
|
|
|
|
remove_pid (pid);
|
|
|
|
}
|
2007-04-21 00:28:42 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for our services to finish */
|
2007-04-20 15:09:47 +05:30
|
|
|
wait_for_services ();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-09-28 17:59:23 +05:30
|
|
|
rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, runlevel);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-07-23 17:06:12 +05:30
|
|
|
#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, ",")))
|
2007-09-29 22:24:58 +05:30
|
|
|
rc_service_mark (token, RC_SERVICE_STOPPED);
|
2007-07-23 17:06:12 +05:30
|
|
|
free (service);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Store our interactive status for boot */
|
2007-07-21 18:19:51 +05:30
|
|
|
if (interactive && strcmp (runlevel, bootlevel) == 0)
|
2007-04-11 18:14:47 +05:30
|
|
|
mark_interactive ();
|
|
|
|
else {
|
2007-10-08 16:41:21 +05:30
|
|
|
if (exists (INTERACTIVE))
|
2007-04-11 18:14:47 +05:30
|
|
|
unlink (INTERACTIVE);
|
|
|
|
}
|
|
|
|
|
2007-12-14 17:53:13 +05:30
|
|
|
/* 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);
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
return (EXIT_SUCCESS);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|