diff options
Diffstat (limited to 'src/sysvinit.c')
-rw-r--r-- | src/sysvinit.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/src/sysvinit.c b/src/sysvinit.c index 2d0671c..0370fcc 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -16,6 +16,7 @@ #include "pies.h" #include "prog.h" +#include <sys/ioctl.h> #include <termios.h> enum boot_state @@ -59,12 +60,13 @@ int prevlevel = 'N'; int initdefault; /* Default runlevel */ int dfl_level; +int emergency_shell; int console_open (int mode) { int i, fd; - + for (i = 0; i < 5; i++) { fd = open (console_device, mode | O_NONBLOCK); @@ -646,6 +648,56 @@ unintr_sleep (unsigned n) ; } +static void +start_shell (const char *shell) +{ + pid_t pid, rc; + int st; + struct sigaction act, old; + + act.sa_flags = SA_RESTART; + act.sa_handler = SIG_DFL; + sigemptyset (&act.sa_mask); + sigaction (SIGCHLD, &act, &old); + + pid = fork (); + if (pid == -1) + { + logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s", + shell, strerror (errno)); + exit (1); + } + + if (pid == 0) + { + int fd; + + signal_setup (SIG_DFL); + setsid (); + + fd = console_open (O_RDWR|O_NOCTTY); + if (fd < 0) + { + logmsg (LOG_CRIT, "open(%s): %s", + console_device, strerror (errno)); + exit (1); + } + ioctl (fd, TIOCSCTTY, 1); + dup (fd); + dup (fd); + + execl (shell, shell, NULL); + _exit (127); + } + + while ((rc = wait (&st)) != pid) + if (rc == (pid_t) -1 && errno == ECHILD) + break; + + logmsg (LOG_CRIT, "shell finished"); + sigaction (SIGCHLD, &old, NULL); +} + /* Memory allocation functions for INIT. They may not fail, therefore they just retry allocation until it eventually succeeds. */ @@ -698,6 +750,8 @@ sysvinit_begin () sysvinit_runlevel_setup (PIES_COMP_DEFAULT); add_extra_sigv (sigv, ARRAY_SIZE (sigv)); sysvinit_sysdep_begin (); + if (emergency_shell) + start_shell ("/sbin/sulogin"); } #define IS_RUNNING_DISABLED_PROG(prog) \ @@ -1140,3 +1194,19 @@ sysvinit_report (struct json_value *obj) json_object_set_string (obj, "initdefault", "%c", initdefault); } + +void +sysvinit_parse_argv (int argc, char **argv) +{ + while (--argc) + { + int c; + char *arg = *++argv; + if (!strcmp (arg, "single") || !strcmp (arg, "-s")) + dfl_level = 'S'; + else if (!strcmp (arg, "-b") || !strcmp (arg, "emergency")) + emergency_shell = 1; + else if (!arg[1] && strchr (valid_runlevels, (c = toupper (arg[0])))) + dfl_level = c; + } +} |