diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2016-01-31 13:43:18 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-01-31 13:43:18 +0200 |
commit | 6f9f2fd7a6952b544dccbf0bdc7f9c312f602afe (patch) | |
tree | 8bf0b45bb6578dee844dc92c1a90a93474f0fa7a | |
parent | 7f20aa4f7e26d8f740b55bef98f0c3c78eca0e79 (diff) | |
download | pies-6f9f2fd7a6952b544dccbf0bdc7f9c312f602afe.tar.gz pies-6f9f2fd7a6952b544dccbf0bdc7f9c312f602afe.tar.bz2 |
Fix runlevel switching; handle powerfail commands.
* src/ctl.c (prog_serialize): List runlevels.
* src/pies.c (main): Set got_alarm after reloading configuration.
Handle ACTION_POWER.
* src/pies.h (ACTION_POWER): New constant.
(progman_running_p): Rename to progman_waiting_p. All uses changed.
(sysvinit_power): New proto.
(POWER_STAT_FILE): New define.
(POWER_STAT_FAIL,POWER_STAT_LOW,POWER_STAT_OK): New constants.
* src/prog.h (prog) <idx>: Remove.
(prog) <wait>: New member.
* src/progman.c (prog_lookup_by_idx): Remove.
(progman_waiting_p): Return 1 only if there is at least one
prog with v.p.wait set.
(prog_start): Initialize v.p.wait for sysvinit components.
(progman_start): Don't do anything if waiting for components from
the previous runlevel.
(progman_wake_sleeping): Likewise.
(progman_cleanup): Assume expect_term if waiting for components from
the previous runlevel.
Clear v.p.wait on exited progs.
* src/sysvinit.c (sysvinit_fifo_handler): Don't call progman_stop
when handling runlevel changes.
Handle INIT_CMD_POWERFAIL, INIT_CMD_POWERFAILNOW, and
INIT_CMD_POWEROK.
(sysvinit_sigtrans): Handle SIGPWR.
(is_comp_wait): Rewrite.
(power_stat_file): New variable.
(sysvinit_power): New function.
-rw-r--r-- | src/ctl.c | 10 | ||||
-rw-r--r-- | src/pies.c | 7 | ||||
-rw-r--r-- | src/pies.h | 16 | ||||
-rw-r--r-- | src/prog.h | 2 | ||||
-rw-r--r-- | src/progman.c | 35 | ||||
-rw-r--r-- | src/sysvinit.c | 94 |
6 files changed, 135 insertions, 29 deletions
@@ -1821,17 +1821,19 @@ prog_serialize (struct json_value *ret, struct prog *prog) json_object_set_number (ret, "PID", prog->pid); else if (prog->v.p.status == status_listener && prog->v.p.comp->socket_url) json_object_set_string (ret, "URL", "%s", prog->v.p.comp->socket_url->string); + if (prog->v.p.comp->runlevels) + json_object_set_string (ret, "runlevels", "%s", + prog->v.p.comp->runlevels); + if (prog->v.p.status == status_sleeping) - { - json_object_set_number (ret, "wakeup-time", - prog->v.p.timestamp + SLEEPTIME); - } + json_object_set_number (ret, "wakeup-time", + prog->v.p.timestamp + SLEEPTIME); v = json_new_array (); for (i = 0; i < prog->v.p.comp->argc; i++) json_array_append (v, json_new_string (prog->v.p.comp->argv[i])); json_object_set (ret, "argv", v); break; @@ -2187,12 +2187,13 @@ main (int argc, char **argv) action = ACTION_CONT; } break; case ACTION_RELOAD: pies_reload (); + got_alarm = 1; action = ACTION_CONT; break; case ACTION_STOP: if (init_process) { @@ -2213,12 +2214,18 @@ main (int argc, char **argv) debug (1, ("kbrequest")); sysvinit_runlevel_setup (PIES_COMP_MASK (pies_comp_kbrequest), NULL); got_alarm = 1; action = ACTION_CONT; break; + + case ACTION_POWER: + debug (1, ("SIGPWR")); + sysvinit_power (); + got_alarm = 1; + action = ACTION_CONT; } if (action == ACTION_CONT) { if (children_cleanup) { children_cleanup = 0; @@ -267,13 +267,14 @@ struct component enum pies_action { ACTION_CONT, ACTION_STOP, ACTION_RESTART, ACTION_RELOAD, ACTION_CTRLALTDEL, - ACTION_KBREQUEST + ACTION_KBREQUEST, + ACTION_POWER }; extern char *instance; extern char *log_tag; extern int log_facility; extern unsigned long shutdown_timeout; @@ -313,13 +314,13 @@ void config_file_add_type (enum config_syntax_type syntax, const char *name); void free_redirector (struct redirector *rp); void pies_schedule_action (int act); void free_action (struct action *act); void register_prog (struct component *comp); -int progman_running_p (void); +int progman_waiting_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), @@ -510,20 +511,31 @@ int is_valid_runlevel (int c); int console_open (int mode); int telinit (const char *arg); int inittab_parse (const char *file); int sysvinit_sigtrans (int sig, int *pact); void sysvinit_runlevel_setup (int mask, int *wait); void sysvinit_sysdep_begin (void); +void sysvinit_power (void); extern char *sysvinit_environ_hint[]; extern char *init_fifo; #ifndef INIT_FIFO # define INIT_FIFO "/dev/initctl" #endif +#ifndef POWER_STAT_FILE +# define POWER_STAT_FILE "/var/run/powerstatus" +#endif + +/* Power status values */ +#define POWER_STAT_FAIL 'F' +#define POWER_STAT_LOW 'L' +#define POWER_STAT_OK 'O' + +/* Request codes */ #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 @@ -49,13 +49,13 @@ struct prog int facility; union { struct { struct component *comp; - size_t idx; /* Numeric identifier */ + int wait; 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 */ /* If status == status_listener: */ diff --git a/src/progman.c b/src/progman.c index 3bbd8b3..4ca3824 100644 --- a/src/progman.c +++ b/src/progman.c @@ -111,22 +111,12 @@ progman_lookup_tcpmux (const char *service, const char *master) && prog->v.p.comp->tcpmux && strcmp (prog->v.p.comp->tcpmux, master) == 0) return prog->v.p.comp; return NULL; } -struct prog * -prog_lookup_by_idx (unsigned idx) -{ - struct prog *prog; - for (prog = proghead; prog; prog = prog->next) - if (IS_COMPONENT (prog) && prog->v.p.idx == idx) - break; - return prog; -} - void prog_stop (struct prog *prog, int sig); static int prog_start_prerequisites (struct prog *prog); char const * prog_tag (struct prog const *prog) { @@ -302,21 +292,25 @@ register_command (char *tag, char *command, pid_t pid) newp->v.c.tag = grecs_strdup (tag); newp->v.c.command = command; link_prog (newp, 0); } int -progman_running_p () +progman_waiting_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) - return 1; + if (IS_COMPONENT (prog) && prog->v.p.wait && prog->pid > 0) + { + debug(1, ("%s: waiting for %s (%lu)", + __FUNCTION__, prog_tag (prog), + (unsigned long) prog->pid)); + return 1; + } } return 0; } size_t progman_running_count () @@ -1056,12 +1050,13 @@ prog_start (struct prog *prog) logmsg (LOG_NOTICE, "disabling sysvinit component %s", prog_tag (prog)); prog->v.p.status = status_disabled; } return; } + prog->v.p.wait = is_comp_wait (prog->v.p.comp); debug (1, ("ok to start %s", prog->v.p.comp->tag)); } /* This call returns 1 in two cases: Either prog is marked as disabled, in which case there's nothing more to do, or one or more of its prerequisites are in status_stopping. In the latter case either the @@ -1498,12 +1493,16 @@ progman_recompute_alarm () void progman_start () { struct prog *prog; + if (progman_waiting_p ()) + /* Noting to do if there are processes left in the previous runlevel */ + return; + recompute_alarm = 0; debug (1, ("starting components")); for (prog = proghead; prog; prog = prog->next) if (IS_COMPONENT (prog)) { if (prog->v.p.comp->mode == pies_comp_inetd) @@ -1543,12 +1542,16 @@ check_stopping (struct prog *prog, time_t now) void progman_wake_sleeping (int onalrm) { struct prog *prog; time_t now = time (NULL); + if (progman_waiting_p ()) + /* Noting to do if there are processes left in the previous runlevel */ + return; + debug (1, (_("managing sleeping/stopping components"))); for (prog = proghead; prog; prog = prog->next) if (IS_COMPONENT (prog)) { switch (prog->v.p.status) @@ -2251,12 +2254,15 @@ react (struct prog *prog, int status, pid_t pid) void progman_cleanup (int expect_term) { pid_t pid; int status; + + if (!expect_term) + expect_term = progman_waiting_p (); while ((pid = waitpid (-1, &status, WNOHANG)) > 0) { struct prog *prog = prog_lookup_by_pid (pid); if (!prog) { print_status (_("unknown child"), pid, status, expect_term); @@ -2301,12 +2307,13 @@ progman_cleanup (int expect_term) { if (prog->v.p.comp->mode >= pies_mark_sysvinit) { sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog_tag (prog), pid, ""); prog->v.p.status = status_finished; + prog->v.p.wait = 0; } else { if (is_sysvinit (prog->v.p.comp)) sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog_tag (prog), pid, ""); diff --git a/src/sysvinit.c b/src/sysvinit.c index d8b7cc5..be7aef8 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -399,13 +399,15 @@ sysvinit_setenv (char const *data, int size) break; } } } char *init_fifo = INIT_FIFO; + static void create_fifo (void); +static void powerfailcmd (int power_stat); static int sysvinit_fifo_handler (int fd, void *data) { static size_t size; union @@ -453,23 +455,34 @@ sysvinit_fifo_handler (int fd, void *data) case 'Q': break; default: if (buf.req.runlevel != runlevel) { - progman_stop (); dfl_level = buf.req.runlevel; inittrans (); } } break; case INIT_CMD_SETENV: sysvinit_setenv (buf.req.data, sizeof (buf.req.data)); break; + case INIT_CMD_POWERFAIL: + powerfailcmd (POWER_STAT_FAIL); + break; + + case INIT_CMD_POWERFAILNOW: + powerfailcmd (POWER_STAT_LOW); + break; + + case INIT_CMD_POWEROK: + powerfailcmd (POWER_STAT_OK); + break; + /* FIXME: react on other commands */ } } size = 0; } return 0; @@ -570,12 +583,15 @@ sysvinit_sigtrans (int sig, int *pact) break; case SIGTERM: case SIGQUIT: /* Ignore these signals. */ *pact = ACTION_CONT; break; + case SIGPWR: + *pact = ACTION_POWER; + break; default: return 0; } return 1; } @@ -651,13 +667,13 @@ inittrans () int n; int newlevel = 0; enum boot_state newstate; int trans = 0; static int wait = 0; - if (progman_running_p ()) + if (progman_waiting_p ()) /* Noting to do if there are processes left in the previous runlevel */ return 0; if (runlevel == 0) n = runlevel_index (dfl_level ? dfl_level : getinitdefault ()); else @@ -723,22 +739,24 @@ inittrans () terminate. */ int is_comp_wait (struct component *comp) { switch (comp->mode) { - case pies_comp_boot: - case pies_comp_powerfail: - case pies_comp_ctrlaltdel: + case pies_comp_sysinit: + case pies_comp_bootwait: + case pies_comp_wait: + case pies_comp_powerwait: case pies_comp_powerfailnow: - case pies_comp_kbrequest: - return 0; + case pies_comp_powerokwait: + case pies_comp_ctrlaltdel: + return 1; default: break; } - return 1; + return 0; } int telinit (const char *arg) { int fd; @@ -968,6 +986,66 @@ inittab_parse (const char *file) } free (buf); fclose (fp); return err; } + +char *power_stat_file = POWER_STAT_FILE; + +void +sysvinit_power (void) +{ + int power_stat = POWER_STAT_FAIL; + int fd; + + fd = open (power_stat_file, O_RDONLY); + if (fd >= 0) + { + char c; + switch (read (fd, &c, 1)) + { + case 1: + power_stat = c; + break; + + case 0: + logmsg (LOG_NOTICE, _("unexpected EOF on %s"), power_stat_file); + break; + + case -1: + logmsg (LOG_ERR, _("error reading from %s: %s"), + power_stat_file, strerror (errno)); + } + close (fd); + if (unlink (power_stat_file)) + logmsg (LOG_ERR, _("can't unlink %s: %s"), power_stat_file, + strerror (errno)); + } + else + debug (1, (_("can't open %s: %s"), power_stat_file, strerror (errno))); + + powerfailcmd (power_stat); +} + +static void +powerfailcmd (int power_stat) +{ + int mask; + + switch (power_stat) + { + case POWER_STAT_OK: /* The power is OK */ + mask = PIES_COMP_MASK (pies_comp_powerokwait); + break; + + case POWER_STAT_LOW: /* Low battery: shut down now */ + mask = PIES_COMP_MASK (pies_comp_powerfailnow); + break; + + default: /* Power failure */ + mask = PIES_COMP_MASK (pies_comp_powerfail) + | PIES_COMP_MASK (pies_comp_powerwait); + } + + sysvinit_runlevel_setup (mask, NULL); +} |