summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2016-01-31 11:43:18 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2016-01-31 11:43:18 (GMT)
commit6f9f2fd7a6952b544dccbf0bdc7f9c312f602afe (patch) (side-by-side diff)
tree8bf0b45bb6578dee844dc92c1a90a93474f0fa7a
parent7f20aa4f7e26d8f740b55bef98f0c3c78eca0e79 (diff)
downloadpies-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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/ctl.c10
-rw-r--r--src/pies.c7
-rw-r--r--src/pies.h16
-rw-r--r--src/prog.h2
-rw-r--r--src/progman.c35
-rw-r--r--src/sysvinit.c94
6 files changed, 135 insertions, 29 deletions
diff --git a/src/ctl.c b/src/ctl.c
index d3e6b64..0e5ea97 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -1824,11 +1824,13 @@ prog_serialize (struct json_value *ret, struct prog *prog)
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++)
diff --git a/src/pies.c b/src/pies.c
index 1bce1eb..96e9281 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -2190,6 +2190,7 @@ main (int argc, char **argv)
case ACTION_RELOAD:
pies_reload ();
+ got_alarm = 1;
action = ACTION_CONT;
break;
@@ -2216,6 +2217,12 @@ main (int argc, char **argv)
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)
{
diff --git a/src/pies.h b/src/pies.h
index ad8e8ee..39977c7 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -270,7 +270,8 @@ enum pies_action {
ACTION_RESTART,
ACTION_RELOAD,
ACTION_CTRLALTDEL,
- ACTION_KBREQUEST
+ ACTION_KBREQUEST,
+ ACTION_POWER
};
extern char *instance;
@@ -316,7 +317,7 @@ 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);
@@ -513,6 +514,7 @@ 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;
@@ -521,6 +523,16 @@ extern char *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
diff --git a/src/prog.h b/src/prog.h
index a29de04..fe42d3a 100644
--- a/src/prog.h
+++ b/src/prog.h
@@ -52,7 +52,7 @@ struct prog
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 */
diff --git a/src/progman.c b/src/progman.c
index 3bbd8b3..4ca3824 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -114,16 +114,6 @@ progman_lookup_tcpmux (const char *service, const char *master)
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);
@@ -305,15 +295,19 @@ register_command (char *tag, char *command, pid_t pid)
}
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;
}
@@ -1059,6 +1053,7 @@ prog_start (struct prog *prog)
}
return;
}
+ prog->v.p.wait = is_comp_wait (prog->v.p.comp);
debug (1, ("ok to start %s", prog->v.p.comp->tag));
}
@@ -1501,6 +1496,10 @@ 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)
@@ -1546,6 +1545,10 @@ 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)
@@ -2254,6 +2257,9 @@ 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);
@@ -2304,6 +2310,7 @@ progman_cleanup (int expect_term)
sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog_tag (prog),
pid, "");
prog->v.p.status = status_finished;
+ prog->v.p.wait = 0;
}
else
{
diff --git a/src/sysvinit.c b/src/sysvinit.c
index d8b7cc5..be7aef8 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -402,7 +402,9 @@ sysvinit_setenv (char const *data, int size)
}
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)
@@ -456,7 +458,6 @@ sysvinit_fifo_handler (int fd, void *data)
default:
if (buf.req.runlevel != runlevel)
{
- progman_stop ();
dfl_level = buf.req.runlevel;
inittrans ();
}
@@ -467,6 +468,18 @@ sysvinit_fifo_handler (int fd, void *data)
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 */
}
}
@@ -573,6 +586,9 @@ sysvinit_sigtrans (int sig, int *pact)
/* Ignore these signals. */
*pact = ACTION_CONT;
break;
+ case SIGPWR:
+ *pact = ACTION_POWER;
+ break;
default:
return 0;
}
@@ -654,7 +670,7 @@ inittrans ()
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;
@@ -726,16 +742,18 @@ 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
@@ -971,3 +989,63 @@ inittab_parse (const char *file)
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);
+}

Return to:

Send suggestions and report system problems to the System administrator.