aboutsummaryrefslogtreecommitdiff
path: root/src/sysvinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sysvinit.c')
-rw-r--r--src/sysvinit.c296
1 files changed, 265 insertions, 31 deletions
diff --git a/src/sysvinit.c b/src/sysvinit.c
index 940125f..23cad9a 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -16,13 +16,13 @@
#include "pies.h"
#include "prog.h"
+#include <termios.h>
enum boot_state
{
sysinit,
boot,
- single0,
- single1,
+ single,
normal,
max_boot_state
};
@@ -30,12 +30,11 @@ enum boot_state
static char *boot_state_name[] = {
"sysinit",
"boot",
- "single0",
- "single1",
+ "single",
"normal"
};
-static char boot_state_str[] = "#*sS ";
+static char boot_state_str[] = "#*s ";
static const char valid_runlevels[] = "0123456789S";
@@ -43,22 +42,154 @@ static int boot_trans_tab[max_boot_state][sizeof(valid_runlevels)-1] = {
/* 0, 1, 2, 3, 4, */
/* 5, 6, 7, 8, 9, S */
/* sysinit */ { boot, boot, boot, boot, boot,
- boot, boot, boot, boot, boot, single0 },
+ boot, boot, boot, boot, boot, single },
/* boot */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single1 },
- /* single0 */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single0 },
- /* single1 */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single1 },
+ normal, normal, normal, normal, normal, normal },
+ /* single */ { boot, boot, boot, boot, boot,
+ boot, boot, boot, boot, boot, single },
/* normal */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single1 },
+ normal, normal, normal, normal, normal, normal },
};
enum boot_state boot_state;
int runlevel = 0;
+int prevlevel = 'N';
int initdefault; /* Default runlevel */
int dfl_level;
+
+int
+console_open (int mode)
+{
+ int i, fd;
+
+ for (i = 0; i < 5; i++)
+ {
+ fd = open (console_device, mode | O_NONBLOCK);
+ if (fd >= 0)
+ {
+ fcntl (fd, F_SETFL, mode);
+ return fd;
+ }
+ }
+ return -1;
+}
+
+void
+console_stty ()
+{
+ struct termios tty;
+ int fd;
+
+ if ((fd = console_open (O_RDWR|O_NOCTTY)) < 0)
+ {
+ logmsg (LOG_CRIT, "can't open %s", console_device);
+ return;
+ }
+
+ tcgetattr (fd, &tty);
+
+ tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+ tty.c_cflag |= HUPCL|CLOCAL|CREAD;
+
+ tty.c_cc[VINTR] = 3; /* ctrl('c') */
+ tty.c_cc[VQUIT] = 28; /* ctrl('\\') */
+ tty.c_cc[VERASE] = 127;
+ tty.c_cc[VKILL] = 24; /* ctrl('x') */
+ tty.c_cc[VEOF] = 4; /* ctrl('d') */
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VSTART] = 17; /* ctrl('q') */
+ tty.c_cc[VSTOP] = 19; /* ctrl('s') */
+ tty.c_cc[VSUSP] = 26; /* ctrl('z') */
+
+ /*
+ * Set pre and post processing
+ */
+ tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+ tty.c_oflag = OPOST|ONLCR;
+ tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+
+ /*
+ * Now set the terminal line.
+ * We don't care about non-transmitted output data
+ * and non-read input data.
+ */
+ tcsetattr (fd, TCSANOW, &tty);
+ tcflush(fd, TCIOFLUSH);
+ close (fd);
+}
+
+int
+askrunlevel ()
+{
+ int fd;
+ char c, lvl = -1;
+ enum { srl_init, srl_char, srl_r, srl_n, srl_skip } srl = srl_init;
+ static const char prompt[] = "\nEnter runlevel: ";
+
+ console_stty ();
+ fd = console_open (O_RDWR|O_NOCTTY);
+ if (fd == -1)
+ return 'S';
+
+ while (1)
+ {
+ if (srl == srl_init)
+ {
+ write (fd, prompt, sizeof (prompt) - 1);
+ if (read (fd, &lvl, 1) != 1)
+ return 'S';
+ srl = srl_char;
+ }
+ else if (srl == srl_n)
+ {
+ if (is_valid_runlevel (lvl))
+ break;
+ srl = srl_init;
+ }
+ else
+ {
+ if (read (fd, &c, 1) != 1)
+ {
+ if (!is_valid_runlevel (lvl))
+ lvl = 'S';
+ break;
+ }
+
+ switch (srl)
+ {
+ case srl_char:
+ if (c == '\r')
+ srl = srl_r;
+ else if (c == '\n')
+ srl = srl_n;
+ else
+ srl = srl_skip;
+ break;
+
+ case srl_r:
+ if (c == '\n')
+ srl = srl_n;
+ else
+ srl = srl_skip;
+ break;
+
+ case srl_skip:
+ if (c == '\n')
+ srl = srl_init;
+ }
+ }
+ }
+ close (fd);
+ return toupper (lvl);
+}
+
+static int
+getinitdefault ()
+{
+ return initdefault ? initdefault : askrunlevel ();
+}
static int
runlevel_index (int n)
@@ -75,10 +206,11 @@ runlevel_index (int n)
}
static int
-enablecomp (struct component *comp, int finished, void *data)
+enablecomp (struct prog *prog, void *data)
{
int *wait = data;
int rc;
+ struct component *comp = prog->v.p.comp;
switch (boot_state)
{
@@ -88,8 +220,7 @@ enablecomp (struct component *comp, int finished, void *data)
case boot:
return comp->mode == pies_comp_boot || comp->mode == pies_comp_bootwait;
- case single0:
- case single1:
+ case single:
case normal:
switch (comp->mode)
{
@@ -111,7 +242,7 @@ enablecomp (struct component *comp, int finished, void *data)
rc = !!strchr (comp->runlevels, runlevel);
if (!rc)
return rc;
- if (finished)
+ if (prog->v.p.status == status_finished)
return -1;
if (wait)
{
@@ -125,6 +256,31 @@ enablecomp (struct component *comp, int finished, void *data)
return rc;
}
+static int
+runlevel_setup_prog (struct prog *prog, void *data)
+{
+ if (is_sysvinit (prog->v.p.comp))
+ {
+ int rc = enablecomp (prog, data);
+ if (rc < 0)
+ return 0;
+ if (rc)
+ prog->v.p.status = status_enabled;
+ else
+ prog->v.p.status = status_disabled;
+ debug (1, ("%s: %s", prog->tag,
+ prog->v.p.status == status_enabled ?
+ "enabled" : "disabled"));
+ }
+ return 0;
+}
+
+static void
+sysvinit_runlevel_setup (int *wait)
+{
+ progman_foreach (runlevel_setup_prog, wait);
+}
+
static const char valid_runlevel_arg[] = "0123456789SsQqAaBbCcUu";
int
@@ -133,6 +289,57 @@ is_valid_runlevel (int c)
return !!strchr (valid_runlevel_arg, c);
}
+#define ENVAR_CONSOLE "CONSOLE="
+#define ENVTMPL_CONSOLE "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+static char env_prevlevel[] = "PREVLEVEL=x";
+static char env_runlevel[] = "RUNLEVEL=x";
+static char env_console[] = ENVAR_CONSOLE ENVTMPL_CONSOLE;
+
+char *sysvinit_environ_hint[] = {
+ env_prevlevel,
+ env_runlevel,
+ env_console,
+ "INIT_VERSION=" PACKAGE_STRING,
+ "PATH=/bin:/usr/bin:/sbin:/usr/sbin",
+ NULL
+};
+
+#define ENVI_PREVLEVEL 0
+#define ENVI_RUNLEVEL 1
+#define ENVI_CONSOLE 2
+#define ENVI_VERSION 3
+#define ENVI_PATH 4
+
+static void
+envsetup ()
+{
+ int i;
+
+ for (i = 0; sysvinit_environ_hint[i]; i++)
+ {
+ char *str = sysvinit_environ_hint[i];
+ switch (i)
+ {
+ case ENVI_PREVLEVEL:
+ str[strlen (str) - 1] = prevlevel;
+ break;
+
+ case ENVI_RUNLEVEL:
+ str[strlen (str) - 1] =
+ boot_state_str[boot_state] == ' ' ?
+ (runlevel ? runlevel : '#') : boot_state_str[boot_state];
+ break;
+
+ case ENVI_CONSOLE:
+ if (strlen (console_device) >= sizeof (ENVTMPL_CONSOLE))
+ logmsg (LOG_ERR, "console device name too long");
+ else
+ strcpy (str + sizeof (ENVAR_CONSOLE) - 1, console_device);
+ }
+ }
+}
+
static void create_fifo (void);
static int
@@ -265,10 +472,42 @@ create_fifo ()
register_socket (fd, sysvinit_fifo_handler, NULL);
}
+static char *try_console[] = { NULL, "/dev/console", "/dev/tty0" };
+char *console_device;
+
+static void
+set_console_dev ()
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE (try_console); i++)
+ {
+ if (try_console[i])
+ {
+ int fd = open (try_console[i], O_RDONLY|O_NONBLOCK);
+
+ if (fd >= 0)
+ {
+ close (fd);
+ console_device = try_console[i];
+ return;
+ }
+ }
+ }
+ /* provide default */
+ console_device = "/dev/null";
+}
+
void
sysvinit_begin ()
{
- progman_sysvinit_enable (enablecomp, NULL);
+ close (0);
+ close (1);
+ close (2);
+ set_console_dev ();
+ console_stty ();
+ setsid ();
+ envsetup ();
+ sysvinit_runlevel_setup (NULL);
}
int
@@ -281,23 +520,17 @@ inittrans ()
static int wait = 0;
if (progman_running_p ())
- {
- debug (1, ("%s exiting: some components still running",__FUNCTION__));
- /* Noting to do if there are processes left in the previous runlevel */
- return 0;
- }
+ /* Noting to do if there are processes left in the previous runlevel */
+ return 0;
if (runlevel == 0)
- n = runlevel_index (dfl_level ? dfl_level : initdefault);
+ n = runlevel_index (dfl_level ? dfl_level : getinitdefault ());
else
n = runlevel_index (runlevel);
if (n == -1)
n = runlevel_index ('S');
newstate = boot_trans_tab[boot_state][n];
- debug (1, ("STATE TRANS: %s(%c,%d) -> %s", boot_state_name[boot_state],
- runlevel,n,
- boot_state_name[newstate]));
if (newstate != boot_state)
{
debug (1, ("STATE TRANS: %s -> %s", boot_state_name[boot_state],
@@ -314,13 +547,12 @@ inittrans ()
case boot:
sysvinit_acct (SYSV_ACCT_BOOT, "reboot", "~~", 0, "~");
break;
- case single0:
+ case single:
newlevel = 'S';
break;
- case single1:
case normal:
/* boot -> normal */
- newlevel = dfl_level ? dfl_level : initdefault;
+ newlevel = dfl_level ? dfl_level : getinitdefault ();
create_fifo ();
}
if (newlevel && newlevel != runlevel)
@@ -329,6 +561,7 @@ inittrans ()
sysvinit_acct (SYSV_ACCT_RUNLEVEL, "runlevel", "~~",
newlevel + 256 * runlevel, "~");
mf_proctitle_format ("init [%c]", newlevel);
+ prevlevel = runlevel ? runlevel : 'N';
runlevel = newlevel;
trans = 1;
wait = 0;
@@ -337,13 +570,14 @@ inittrans ()
trans = 1;
if (trans)
{
+ envsetup ();
if (wait == 0)
{
- progman_sysvinit_enable (enablecomp, &wait);
+ sysvinit_runlevel_setup (&wait);
if (wait)
return 1;
}
- progman_sysvinit_enable (enablecomp, NULL);
+ sysvinit_runlevel_setup (NULL);
wait = 0;
}
return trans;

Return to:

Send suggestions and report system problems to the System administrator.