aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-01-06 17:04:28 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2013-01-06 17:04:28 +0200
commit1bfa33ac7c167cd863b88a5cac7690d511851e6e (patch)
treea892e281cba3ea127af5faf5da81ff2cc0c3aae9 /src
parent4f7c28158308563dcad912d87a0031d095d4690a (diff)
downloadpies-1bfa33ac7c167cd863b88a5cac7690d511851e6e.tar.gz
pies-1bfa33ac7c167cd863b88a5cac7690d511851e6e.tar.bz2
Fix runlevel transition algorithm, implement SysV-style fifo interface.
* src/prog.h: New file. * src/Makefile.am: Add new file. * src/cmdline.opt: New option --telinit (-T). * src/diag.c (vlogmsg): In sysvin it mode, write directly to the console. Close it when finished. * src/pies.c (_cb_initdefault, _cb_runlevels): Use is_valid_runlevel to check if the specified runlevels are ok. (main): In sysvinit mode, reset action to ACTION_CONT. * src/pies.h (progman_filter): New proto. (progman_accept,register_socket): Change signature. (deregister_socket): New proto. (register_program_socket): New proto. * src/progman.c: Move constant and adatatype definitions to prog.h (prog_stop): Remove static qualifier. (console_open): Likewise. (progman_accept): Use new socket API. (progman_stop): Correctly handle timeouts. (progman_foreach): New function. * src/socket.c: Register all sockets along with their handlers in a doubly-linked list. (sockinst): New struct. (register_socket,deregister_socket): New functions. (register_program_socket): New function. (pies_pause): Traverse the list to find which fd has changed. Use its registered handler to handle the event. * src/sysvinit.c: Include prog.h (is_valid_runlevel): New function. (sysvinit_fifo_handler,check_fifo): New static functions. (inittrans): Fix transition algorithm. (telinit): New function.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/cmdline.opt9
-rw-r--r--src/diag.c31
-rw-r--r--src/pies.c16
-rw-r--r--src/pies.h36
-rw-r--r--src/prog.h85
-rw-r--r--src/progman.c125
-rw-r--r--src/socket.c106
-rw-r--r--src/sysvinit.c192
9 files changed, 488 insertions, 115 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3752eae..9e9bf80 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,7 +40,8 @@ noinst_HEADERS = \
cmdline.h\
meta1gram.h\
meta1lex.h\
- pies.h
+ pies.h\
+ prog.h
meta1lex.c: meta1gram.h
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 31fcf20..76fc4da 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -110,7 +110,14 @@ BEGIN
log_to_stderr_only = 1;
lint_mode = 1;
END
-
+
+OPTION(telinit,T,RUNLEVEL,
+ [<emulate telinit command>])
+BEGIN
+ log_to_stderr_only = 1;
+ exit (telinit (optarg));
+END
+
GROUP(Preprocessor)
OPTION(define,D,[<NAME[=VALUE]>],
diff --git a/src/diag.c b/src/diag.c
index fe057d0..bb64ab9 100644
--- a/src/diag.c
+++ b/src/diag.c
@@ -42,17 +42,42 @@ syslog_printer (int prio, const char *fmt, va_list ap)
#endif
}
+static FILE *
+stderr_open ()
+{
+ if (!init_process)
+ return stderr;
+ else
+ {
+ int fd = console_open (O_WRONLY|O_NOCTTY|O_NDELAY);
+ if (fd == -1)
+ return NULL;
+ return fdopen (fd, "w");
+ }
+}
+
+static void
+stderr_close (FILE *fp)
+{
+ if (init_process)
+ fclose (fp);
+}
+
void
vlogmsg (int prio, const char *fmt, va_list ap)
{
if (DIAG_OUTPUT (DIAG_TO_STDERR))
{
va_list aq;
- fprintf (stderr, "%s: ", program_name);
+ FILE *fp = stderr_open ();
+ if (!fp)
+ return;
+ fprintf (fp, "%s: ", program_name);
va_copy (aq, ap);
- vfprintf (stderr, fmt, aq);
+ vfprintf (fp, fmt, aq);
va_end (aq);
- fprintf (stderr, "\n");
+ fprintf (fp, "\n");
+ stderr_close (fp);
}
if (DIAG_OUTPUT (DIAG_TO_SYSLOG))
diff --git a/src/pies.c b/src/pies.c
index a2dc5e0..41ca486 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -959,8 +959,6 @@ _cb_flags (enum grecs_callback_command cmd,
return 0;
}
-static const char valid_runlevels[] = "0123456789Ss";
-
static int
_cb_initdefault (enum grecs_callback_command cmd,
grecs_locus_t *locus,
@@ -975,7 +973,7 @@ _cb_initdefault (enum grecs_callback_command cmd,
grecs_error (locus, 0, _("argument must be a single character"));
return 1;
}
- if (!strchr (valid_runlevels, value->v.string[0]))
+ if (!is_valid_runlevel (value->v.string[0]))
{
grecs_error (locus, 0, _("not a valid runlevel"));
return 1;
@@ -995,7 +993,7 @@ _cb_runlevels (enum grecs_callback_command cmd,
return 1;
for (p = value->v.string; *p; p++)
{
- if (!strchr (valid_runlevels, *p))
+ if (!is_valid_runlevel (*p))
{
grecs_error (locus, 0, _("not a valid runlevel: %c"));
return 1;
@@ -2332,7 +2330,7 @@ main (int argc, char **argv)
(unsigned long) pid);
exit (EX_USAGE);
}
-
+
logmsg (LOG_INFO, _("%s %s starting"), proginfo.package, proginfo.version);
if (!foreground)
@@ -2381,6 +2379,14 @@ main (int argc, char **argv)
progman_dump_stats (statfile);
action = ACTION_CONT;
break;
+
+ case ACTION_STOP:
+ case ACTION_RESTART:
+ if (init_process)
+ {
+ debug (1, ("ignoring stop/restart"));
+ action = ACTION_CONT;
+ }
}
if (action == ACTION_CONT)
{
diff --git a/src/pies.h b/src/pies.h
index e7ad1c6..2203d87 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -285,11 +285,13 @@ void progman_start (void);
void progman_wake_sleeping (int);
void progman_stop (void);
void progman_cleanup (int expect_term);
+void progman_filter (int (*filter) (struct component *, void *data),
+ void *data);
void progman_stop_component (const char *name);
void progman_dump_stats (const char *filename);
void progman_dump_prereq (void);
void progman_dump_depmap (void);
-int progman_accept (int socket);
+int progman_accept (int socket, void *data);
int progman_build_depmap (void);
void progman_create_sockets (void);
struct component *progman_lookup_component (const char *tag);
@@ -362,7 +364,10 @@ void pies_url_destroy (struct pies_url **purl);
const char * pies_url_get_arg (struct pies_url *url, const char *argname);
void pies_pause (void);
-int register_socket (int socktype, int fd);
+void *register_socket (int fd, int (*handler) (int, void *), void *data);
+void deregister_socket (int fd);
+
+int register_program_socket (int socktype, int fd, void *data);
int pass_fd (const char *socket, int fd, unsigned time_out);
int create_socket (struct pies_url *url, int socket_type,
const char *user, mode_t umask);
@@ -456,6 +461,33 @@ struct inetd_builtin *inetd_builtin_lookup (const char *service, int socktype);
void sysvinit_begin (void);
int inittrans (void);
int is_comp_wait (struct component *comp);
+int is_valid_runlevel (int c);
+
+#ifndef INIT_FIFO
+# define INIT_FIFO "/dev/initctl"
+#endif
+
+#define INIT_MAGIC 0x03091969
+#define INIT_CMD_START 0
+#define INIT_CMD_RUNLVL 1
+#define INIT_CMD_POWERFAIL 2
+#define INIT_CMD_POWERFAILNOW 3
+#define INIT_CMD_POWEROK 4
+#define INIT_CMD_BSD 5
+#define INIT_CMD_SETENV 6
+#define INIT_CMD_UNSETENV 7
+
+#define INIT_CMD_CHANGECONS 12345
+
+struct sysvinit_request {
+ int magic; /* Magic number */
+ int cmd; /* What kind of request */
+ int runlevel; /* Runlevel to change to */
+ int sleeptime; /* Time between TERM and KILL */
+ char pad[368];
+};
+
+
/* utmp.c */
#define SYSV_ACCT_BOOT 0
diff --git a/src/prog.h b/src/prog.h
new file mode 100644
index 0000000..2fd4c47
--- /dev/null
+++ b/src/prog.h
@@ -0,0 +1,85 @@
+/* This file is part of GNU Pies.
+ Copyright (C) 2008, 2009, 2010, 2011 Sergey Poznyakoff
+
+ GNU Pies is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Pies is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+enum prog_type
+ {
+ TYPE_COMPONENT,
+ TYPE_REDIRECTOR,
+ TYPE_COMMAND
+ };
+
+enum prog_status
+ {
+ status_enabled, /* Component enabled. prog->pid!=0 shows if it is
+ actually running */
+ status_disabled, /* Component is disabled. */
+ status_listener, /* Component is an inetd listener */
+ status_sleeping, /* Component is sleeping. An attempt to start it will
+ be made at prog->v.p.timestamp + SLEEPTIME */
+ status_stopping, /* Component is being stopped */
+ status_finished, /* A "once" component has finished */
+ };
+
+struct conn_class
+{
+ const char *tag;
+ union pies_sockaddr_storage sa_storage;
+ size_t sa_len;
+ size_t count;
+};
+
+struct prog
+{
+ struct prog *next, *prev;
+ enum prog_type type;
+ pid_t pid; /* PID */
+ char *tag; /* Entry tag (for diagnostics purposes) */
+ char **prereq;
+ int facility;
+ union
+ {
+ struct
+ {
+ struct component *comp;
+ size_t idx; /* Numeric identifier */
+ int socket;
+ struct prog *redir[2]; /* Pointers to redirectors */
+ time_t timestamp; /* Time of last startup */
+ size_t failcount; /* Number of failed starts since timestamp */
+ enum prog_status status; /* Current component status */
+ char *runlevels;
+ /* If status == status_listener: */
+ size_t num_instances; /* Number of running instances */
+ /* If comp->type == pies_comp_inetd && status == status_enabled */
+ struct prog *listener;
+ union pies_sockaddr_storage sa_storage;
+ size_t sa_len;
+ struct conn_class *cclass;
+ } p;
+
+ struct
+ {
+ struct prog *master;
+ } r;
+
+ struct
+ {
+ char *command;
+ } c;
+ } v;
+};
+
+void progman_foreach (int (*filter) (struct prog *, void *data), void *data);
diff --git a/src/progman.c b/src/progman.c
index 97216b8..2b375fe 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -16,74 +16,7 @@
#include "pies.h"
#include <termios.h>
-
-enum prog_type
- {
- TYPE_COMPONENT,
- TYPE_REDIRECTOR,
- TYPE_COMMAND
- };
-
-enum prog_status
- {
- status_enabled, /* Component enabled. prog->pid!=0 shows if it is
- actually running */
- status_disabled, /* Component is disabled. */
- status_listener, /* Component is an inetd listener */
- status_sleeping, /* Component is sleeping. An attempt to start it will
- be made at prog->v.p.timestamp + SLEEPTIME */
- status_stopping, /* Component is being stopped */
- status_finished, /* A "once" component has finished */
- };
-
-struct conn_class
-{
- const char *tag;
- union pies_sockaddr_storage sa_storage;
- size_t sa_len;
- size_t count;
-};
-
-struct prog
-{
- struct prog *next, *prev;
- enum prog_type type;
- pid_t pid; /* PID */
- char *tag; /* Entry tag (for diagnostics purposes) */
- char **prereq;
- int facility;
- union
- {
- struct
- {
- struct component *comp;
- size_t idx; /* Numeric identifier */
- int socket;
- struct prog *redir[2]; /* Pointers to redirectors */
- time_t timestamp; /* Time of last startup */
- size_t failcount; /* Number of failed starts since timestamp */
- enum prog_status status; /* Current component status */
- char *runlevels;
- /* If status == status_listener: */
- size_t num_instances; /* Number of running instances */
- /* If comp->type == pies_comp_inetd && status == status_enabled */
- struct prog *listener;
- union pies_sockaddr_storage sa_storage;
- size_t sa_len;
- struct conn_class *cclass;
- } p;
-
- struct
- {
- struct prog *master;
- } r;
-
- struct
- {
- char *command;
- } c;
- } v;
-};
+#include "prog.h"
#define IS_COMPONENT(p) ((p)->type == TYPE_COMPONENT)
@@ -209,7 +142,7 @@ prog_lookup_by_idx (unsigned idx)
return prog;
}
-static void prog_stop (struct prog *prog, int sig);
+void prog_stop (struct prog *prog, int sig);
static int prog_start_prerequisites (struct prog *prog);
void
@@ -1139,7 +1072,7 @@ progman_run_comp (struct component *comp, int fd,
prog_execute (prog);
}
-static int
+int
console_open (int mode)
{
int i, fd;
@@ -1565,15 +1498,9 @@ _prog_wait (struct prog *p)
}
int
-progman_accept (int socket)
+progman_accept (int socket, void *data)
{
- struct prog *p = prog_lookup_by_socket (socket);
- if (!p)
- {
- logmsg (LOG_EMERG,
- _("INTERNAL ERROR: no matching prog for fd %d"), socket);
- return 1;
- }
+ struct prog *p = data;
if (p->v.p.comp->socket_type == SOCK_STREAM
&& !(p->v.p.comp->flags & CF_WAIT))
@@ -1756,7 +1683,7 @@ progman_create_sockets ()
comp->privs.user, comp->umask);
if (fd == -1)
prog->v.p.status = status_disabled;
- else if (register_socket (comp->socket_type, fd))
+ else if (register_program_socket (comp->socket_type, fd, prog))
{
close (fd);
prog->v.p.status = status_disabled;
@@ -1989,7 +1916,7 @@ prog_stop_dependents (struct prog *prog)
free (pos);
}
-static void
+void
prog_stop (struct prog *prog, int sig)
{
if (prog->pid == 0)
@@ -2023,20 +1950,31 @@ prog_stop_all (int sig)
prog_stop (prog, sig);
}
-void
-progman_stop ()
+static int
+progman_wait ()
{
- unsigned long i;
+ time_t start = time (NULL);
- prog_stop_all (SIGTERM);
- for (i = 0; i < shutdown_timeout; i++)
+ do
{
progman_cleanup (1);
if (progman_running_count () == 0)
- return;
+ return 0;
sleep (1);
}
- prog_stop_all (SIGKILL);
+ while (time (NULL) - start < shutdown_timeout);
+ return 1;
+}
+
+void
+progman_stop ()
+{
+ prog_stop_all (SIGTERM);
+ if (progman_wait ())
+ {
+ prog_stop_all (SIGKILL);
+ progman_wait ();
+ }
}
static void
@@ -2534,14 +2472,23 @@ progman_cleanup (int expect_term)
}
void
+progman_foreach (int (*filter) (struct prog *, void *data), void *data)
+{
+ struct prog *prog;
+ for (prog = proghead; prog; prog = prog->next)
+ if (IS_COMPONENT (prog) && filter (prog, data))
+ break;
+}
+
+void
progman_stop_component (const char *name)
{
struct prog *prog;
- logmsg (LOG_INFO, _("stopping component `%s'"), name);
for (prog = proghead; prog; prog = prog->next)
if (IS_COMPONENT (prog) && strcmp (prog->tag, name) == 0)
{
+ logmsg (LOG_INFO, _("stopping component `%s'"), prog->tag);
switch (prog->v.p.status)
{
case status_enabled:
@@ -2561,7 +2508,7 @@ progman_stop_component (const char *name)
default:
logmsg (LOG_INFO,
_("stopping component `%s': component not started"),
- name);
+ prog->tag);
}
}
}
diff --git a/src/socket.c b/src/socket.c
index e32701f..fdce7d1 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -395,17 +395,101 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime)
fd_set listenset;
int fd_max;
+struct sockinst
+{
+ struct sockinst *prev, *next;
+ int fd;
+ int (*handler) (int, void *);
+ void *data;
+};
+
+struct sockinst *si_head, *si_tail;
+
+static struct sockinst *
+find_socket (int fd)
+{
+ struct sockinst *sp;
+
+ for (sp = si_head; sp; sp = sp->next)
+ if (sp->fd == fd)
+ break;
+ return sp;
+}
+
+struct sockinst *
+find_socket_handler (int (*handler) (int, void *))
+{
+ struct sockinst *sp;
+
+ for (sp = si_head; sp; sp = sp->next)
+ if (sp->handler == handler)
+ break;
+ return sp;
+}
+
+static int
+calc_fd_max ()
+{
+ struct sockinst *sp;
+
+ fd_max = -1;
+ for (sp = si_head; sp; sp = sp->next)
+ if (sp->fd > fd_max)
+ fd_max = sp->fd;
+}
+
+void *
+register_socket (int fd, int (*handler) (int, void *), void *data)
+{
+ struct sockinst *sip = xmalloc (sizeof *sip);
+ sip->fd = fd;
+ sip->handler = handler;
+ sip->data = data;
+ sip->next = NULL;
+ sip->prev = si_tail;
+ if (si_tail)
+ si_tail->next = sip;
+ else
+ si_head = sip;
+ si_tail = sip;
+ FD_SET (fd, &listenset);
+ if (fd_max == -1)
+ calc_fd_max ();
+ else if (fd > fd_max)
+ fd_max = fd;
+ return sip;
+}
+
+void
+deregister_socket (int fd)
+{
+ struct sockinst *sp = find_socket (fd);
+
+ if (!sp)
+ return;
+ if (sp->prev)
+ sp->prev->next = sp->next;
+ else
+ si_head = sp->next;
+ if (sp->next)
+ sp->next->prev = sp->prev;
+ else
+ si_tail = sp->prev;
+ free (sp);
+ FD_CLR (fd, &listenset);
+ fd_max = -1;
+}
+
+
int
-register_socket (int socktype, int fd)
+register_program_socket (int socktype, int fd, void *data)
{
if (socktype == SOCK_STREAM && listen (fd, 8) == -1)
{
logmsg (LOG_ERR, "listen: %s", strerror (errno));
return 1;
}
- FD_SET (fd, &listenset);
- if (fd > fd_max)
- fd_max = fd;
+ register_socket (fd, progman_accept, data);
return 0;
}
@@ -430,18 +514,20 @@ enable_socket (int fd)
void
pies_pause ()
{
+ if (fd_max == -1)
+ calc_fd_max ();
+
while (1)
{
fd_set rdset = listenset;
int rc = select (fd_max + 1, &rdset, NULL, NULL, NULL);
if (rc > 0)
{
- int i;
- for (i = 0; i <= fd_max; i++)
- {
- if (FD_ISSET (i, &rdset))
- progman_accept (i);
- }
+ struct sockinst *sp;
+
+ for (sp = si_head; sp; sp = sp->next)
+ if (FD_ISSET (sp->fd, &rdset))
+ sp->handler (sp->fd, sp->data);
break;
}
else if (rc < 0)
diff --git a/src/sysvinit.c b/src/sysvinit.c
index ef765a1..940125f 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -15,6 +15,7 @@
along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
#include "pies.h"
+#include "prog.h"
enum boot_state
{
@@ -124,6 +125,146 @@ enablecomp (struct component *comp, int finished, void *data)
return rc;
}
+static const char valid_runlevel_arg[] = "0123456789SsQqAaBbCcUu";
+
+int
+is_valid_runlevel (int c)
+{
+ return !!strchr (valid_runlevel_arg, c);
+}
+
+static void create_fifo (void);
+
+static int
+sysvinit_stop_filter (struct prog *prog, void *data)
+{
+ switch (prog->v.p.status)
+ {
+ case status_enabled:
+ case status_listener:
+ prog_stop (prog, SIGTERM);
+ prog->v.p.status = status_disabled; /* See FIXME, progman.c:2364 */
+ break;
+ }
+ return 0;
+}
+
+static int
+sysvinit_fifo_handler (int fd, void *data)
+{
+ static size_t size;
+ union
+ {
+ struct sysvinit_request req;
+ char data[sizeof (struct sysvinit_request)];
+ } buf;
+ int rc;
+
+ rc = read (fd, buf.data + size, sizeof (struct sysvinit_request) - size);
+ if (rc == -1)
+ {
+ logmsg (LOG_ERR, _("error reading from %s: %s"), INIT_FIFO,
+ strerror (errno));
+ size = 0;
+ return 0;
+ }
+ if (rc == 0)
+ {
+ logmsg (LOG_ERR, _("end of file on %s: reopening"), INIT_FIFO);
+ size = 0;
+ close (fd);
+ deregister_socket (fd);
+ create_fifo ();
+ return 0;
+ }
+
+ size += rc;
+
+ if (size == sizeof (struct sysvinit_request))
+ {
+ if (buf.req.magic != INIT_MAGIC)
+ logmsg (LOG_ERR, _("got invalid initreq"));
+ else
+ {
+ debug (1, ("INITREQ: cmd=%d, runlevel=%d, sleeptime=%d",
+ buf.req.cmd, buf.req.runlevel, buf.req.sleeptime));
+ switch (buf.req.cmd)
+ {
+ case INIT_CMD_RUNLVL:
+ buf.req.runlevel = toupper (buf.req.runlevel);
+ if (buf.req.runlevel != runlevel)
+ {
+ progman_stop ();
+ dfl_level = buf.req.runlevel;
+ inittrans ();
+ }
+ break;
+
+ /* FIXME: react on other commands */
+ }
+ }
+ size = 0;
+ }
+ return 0;
+}
+
+static void
+create_fifo ()
+{
+ static int fd = -1;
+ struct stat st, fst;
+
+ if (stat (INIT_FIFO, &st) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ logmsg (LOG_ERR, "cannot stat fifo %s: %s", INIT_FIFO,
+ strerror (errno));
+ return;
+ }
+ else if (mkfifo (INIT_FIFO, 0600))
+ {
+ logmsg (LOG_ERR, "cannot create fifo %s: %s", INIT_FIFO,
+ strerror (errno));
+ return;
+ }
+ }
+ else
+ {
+ if (!S_ISFIFO (st.st_mode))
+ {
+ logmsg (LOG_ERR, "not a fifo: %s", INIT_FIFO);
+ return;
+ }
+
+ chmod (INIT_FIFO, 0600);
+ }
+
+ if (fd != -1)
+ {
+ fstat (fd, &fst);
+ if (fst.st_dev != st.st_dev || fst.st_ino != st.st_ino)
+ {
+ deregister_socket (fd);
+ close (fd);
+ }
+ debug (1, ("reopening %s", INIT_FIFO));
+ }
+
+ /* Opening the socket in read-write mode ensures we won't get EOF
+ on it when the caller party closes connection (at least on Linux).
+ Nevertheless, the svinit_fifo_handler is prepared for that eventuality,
+ too. */
+ fd = open (INIT_FIFO, O_RDWR|O_NONBLOCK);
+ if (fd == -1)
+ {
+ logmsg (LOG_ERR, "cannot open %s: %s", INIT_FIFO,
+ strerror (errno));
+ return;
+ }
+ register_socket (fd, sysvinit_fifo_handler, NULL);
+}
+
void
sysvinit_begin ()
{
@@ -140,9 +281,12 @@ inittrans ()
static int wait = 0;
if (progman_running_p ())
- /* Noting to do if there are processes left in the previous runlevel */
- return 0;
-
+ {
+ debug (1, ("%s exiting: some components still running",__FUNCTION__));
+ /* 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);
else
@@ -160,6 +304,7 @@ inittrans ()
boot_state_name[newstate]));
boot_state = newstate;
trans = 1;
+ wait = 0;
}
switch (boot_state)
@@ -170,12 +315,13 @@ inittrans ()
sysvinit_acct (SYSV_ACCT_BOOT, "reboot", "~~", 0, "~");
break;
case single0:
- case single1:
newlevel = 'S';
break;
+ case single1:
case normal:
/* boot -> normal */
newlevel = dfl_level ? dfl_level : initdefault;
+ create_fifo ();
}
if (newlevel && newlevel != runlevel)
{
@@ -198,6 +344,7 @@ inittrans ()
return 1;
}
progman_sysvinit_enable (enablecomp, NULL);
+ wait = 0;
}
return trans;
}
@@ -219,3 +366,40 @@ is_comp_wait (struct component *comp)
return 1;
}
+int
+telinit (const char *arg)
+{
+ int fd;
+ struct sysvinit_request req;
+
+ if (arg[1] || !is_valid_runlevel (*arg))
+ {
+ logmsg (LOG_CRIT, "invalid argument");
+ exit (EX_USAGE);
+ }
+ memset (&req, 0, sizeof (req));
+ req.magic = INIT_MAGIC;
+ req.cmd = INIT_CMD_RUNLVL;
+ req.runlevel = *arg;
+#if 0
+ req.sleeptime = sltime;
+#endif
+
+ signal (SIGALRM, SIG_DFL);
+ alarm (5);
+ fd = open (INIT_FIFO, O_WRONLY);
+ if (fd < 0)
+ {
+ logmsg (LOG_ERR, _("can't open %s: %s"), INIT_FIFO, strerror (errno));
+ exit (EX_UNAVAILABLE);
+ }
+ if (write (fd, &req, sizeof (req)) != sizeof (req))
+ {
+ logmsg (LOG_ERR, _("error writing to %s: %s"),
+ INIT_FIFO, strerror (errno));
+ exit (EX_UNAVAILABLE);
+ }
+ alarm (0);
+ close (fd);
+ exit (0);
+}

Return to:

Send suggestions and report system problems to the System administrator.