aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-01-07 14:31:58 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2013-01-07 14:31:58 +0200
commit5d2eff82abf052d5edb8f201559cb6e17bbf158f (patch)
tree7151f3fc984021039be9549fc0017ce3fe30bb5c
parent720f035564cbec85af84d1d9daff48d4068a4f3e (diff)
downloadpies-5d2eff82abf052d5edb8f201559cb6e17bbf158f.tar.gz
pies-5d2eff82abf052d5edb8f201559cb6e17bbf158f.tar.bz2
Fix sysvinit execution environment, simplify boot state system.
* src/pies.c (_cb_runlevels): Bugfix. (set_console_dev): Move to sysvinit.c * src/pies.h (progman_sysvinit_enable): Remove proto. (console_open, telinit): New protos. (sysvinit_environ_hint): New extern. * src/prog.h (prog_stop): New proto. * src/progman.c (env_concat): Bugfix. (env_concat): In sysvinit mode, apply sysvinit_environ_hint to the environment. (console_open, console_stty): Move to sysvinit.c * src/sysvinit.c (boot_state): Simplify state set. (getinitdefault, askrunlevel): New functions. (sysvinit_runlevel_setup): New function. (enablecomp): Change signature to match progman_foreach API. (sysvinit_begin): Prepare console, become a session leader, prepare environment. (inittrans): Call sysvinit_runlevel_setup * src/socket.c (calc_fd_max): Fix return type. * src/acl.c (acl_copy): Remove unused variable.
-rw-r--r--src/acl.c2
-rw-r--r--src/pies.c28
-rw-r--r--src/pies.h6
-rw-r--r--src/prog.h1
-rw-r--r--src/progman.c118
-rw-r--r--src/socket.c2
-rw-r--r--src/sysvinit.c296
7 files changed, 290 insertions, 163 deletions
diff --git a/src/acl.c b/src/acl.c
index df53165..301f56f 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -640,8 +640,6 @@ acl_compare (void const *data1, void const *data2)
static int
acl_copy (void *a, void *b)
{
- const struct pies_acl *pb = b;
-
memcpy (a, b, sizeof (struct pies_acl));
memset (b, 0, sizeof (struct pies_acl));
return 0;
diff --git a/src/pies.c b/src/pies.c
index 36bd220..beab6fa 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -995,7 +995,7 @@ _cb_runlevels (enum grecs_callback_command cmd,
{
if (!is_valid_runlevel (*p))
{
- grecs_error (locus, 0, _("not a valid runlevel: %c"));
+ grecs_error (locus, 0, _("not a valid runlevel: %c"), *p);
return 1;
}
}
@@ -2115,31 +2115,6 @@ set_state_file_names (const char *base)
qotdfile = mkfilename (statedir, base, ".qotd");
}
-static char *try_console[] = { NULL, "/dev/console", "/dev/tty0" };
-char *console_device;
-
-static void
-set_console_dev ()
-{
- int i;
- for (i = 0; i < ARRAY_SIZE (try_console); i++)
- {
- if (try_console[i])
- {
- int fd = open (try_console[i], O_RDONLY|O_NONBLOCK);
-
- if (fd >= 0)
- {
- close (fd);
- console_device = try_console[i];
- return;
- }
- }
- }
- /* provide default */
- console_device = "/dev/null";
-}
-
int
main (int argc, char **argv)
{
@@ -2306,7 +2281,6 @@ main (int argc, char **argv)
if (init_process)
{
foreground = 1;
- set_console_dev ();
sysvinit_begin ();
}
else
diff --git a/src/pies.h b/src/pies.h
index 0da13e3..ca50a26 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -303,8 +303,6 @@ void progman_run_comp (struct component *comp, int fd,
void progman_iterate_comp (int (*fun) (struct component *, void *),
void *data);
-void progman_sysvinit_enable (int (*fun) (struct component *, int, void *),
- void *data);
void fd_report (int fd, const char *msg);
@@ -462,6 +460,10 @@ void sysvinit_begin (void);
int inittrans (void);
int is_comp_wait (struct component *comp);
int is_valid_runlevel (int c);
+int console_open (int mode);
+int telinit (const char *arg);
+
+extern char *sysvinit_environ_hint[];
#ifndef INIT_FIFO
# define INIT_FIFO "/dev/initctl"
diff --git a/src/prog.h b/src/prog.h
index 5a5ad13..8fddf97 100644
--- a/src/prog.h
+++ b/src/prog.h
@@ -83,3 +83,4 @@ struct prog
};
void progman_foreach (int (*filter) (struct prog *, void *data), void *data);
+void prog_stop (struct prog *prog, int sig);
diff --git a/src/progman.c b/src/progman.c
index 1895152..0463366 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -15,7 +15,6 @@
along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
#include "pies.h"
-#include <termios.h>
#include "prog.h"
#define IS_COMPONENT(p) ((p)->type == TYPE_COMPONENT)
@@ -27,41 +26,28 @@ static int recompute_alarm;
static struct grecs_symtab *conn_tab;
void
-progman_iterate_comp (int (*fun) (struct component *, void *), void *data)
+progman_foreach (int (*filter) (struct prog *, void *data), void *data)
{
struct prog *prog;
-
for (prog = proghead; prog; prog = prog->next)
- if (IS_COMPONENT (prog)
- && !(prog->v.p.comp->mode == pies_comp_inetd
- && prog->v.p.listener)
- && fun (prog->v.p.comp, data))
+ if (IS_COMPONENT (prog) && filter (prog, data))
break;
}
+/* FIXME: Rewrite this using progman_foreach */
void
-progman_sysvinit_enable (int (*fun) (struct component *, int, void *),
- void *data)
+progman_iterate_comp (int (*fun) (struct component *, void *), void *data)
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
- if (IS_COMPONENT (prog) && is_sysvinit (prog->v.p.comp))
- {
- int rc = fun (prog->v.p.comp, prog->v.p.status == status_finished,
- data);
- if (rc < 0)
- continue;
- if (rc)
- prog->v.p.status = status_enabled;
- else
- prog->v.p.status = status_disabled;
- debug (1, ("%s: %s", prog->tag,
- prog->v.p.status == status_enabled ?
- "enabled" : "disabled"));
- }
+ if (IS_COMPONENT (prog)
+ && !(prog->v.p.comp->mode == pies_comp_inetd
+ && prog->v.p.listener)
+ && fun (prog->v.p.comp, data))
+ break;
}
-
+
static struct prog *
prog_lookup_by_pid (pid_t pid)
{
@@ -368,10 +354,7 @@ progman_running_p ()
{
if (IS_COMPONENT (prog) && is_comp_wait (prog->v.p.comp) &&
prog->pid > 0)
- {
- debug (1, ("COMP %s still running", prog->tag));
- return 1;
- }
+ return 1;
}
return 0;
}
@@ -759,6 +742,7 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b)
{
if (c_ispunct (b[0]))
b++;
+ len = strlen (b);
res = xmalloc (namelen + 1 + len + 1);
strcpy (res + namelen + 1, b);
}
@@ -1015,6 +999,8 @@ prog_start_prologue (struct prog *prog)
environ_setup (prog->v.p.comp->env ?
prog->v.p.comp->env :
((prog->v.p.comp->flags & CF_SOCKENV) ? sockenv_hint : NULL));
+ if (init_process)
+ environ_setup (sysvinit_environ_hint);
DEBUG_ENVIRON (4);
pies_priv_setup (&prog->v.p.comp->privs);
@@ -1072,68 +1058,6 @@ progman_run_comp (struct component *comp, int fd,
prog_execute (prog);
}
-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);
- return fd;
- }
- }
- return -1;
-}
-
-static void
-console_stty ()
-{
- struct termios tty;
- int fd;
-
- if ((fd = console_open (O_RDWR|O_NOCTTY)) < 0)
- {
- logmsg (LOG_CRIT, "can't open %s", console_device);
- return;
- }
-
- tcgetattr (fd, &tty);
-
- tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
- tty.c_cflag |= HUPCL|CLOCAL|CREAD;
-
- tty.c_cc[VINTR] = 3; /* ctrl('c') */
- tty.c_cc[VQUIT] = 28; /* ctrl('\\') */
- tty.c_cc[VERASE] = 127;
- tty.c_cc[VKILL] = 24; /* ctrl('x') */
- tty.c_cc[VEOF] = 4; /* ctrl('d') */
- tty.c_cc[VTIME] = 0;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VSTART] = 17; /* ctrl('q') */
- tty.c_cc[VSTOP] = 19; /* ctrl('s') */
- tty.c_cc[VSUSP] = 26; /* ctrl('z') */
-
- /*
- * Set pre and post processing
- */
- tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
- tty.c_oflag = OPOST|ONLCR;
- tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
-
- /*
- * Now set the terminal line.
- * We don't care about non-transmitted output data
- * and non-read input data.
- */
- tcsetattr (fd, TCSANOW, &tty);
- tcflush(fd, TCIOFLUSH);
- close (fd);
-}
-
static void
prog_start (struct prog *prog)
{
@@ -1200,6 +1124,9 @@ prog_start (struct prog *prog)
/* Wait until an incoming connection is requested */
if (prog->v.p.socket == -1)
return;
+
+ default:
+ break;
}
debug (1, (_("starting %s"), prog->tag));
@@ -1251,7 +1178,7 @@ prog_start (struct prog *prog)
{
logmsg (LOG_CRIT, "open(%s): %s",
console_device, strerror (errno));
- fd = open("/dev/null", O_RDWR);
+ fd = open ("/dev/null", O_RDWR);
}
if (fd != 0)
dup2 (fd, 0);
@@ -2472,15 +2399,6 @@ 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;
diff --git a/src/socket.c b/src/socket.c
index c4edcc3..78f79f5 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -427,7 +427,7 @@ find_socket_handler (int (*handler) (int, void *))
return sp;
}
-static int
+static void
calc_fd_max ()
{
struct sockinst *sp;
diff --git a/src/sysvinit.c b/src/sysvinit.c
index 940125f..23cad9a 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -16,13 +16,13 @@
#include "pies.h"
#include "prog.h"
+#include <termios.h>
enum boot_state
{
sysinit,
boot,
- single0,
- single1,
+ single,
normal,
max_boot_state
};
@@ -30,12 +30,11 @@ enum boot_state
static char *boot_state_name[] = {
"sysinit",
"boot",
- "single0",
- "single1",
+ "single",
"normal"
};
-static char boot_state_str[] = "#*sS ";
+static char boot_state_str[] = "#*s ";
static const char valid_runlevels[] = "0123456789S";
@@ -43,22 +42,154 @@ static int boot_trans_tab[max_boot_state][sizeof(valid_runlevels)-1] = {
/* 0, 1, 2, 3, 4, */
/* 5, 6, 7, 8, 9, S */
/* sysinit */ { boot, boot, boot, boot, boot,
- boot, boot, boot, boot, boot, single0 },
+ boot, boot, boot, boot, boot, single },
/* boot */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single1 },
- /* single0 */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single0 },
- /* single1 */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single1 },
+ normal, normal, normal, normal, normal, normal },
+ /* single */ { boot, boot, boot, boot, boot,
+ boot, boot, boot, boot, boot, single },
/* normal */ { normal, normal, normal, normal, normal,
- normal, normal, normal, normal, normal, single1 },
+ normal, normal, normal, normal, normal, normal },
};
enum boot_state boot_state;
int runlevel = 0;
+int prevlevel = 'N';
int initdefault; /* Default runlevel */
int dfl_level;
+
+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);
+ return fd;
+ }
+ }
+ return -1;
+}
+
+void
+console_stty ()
+{
+ struct termios tty;
+ int fd;
+
+ if ((fd = console_open (O_RDWR|O_NOCTTY)) < 0)
+ {
+ logmsg (LOG_CRIT, "can't open %s", console_device);
+ return;
+ }
+
+ tcgetattr (fd, &tty);
+
+ tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+ tty.c_cflag |= HUPCL|CLOCAL|CREAD;
+
+ tty.c_cc[VINTR] = 3; /* ctrl('c') */
+ tty.c_cc[VQUIT] = 28; /* ctrl('\\') */
+ tty.c_cc[VERASE] = 127;
+ tty.c_cc[VKILL] = 24; /* ctrl('x') */
+ tty.c_cc[VEOF] = 4; /* ctrl('d') */
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VSTART] = 17; /* ctrl('q') */
+ tty.c_cc[VSTOP] = 19; /* ctrl('s') */
+ tty.c_cc[VSUSP] = 26; /* ctrl('z') */
+
+ /*
+ * Set pre and post processing
+ */
+ tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+ tty.c_oflag = OPOST|ONLCR;
+ tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+
+ /*
+ * Now set the terminal line.
+ * We don't care about non-transmitted output data
+ * and non-read input data.
+ */
+ tcsetattr (fd, TCSANOW, &tty);
+ tcflush(fd, TCIOFLUSH);
+ close (fd);
+}
+
+int
+askrunlevel ()
+{
+ int fd;
+ char c, lvl = -1;
+ enum { srl_init, srl_char, srl_r, srl_n, srl_skip } srl = srl_init;
+ static const char prompt[] = "\nEnter runlevel: ";
+
+ console_stty ();
+ fd = console_open (O_RDWR|O_NOCTTY);
+ if (fd == -1)
+ return 'S';
+
+ while (1)
+ {
+ if (srl == srl_init)
+ {
+ write (fd, prompt, sizeof (prompt) - 1);
+ if (read (fd, &lvl, 1) != 1)
+ return 'S';
+ srl = srl_char;
+ }
+ else if (srl == srl_n)
+ {
+ if (is_valid_runlevel (lvl))
+ break;
+ srl = srl_init;
+ }
+ else
+ {
+ if (read (fd, &c, 1) != 1)
+ {
+ if (!is_valid_runlevel (lvl))
+ lvl = 'S';
+ break;
+ }
+
+ switch (srl)
+ {
+ case srl_char:
+ if (c == '\r')
+ srl = srl_r;
+ else if (c == '\n')
+ srl = srl_n;
+ else
+ srl = srl_skip;
+ break;
+
+ case srl_r:
+ if (c == '\n')
+ srl = srl_n;
+ else
+ srl = srl_skip;
+ break;
+
+ case srl_skip:
+ if (c == '\n')
+ srl = srl_init;
+ }
+ }
+ }
+ close (fd);
+ return toupper (lvl);
+}
+
+static int
+getinitdefault ()
+{
+ return initdefault ? initdefault : askrunlevel ();
+}
static int
runlevel_index (int n)
@@ -75,10 +206,11 @@ runlevel_index (int n)
}
static int
-enablecomp (struct component *comp, int finished, void *data)
+enablecomp (struct prog *prog, void *data)
{
int *wait = data;
int rc;
+ struct component *comp = prog->v.p.comp;
switch (boot_state)
{
@@ -88,8 +220,7 @@ enablecomp (struct component *comp, int finished, void *data)
case boot:
return comp->mode == pies_comp_boot || comp->mode == pies_comp_bootwait;
- case single0:
- case single1:
+ case single:
case normal:
switch (comp->mode)
{
@@ -111,7 +242,7 @@ enablecomp (struct component *comp, int finished, void *data)
rc = !!strchr (comp->runlevels, runlevel);
if (!rc)
return rc;
- if (finished)
+ if (prog->v.p.status == status_finished)
return -1;
if (wait)
{
@@ -125,6 +256,31 @@ enablecomp (struct component *comp, int finished, void *data)
return rc;
}
+static int
+runlevel_setup_prog (struct prog *prog, void *data)
+{
+ if (is_sysvinit (prog->v.p.comp))
+ {
+ int rc = enablecomp (prog, data);
+ if (rc < 0)
+ return 0;
+ if (rc)
+ prog->v.p.status = status_enabled;
+ else
+ prog->v.p.status = status_disabled;
+ debug (1, ("%s: %s", prog->tag,
+ prog->v.p.status == status_enabled ?
+ "enabled" : "disabled"));
+ }
+ return 0;
+}
+
+static void
+sysvinit_runlevel_setup (int *wait)
+{
+ progman_foreach (runlevel_setup_prog, wait);
+}
+
static const char valid_runlevel_arg[] = "0123456789SsQqAaBbCcUu";
int
@@ -133,6 +289,57 @@ is_valid_runlevel (int c)
return !!strchr (valid_runlevel_arg, c);
}
+#define ENVAR_CONSOLE "CONSOLE="
+#define ENVTMPL_CONSOLE "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+static char env_prevlevel[] = "PREVLEVEL=x";
+static char env_runlevel[] = "RUNLEVEL=x";
+static char env_console[] = ENVAR_CONSOLE ENVTMPL_CONSOLE;
+
+char *sysvinit_environ_hint[] = {
+ env_prevlevel,
+ env_runlevel,
+ env_console,
+ "INIT_VERSION=" PACKAGE_STRING,
+ "PATH=/bin:/usr/bin:/sbin:/usr/sbin",
+ NULL
+};
+
+#define ENVI_PREVLEVEL 0
+#define ENVI_RUNLEVEL 1
+#define ENVI_CONSOLE 2
+#define ENVI_VERSION 3
+#define ENVI_PATH 4
+
+static void
+envsetup ()
+{
+ int i;
+
+ for (i = 0; sysvinit_environ_hint[i]; i++)
+ {
+ char *str = sysvinit_environ_hint[i];
+ switch (i)
+ {
+ case ENVI_PREVLEVEL:
+ str[strlen (str) - 1] = prevlevel;
+ break;
+
+ case ENVI_RUNLEVEL:
+ str[strlen (str) - 1] =
+ boot_state_str[boot_state] == ' ' ?
+ (runlevel ? runlevel : '#') : boot_state_str[boot_state];
+ break;
+
+ case ENVI_CONSOLE:
+ if (strlen (console_device) >= sizeof (ENVTMPL_CONSOLE))
+ logmsg (LOG_ERR, "console device name too long");
+ else
+ strcpy (str + sizeof (ENVAR_CONSOLE) - 1, console_device);
+ }
+ }
+}
+
static void create_fifo (void);
static int
@@ -265,10 +472,42 @@ create_fifo ()
register_socket (fd, sysvinit_fifo_handler, NULL);
}
+static char *try_console[] = { NULL, "/dev/console", "/dev/tty0" };
+char *console_device;
+
+static void
+set_console_dev ()
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE (try_console); i++)
+ {
+ if (try_console[i])
+ {
+ int fd = open (try_console[i], O_RDONLY|O_NONBLOCK);
+
+ if (fd >= 0)
+ {
+ close (fd);
+ console_device = try_console[i];
+ return;
+ }
+ }
+ }
+ /* provide default */
+ console_device = "/dev/null";
+}
+
void
sysvinit_begin ()
{
- progman_sysvinit_enable (enablecomp, NULL);
+ close (0);
+ close (1);
+ close (2);
+ set_console_dev ();
+ console_stty ();
+ setsid ();
+ envsetup ();
+ sysvinit_runlevel_setup (NULL);
}
int
@@ -281,23 +520,17 @@ inittrans ()
static int wait = 0;
if (progman_running_p ())
- {
- debug (1, ("%s exiting: some components still running",__FUNCTION__));
- /* Noting to do if there are processes left in the previous runlevel */
- return 0;
- }
+ /* 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);
+ n = runlevel_index (dfl_level ? dfl_level : getinitdefault ());
else
n = runlevel_index (runlevel);
if (n == -1)
n = runlevel_index ('S');
newstate = boot_trans_tab[boot_state][n];
- debug (1, ("STATE TRANS: %s(%c,%d) -> %s", boot_state_name[boot_state],
- runlevel,n,
- boot_state_name[newstate]));
if (newstate != boot_state)
{
debug (1, ("STATE TRANS: %s -> %s", boot_state_name[boot_state],
@@ -314,13 +547,12 @@ inittrans ()
case boot:
sysvinit_acct (SYSV_ACCT_BOOT, "reboot", "~~", 0, "~");
break;
- case single0:
+ case single:
newlevel = 'S';
break;
- case single1:
case normal:
/* boot -> normal */
- newlevel = dfl_level ? dfl_level : initdefault;
+ newlevel = dfl_level ? dfl_level : getinitdefault ();
create_fifo ();
}
if (newlevel && newlevel != runlevel)
@@ -329,6 +561,7 @@ inittrans ()
sysvinit_acct (SYSV_ACCT_RUNLEVEL, "runlevel", "~~",
newlevel + 256 * runlevel, "~");
mf_proctitle_format ("init [%c]", newlevel);
+ prevlevel = runlevel ? runlevel : 'N';
runlevel = newlevel;
trans = 1;
wait = 0;
@@ -337,13 +570,14 @@ inittrans ()
trans = 1;
if (trans)
{
+ envsetup ();
if (wait == 0)
{
- progman_sysvinit_enable (enablecomp, &wait);
+ sysvinit_runlevel_setup (&wait);
if (wait)
return 1;
}
- progman_sysvinit_enable (enablecomp, NULL);
+ sysvinit_runlevel_setup (NULL);
wait = 0;
}
return trans;

Return to:

Send suggestions and report system problems to the System administrator.