aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-02-15 22:24:04 +0200
committerSergey Poznyakoff <gray@gnu.org>2016-02-15 22:24:04 +0200
commit27366c475aa4955f296f169cf9acd33e36b9d7b3 (patch)
tree3e09f2ae80c423ccd2a0a2929852be3560cb1d2b /src
parent0a5eb4f65a20d37f2051dce8816485dd219fb735 (diff)
downloadpies-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.c40
-rw-r--r--src/pies.h2
-rw-r--r--src/progman.c6
-rw-r--r--src/sysvinit.c72
4 files changed, 95 insertions, 25 deletions
diff --git a/src/pies.c b/src/pies.c
index 3734b47..653a865 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -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);
diff --git a/src/pies.h b/src/pies.h
index bcce32a..4a6160f 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -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;
+ }
+}

Return to:

Send suggestions and report system problems to the System administrator.