aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
@@ -37,13 +37,14 @@ pies_SOURCES = \
noinst_HEADERS = \
acl.h\
cmdline.h\
meta1gram.h\
meta1lex.h\
- pies.h
+ pies.h\
+ prog.h
meta1lex.c: meta1gram.h
BUILT_SOURCES=cmdline.h
incdir=$(pkgdatadir)/$(VERSION)/include
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 31fcf20..76fc4da 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -107,13 +107,20 @@ END
OPTION(lint,t,,
[<parse configuration file and exit>])
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]>],
[<define a preprocessor symbol NAME as having VALUE or empty>])
BEGIN
add_pp_option ("-D", optarg);
diff --git a/src/diag.c b/src/diag.c
index fe057d0..bb64ab9 100644
--- a/src/diag.c
+++ b/src/diag.c
@@ -39,23 +39,48 @@ syslog_printer (int prio, const char *fmt, va_list ap)
char buf[128];
vsnprintf (buf, sizeof buf, fmt, ap);
syslog (prio, "%s", buf);
#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))
syslog_printer (prio, fmt, ap);
}
diff --git a/src/pies.c b/src/pies.c
index a2dc5e0..41ca486 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -956,14 +956,12 @@ _cb_flags (enum grecs_callback_command cmd,
grecs_error (locus, 0, _("too many arguments"));
return 1;
}
return 0;
}
-static const char valid_runlevels[] = "0123456789Ss";
-
static int
_cb_initdefault (enum grecs_callback_command cmd,
grecs_locus_t *locus,
void *varptr, grecs_value_t *value, void *cb_data)
{
int *val = varptr;
@@ -972,13 +970,13 @@ _cb_initdefault (enum grecs_callback_command cmd,
return 1;
if (strlen (value->v.string) != 1)
{
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;
}
*val = toupper (value->v.string[0]);
return 0;
@@ -992,13 +990,13 @@ _cb_runlevels (enum grecs_callback_command cmd,
char **sptr = varptr, *p;
if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
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;
}
}
*sptr = grecs_strdup(value->v.string);
@@ -2329,13 +2327,13 @@ main (int argc, char **argv)
case pies_status_running:
logmsg (LOG_ERR, _("another pies instance already running (pid %lu)"),
(unsigned long) pid);
exit (EX_USAGE);
}
-
+
logmsg (LOG_INFO, _("%s %s starting"), proginfo.package, proginfo.version);
if (!foreground)
{
check_pidfile (pidfile);
if (daemon (0, 0) == -1)
@@ -2378,12 +2376,20 @@ main (int argc, char **argv)
break;
case ACTION_DUMPSTATS:
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)
{
if (children_cleanup)
{
children_cleanup = 0;
diff --git a/src/pies.h b/src/pies.h
index e7ad1c6..2203d87 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -282,17 +282,19 @@ void register_prog (struct component *comp);
int progman_running_p (void);
size_t progman_running_count (void);
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);
struct component *progman_lookup_tcpmux (const char *service,
const char *master);
@@ -359,13 +361,16 @@ struct pies_url
int pies_url_create (struct pies_url **purl, const char *str);
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);
void disable_socket (int fd);
void enable_socket (int fd);
@@ -453,12 +458,39 @@ struct inetd_builtin
struct inetd_builtin *inetd_builtin_lookup (const char *service, int socktype);
/* sysvinit.c */
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
#define SYSV_ACCT_RUNLEVEL 1
#define SYSV_ACCT_PROC_START 2
#define SYSV_ACCT_PROC_STOP 3
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
@@ -13,80 +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 <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)
static size_t numcomp;
static struct prog *proghead, *progtail;
static pies_depmap_t depmap;
@@ -206,13 +139,13 @@ prog_lookup_by_idx (unsigned idx)
for (prog = proghead; prog; prog = prog->next)
if (IS_COMPONENT (prog) && prog->v.p.idx == idx)
break;
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
link_prog (struct prog *pp, int prepend)
{
if (prepend)
@@ -1136,13 +1069,13 @@ progman_run_comp (struct component *comp, int fd,
prog->v.p.cclass = conn_class_lookup (comp->tag, sa, salen);
prog_start_prologue (prog);
prog_sockenv (prog);
prog_execute (prog);
}
-static int
+int
console_open (int mode)
{
int i, fd;
for (i = 0; i < 5; i++)
{
@@ -1562,21 +1495,15 @@ _prog_wait (struct prog *p)
p->v.p.num_instances++;
return 0;
}
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))
return _prog_accept (p);
return _prog_wait (p);
@@ -1753,13 +1680,13 @@ progman_create_sockets ()
{
int fd = create_socket (comp->socket_url,
comp->socket_type,
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;
}
else
prog->v.p.socket = fd;
@@ -1986,13 +1913,13 @@ prog_stop_dependents (struct prog *prog)
}
prog_stop (dp, SIGTERM);
}
free (pos);
}
-static void
+void
prog_stop (struct prog *prog, int sig)
{
if (prog->pid == 0)
return;
if (prog->type == TYPE_COMPONENT)
{
@@ -2020,26 +1947,37 @@ prog_stop_all (int sig)
if (IS_COMPONENT (prog)
&& (prog->v.p.status == status_enabled
|| prog->v.p.status == status_stopping))
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
print_status (const char *tag, pid_t pid, int status, int expect_term)
{
if (WIFEXITED (status))
@@ -2531,20 +2469,29 @@ progman_cleanup (int expect_term)
if (!expect_term)
/* This will also recompute alarm settings, if necessary */
progman_wake_sleeping (0);
}
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:
case status_listener:
prog_stop (prog, SIGTERM);
break;
@@ -2558,13 +2505,13 @@ progman_stop_component (const char *name)
prog->v.p.failcount = 0;
break;
default:
logmsg (LOG_INFO,
_("stopping component `%s': component not started"),
- name);
+ prog->tag);
}
}
}
void
progman_dump_stats (const char *filename)
diff --git a/src/socket.c b/src/socket.c
index e32701f..fdce7d1 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -392,23 +392,107 @@ 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;
}
void
disable_socket (int fd)
{
@@ -427,24 +511,26 @@ enable_socket (int fd)
FD_SET (fd, &listenset);
}
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)
{
if (errno != EINTR)
logmsg (LOG_ERR, "select: %s", strerror (errno));
diff --git a/src/sysvinit.c b/src/sysvinit.c
index ef765a1..940125f 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -12,12 +12,13 @@
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/>. */
#include "pies.h"
+#include "prog.h"
enum boot_state
{
sysinit,
boot,
single0,
@@ -121,12 +122,152 @@ enablecomp (struct component *comp, int finished, void *data)
}
return 0;
}
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 ()
{
progman_sysvinit_enable (enablecomp, NULL);
}
@@ -137,15 +278,18 @@ inittrans ()
int newlevel = 0;
enum boot_state newstate;
int trans = 0;
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
n = runlevel_index (runlevel);
if (n == -1)
n = runlevel_index ('S');
@@ -157,28 +301,30 @@ inittrans ()
if (newstate != boot_state)
{
debug (1, ("STATE TRANS: %s -> %s", boot_state_name[boot_state],
boot_state_name[newstate]));
boot_state = newstate;
trans = 1;
+ wait = 0;
}
switch (boot_state)
{
case sysinit:
break;
case boot:
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)
{
debug (1, ("RL TRANS: %c -> %c", runlevel, newlevel));
sysvinit_acct (SYSV_ACCT_RUNLEVEL, "runlevel", "~~",
newlevel + 256 * runlevel, "~");
@@ -195,12 +341,13 @@ inittrans ()
{
progman_sysvinit_enable (enablecomp, &wait);
if (wait)
return 1;
}
progman_sysvinit_enable (enablecomp, NULL);
+ wait = 0;
}
return trans;
}
/* Return true if the progman should wait for the component to
terminate. */
@@ -216,6 +363,43 @@ is_comp_wait (struct component *comp)
case pies_comp_kbrequest:
return 0;
}
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.