runsvdir: (almost) close a signal race

We could lose a signal while processing previous one

function                                             old     new   delta
runsvdir_main                                       1088    1077     -11

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2015-03-02 17:37:31 +01:00
parent 1eafd44947
commit fa535f3e48
1 changed files with 28 additions and 25 deletions

View File

@ -59,7 +59,6 @@ struct globals {
int svnum;
#if ENABLE_FEATURE_RUNSVDIR_LOG
char *rplog;
int rploglen;
struct fd_pair logpipe;
struct pollfd pfd[1];
unsigned stamplog;
@ -70,7 +69,6 @@ struct globals {
#define svdir (G.svdir )
#define svnum (G.svnum )
#define rplog (G.rplog )
#define rploglen (G.rploglen )
#define logpipe (G.logpipe )
#define pfd (G.pfd )
#define stamplog (G.stamplog )
@ -219,15 +217,11 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
struct stat s;
dev_t last_dev = last_dev; /* for gcc */
ino_t last_ino = last_ino; /* for gcc */
time_t last_mtime = 0;
int wstat;
time_t last_mtime;
int curdir;
pid_t pid;
unsigned deadline;
unsigned now;
unsigned stampcheck;
int i;
int need_rescan = 1;
int need_rescan;
char *opt_s_argv[3];
INIT_G();
@ -257,8 +251,7 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
/* setup log */
if (*argv) {
rplog = *argv;
rploglen = strlen(rplog);
if (rploglen < 7) {
if (strlen(rplog) < 7) {
warnx("log must have at least seven characters");
} else if (piped_pair(logpipe)) {
warnx("can't create pipe for log");
@ -287,11 +280,16 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
close_on_exec_on(curdir);
stampcheck = monotonic_sec();
need_rescan = 1;
last_mtime = 0;
for (;;) {
unsigned now;
unsigned sig;
/* collect children */
for (;;) {
pid = wait_any_nohang(&wstat);
pid_t pid = wait_any_nohang(NULL);
if (pid <= 0)
break;
for (i = 0; i < svnum; i++) {
@ -345,15 +343,17 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
}
pfd[0].revents = 0;
#endif
deadline = (need_rescan ? 1 : 5);
sig_block(SIGCHLD);
{
unsigned deadline = (need_rescan ? 1 : 5);
sig_block(SIGCHLD);
#if ENABLE_FEATURE_RUNSVDIR_LOG
if (rplog)
poll(pfd, 1, deadline*1000);
else
if (rplog)
poll(pfd, 1, deadline*1000);
else
#endif
sleep(deadline);
sig_unblock(SIGCHLD);
sleep(deadline);
sig_unblock(SIGCHLD);
}
#if ENABLE_FEATURE_RUNSVDIR_LOG
if (pfd[0].revents & POLLIN) {
@ -361,21 +361,25 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
while (read(logpipe.rd, &ch, 1) > 0) {
if (ch < ' ')
ch = ' ';
for (i = 6; i < rploglen; i++)
for (i = 6; rplog[i] != '\0'; i++)
rplog[i-1] = rplog[i];
rplog[rploglen-1] = ch;
rplog[i-1] = ch;
}
}
#endif
if (!bb_got_signal)
sig = bb_got_signal;
if (!sig)
continue;
bb_got_signal = 0;
/* -s SCRIPT: useful if we are init.
* In this case typically script never returns,
* it halts/powers off/reboots the system. */
if (opt_s_argv[0]) {
pid_t pid;
/* Single parameter: signal# */
opt_s_argv[1] = utoa(bb_got_signal);
opt_s_argv[1] = utoa(sig);
pid = spawn(opt_s_argv);
if (pid > 0) {
/* Remembering to wait for _any_ children,
@ -385,7 +389,7 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
}
}
if (bb_got_signal == SIGHUP) {
if (sig == SIGHUP) {
for (i = 0; i < svnum; i++)
if (sv[i].pid)
kill(sv[i].pid, SIGTERM);
@ -393,9 +397,8 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
/* SIGHUP or SIGTERM (or SIGUSRn if we are init) */
/* Exit unless we are init */
if (getpid() != 1)
return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS;
return (SIGHUP == sig) ? 111 : EXIT_SUCCESS;
/* init continues to monitor services forever */
bb_got_signal = 0;
} /* for (;;) */
}