aboutsummaryrefslogtreecommitdiff
path: root/src/sysvinit.c
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/sysvinit.c
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/sysvinit.c')
-rw-r--r--src/sysvinit.c192
1 files changed, 188 insertions, 4 deletions
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.