diff options
-rw-r--r-- | src/acl.c | 2 | ||||
-rw-r--r-- | src/pies.c | 28 | ||||
-rw-r--r-- | src/pies.h | 6 | ||||
-rw-r--r-- | src/prog.h | 1 | ||||
-rw-r--r-- | src/progman.c | 118 | ||||
-rw-r--r-- | src/socket.c | 2 | ||||
-rw-r--r-- | src/sysvinit.c | 296 |
7 files changed, 290 insertions, 163 deletions
@@ -637,14 +637,12 @@ acl_compare (void const *data1, void const *data2) return strcasecmp (p1->name, p2->name); } 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; } static void @@ -992,13 +992,13 @@ _cb_runlevels (enum grecs_callback_command cmd, if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING)) return 1; for (p = value->v.string; *p; p++) { 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; } } *sptr = grecs_strdup(value->v.string); for (p = *sptr; *p; p++) *p = toupper (*p); @@ -2112,37 +2112,12 @@ set_state_file_names (const char *base) if (!statfile) statfile = mkfilename (statedir, base, ".stat"); if (!qotdfile) 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) { int index; pid_t pid; extern char **environ; @@ -2303,13 +2278,12 @@ main (int argc, char **argv) umask (pies_umask); } if (init_process) { foreground = 1; - set_console_dev (); sysvinit_begin (); } else switch (pies_check_status (&pid)) { case pies_status_ctr: @@ -300,14 +300,12 @@ struct component *progman_lookup_tcpmux (const char *service, void progman_run_comp (struct component *comp, int fd, union pies_sockaddr_storage *sa, socklen_t salen); 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); int check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen); void log_setup (int want_stderr); @@ -459,12 +457,16 @@ 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); +int console_open (int mode); +int telinit (const char *arg); + +extern char *sysvinit_environ_hint[]; #ifndef INIT_FIFO # define INIT_FIFO "/dev/initctl" #endif #define INIT_MAGIC 0x03091969 @@ -80,6 +80,7 @@ struct prog char *command; } c; } v; }; 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 @@ -12,59 +12,45 @@ 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 <termios.h> #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; 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) { struct prog *prog; for (prog = proghead; prog; prog = prog->next) @@ -365,16 +351,13 @@ progman_running_p () struct prog *prog; for (prog = proghead; prog; prog = prog->next) { 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; } size_t progman_running_count () @@ -756,12 +739,13 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b) res[namelen + 1 + len] = 0; } else /* if (a == NULL) */ { if (c_ispunct (b[0])) b++; + len = strlen (b); res = xmalloc (namelen + 1 + len + 1); strcpy (res + namelen + 1, b); } memcpy (res, name, namelen); res[namelen] = '='; return res; @@ -1012,12 +996,14 @@ prog_start_prologue (struct prog *prog) prog->tag, prog->v.p.comp->dir, strerror (errno)); } 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); if (prog->v.p.comp->umask) umask (prog->v.p.comp->umask); @@ -1069,74 +1055,12 @@ 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); } -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) { pid_t pid; int redir[2]; fd_set fdset; @@ -1197,12 +1121,15 @@ prog_start (struct prog *prog) break; case pies_comp_inetd: /* Wait until an incoming connection is requested */ if (prog->v.p.socket == -1) return; + + default: + break; } debug (1, (_("starting %s"), prog->tag)); if (prog->v.p.comp->rmfile) { @@ -1248,13 +1175,13 @@ prog_start (struct prog *prog) { int fd = console_open (O_RDWR|O_NOCTTY); if (fd < 0) { 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); if (fd != 1) dup2 (fd, 1); if (fd != 2) @@ -2469,21 +2396,12 @@ 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; for (prog = proghead; prog; prog = prog->next) if (IS_COMPONENT (prog) && strcmp (prog->tag, name) == 0) diff --git a/src/socket.c b/src/socket.c index c4edcc3..78f79f5 100644 --- a/src/socket.c +++ b/src/socket.c @@ -424,13 +424,13 @@ find_socket_handler (int (*handler) (int, void *)) for (sp = si_head; sp; sp = sp->next) if (sp->handler == handler) break; return sp; } -static int +static void calc_fd_max () { struct sockinst *sp; fd_max = -1; for (sp = si_head; sp; sp = sp->next) diff --git a/src/sysvinit.c b/src/sysvinit.c index 940125f..23cad9a 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -13,55 +13,186 @@ 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 <termios.h> enum boot_state { sysinit, boot, - single0, - single1, + single, normal, max_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"; 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) { char *p; @@ -72,27 +203,27 @@ runlevel_index (int n) if (!p) return -1; return p - valid_runlevels; } 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) { case sysinit: return comp->mode == pies_comp_sysinit; case boot: return comp->mode == pies_comp_boot || comp->mode == pies_comp_bootwait; - case single0: - case single1: + case single: case normal: switch (comp->mode) { case pies_comp_sysinit: case pies_comp_boot: case pies_comp_bootwait: @@ -108,13 +239,13 @@ enablecomp (struct component *comp, int finished, void *data) return 0; } } rc = !!strchr (comp->runlevels, runlevel); if (!rc) return rc; - if (finished) + if (prog->v.p.status == status_finished) return -1; if (wait) { if (comp->mode == pies_comp_wait) { *wait = 1; @@ -122,20 +253,96 @@ enablecomp (struct component *comp, int finished, void *data) } return 0; } 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 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 sysvinit_stop_filter (struct prog *prog, void *data) { switch (prog->v.p.status) @@ -262,45 +469,71 @@ create_fifo () strerror (errno)); return; } 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 inittrans () { int n; int newlevel = 0; enum boot_state newstate; int trans = 0; 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], boot_state_name[newstate])); boot_state = newstate; trans = 1; @@ -311,42 +544,43 @@ inittrans () { case sysinit: break; 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) { debug (1, ("RL TRANS: %c -> %c", runlevel, newlevel)); 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; } if (wait) 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 true if the progman should wait for the component to |