diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2016-02-15 22:24:04 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-02-15 22:24:04 +0200 |
commit | 27366c475aa4955f296f169cf9acd33e36b9d7b3 (patch) | |
tree | 3e09f2ae80c423ccd2a0a2929852be3560cb1d2b /src | |
parent | 0a5eb4f65a20d37f2051dce8816485dd219fb735 (diff) | |
download | pies-27366c475aa4955f296f169cf9acd33e36b9d7b3.tar.gz pies-27366c475aa4955f296f169cf9acd33e36b9d7b3.tar.bz2 |
Implement emergency shell.
* src/pies.c (main): Move init-specific command line
handling to sysvinit_parse_argv.
* src/pies.h (dfl_level): Remove extern.
(sysvinit_parse_argv): New proto.
* src/sysvinit.c (sysvinit_parse_argv): New function.
(sysvinit_begin): Start emergency shell, if requested.
Diffstat (limited to 'src')
-rw-r--r-- | src/pies.c | 40 | ||||
-rw-r--r-- | src/pies.h | 2 | ||||
-rw-r--r-- | src/progman.c | 6 | ||||
-rw-r--r-- | src/sysvinit.c | 72 |
4 files changed, 95 insertions, 25 deletions
@@ -1924,13 +1924,12 @@ set_state_file_names (const char *base) size_t pies_master_argc; char **pies_master_argv; int main (int argc, char **argv) { - int index; pid_t pid; extern char **environ; struct grecs_list_entry *ep; int diag_flags; set_program_name (argv[0]); @@ -1998,24 +1997,30 @@ main (int argc, char **argv) config_file_add_type (CONF_PIES, "/etc/pies.init"); } #else config_file_add_type (CONF_INITTAB, "/etc/inittab"); config_file_add_type (CONF_PIES, "/etc/pies.init"); #endif - for (index = 1; index < argc; index++) + sysvinit_parse_argv (argc, argv); + } + else + { + int index; + + parse_options (argc, argv, &index); + argc -= index; + argv += index; + + if (argc && !(command == COM_RESTART_COMPONENT + || command == COM_TRACE_DEPEND + || command == COM_TRACE_PREREQ)) { - if (!strcmp (argv[index], "single") || !strcmp (argv[index], "-s")) - dfl_level = 'S'; - else if (strchr("0123456789sS", argv[index][0]) && !argv[index][1]) - { - dfl_level = toupper (argv[index][0]); - } + logmsg (LOG_ERR, "extra command line arguments"); + exit (EX_USAGE); } } - else - parse_options (argc, argv, &index); if (!instance) { instance = strrchr (program_name, '/'); if (!instance) instance = (char*) program_name; @@ -2056,21 +2061,12 @@ main (int argc, char **argv) if (lint_mode) exit (0); /* Re-setup logging: it might have been reset in the config file */ diag_setup (log_to_stderr_only ? DIAG_TO_STDERR : 0); - if (argc != index - && !(command == COM_RESTART_COMPONENT - || command == COM_TRACE_DEPEND - || command == COM_TRACE_PREREQ)) - { - logmsg (LOG_ERR, "extra command line arguments"); - exit (EX_CONFIG); - } - if (!control.url) { char const *str = default_control_url[init_process]; if (pies_url_create (&control.url, str)) { logmsg (LOG_CRIT, _("%s: cannot create control URL: %s"), @@ -2083,13 +2079,13 @@ main (int argc, char **argv) switch (command) { case COM_RESTART_COMPONENT: pies_priv_setup (&pies_privs); if (pies_umask) umask (pies_umask); - exit (request_restart_components (argc - index, argv + index)); + exit (request_restart_components (argc, argv)); case COM_RELOAD: exit (request_reload ()); case COM_STATUS: exit (request_status ()); @@ -2099,17 +2095,17 @@ main (int argc, char **argv) case COM_DUMP_DEPMAP: components_dump_depmap (); exit (0); case COM_TRACE_DEPEND: - components_trace (argv + index, depmap_row); + components_trace (argv, depmap_row); exit (0); case COM_TRACE_PREREQ: - components_trace (argv + index, depmap_col); + components_trace (argv, depmap_col); exit (0); default: pies_priv_setup (&pies_privs); if (pies_umask) umask (pies_umask); @@ -288,13 +288,12 @@ extern char **mailer_argv; extern size_t default_max_rate; extern char *qotdfile; extern int init_process; extern char *console_device; extern int initdefault; -extern int dfl_level; extern size_t pies_master_argc; extern char **pies_master_argv; extern char *default_control_url[2]; enum config_syntax_type @@ -520,12 +519,13 @@ int sysvinit_sigtrans (int sig, int *pact); void sysvinit_runlevel_setup (int mask); void sysvinit_sysdep_begin (void); void sysvinit_power (void); void sysvinit_report (struct json_value *obj); int sysvinit_set_runlevel (int newlevel); +void sysvinit_parse_argv (int argc, char **argv); extern char *sysvinit_environ_hint[]; extern char *init_fifo; #ifndef INIT_FIFO # define INIT_FIFO "/dev/initctl" diff --git a/src/progman.c b/src/progman.c index 8a5187c..1be7d27 100644 --- a/src/progman.c +++ b/src/progman.c @@ -1202,13 +1202,13 @@ prog_start (struct prog *prog) FD_SET (2, &fdset); if (prog->v.p.comp->mode == pies_comp_pass_fd) FD_SET (prog->v.p.socket, &fdset); close_fds (&fdset); prog_execute (prog); - + case -1: logmsg (LOG_CRIT, _("cannot run `%s': fork failed: %s"), prog_tag (prog), strerror (errno)); break; @@ -1543,12 +1543,15 @@ progman_wake_sleeping (int onalrm) debug (1, (_("checking for components to start"))); for (prog = proghead; prog; prog = prog->next) { if (IS_ACTIVE_COMPONENT (prog) && prog->v.p.wait) { + /* The following works on the assumption that prog->v.p.wait is + set when enabling the component and gets cleared right after + it has finished. */ if (prog->v.p.status != status_running) prog_start (prog); return; } } @@ -2408,7 +2411,8 @@ progman_stop_component (struct prog **progptr) void progman_stop_tag (const char *name) { struct prog *prog = progman_locate (name); progman_stop_component (&prog); } + /* EOF */ diff --git a/src/sysvinit.c b/src/sysvinit.c index 2d0671c..0370fcc 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -13,12 +13,13 @@ You should have received a copy of the GNU General Public License along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ #include "pies.h" #include "prog.h" +#include <sys/ioctl.h> #include <termios.h> enum boot_state { sysinit, boot, @@ -56,18 +57,19 @@ static int boot_trans_tab[max_boot_state][sizeof(valid_runlevels)-1] = { enum boot_state boot_state; int runlevel = 0; 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); if (fd >= 0) { fcntl (fd, F_SETFL, mode); @@ -643,12 +645,62 @@ unintr_sleep (unsigned n) tv.tv_usec = 0; while (select (0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR) ; } +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. */ static void * sysvinit_malloc (size_t size) @@ -695,12 +747,14 @@ sysvinit_begin () console_stty (); setsid (); envsetup (); 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) \ (IS_COMPONENT (prog) \ && prog->v.p.status == status_running \ && prog->v.p.comp->flags & CF_DISABLED) \ @@ -1137,6 +1191,22 @@ sysvinit_report (struct json_value *obj) json_object_set_string (obj, "bootstate", "%s", boot_state_name[boot_state]); if (initdefault) 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; + } +} |