blob: 2b7927542aeb37725b9af933ead0532451636a9f [file] [log] [blame]
Denis Vlasenko8a164052007-03-12 23:34:52 +00001/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
Denis Vlasenkod18f52b2008-03-02 12:53:15 +000028/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
Denys Vlasenko0863e1a2015-10-19 00:41:28 +020029
30//config:config RUNSVDIR
31//config: bool "runsvdir"
32//config: default y
33//config: help
34//config: runsvdir starts a runsv process for each subdirectory, or symlink to
35//config: a directory, in the services directory dir, up to a limit of 1000
36//config: subdirectories, and restarts a runsv process if it terminates.
37//config:
38//config:config FEATURE_RUNSVDIR_LOG
39//config: bool "Enable scrolling argument log"
40//config: depends on RUNSVDIR
41//config: default n
42//config: help
43//config: Enable feature where second parameter of runsvdir holds last error
44//config: message (viewable via top/ps). Otherwise (feature is off
45//config: or no parameter), error messages go to stderr only.
46
47//applet:IF_RUNSVDIR(APPLET(runsvdir, BB_DIR_USR_BIN, BB_SUID_DROP))
48
49//kbuild:lib-$(CONFIG_RUNSVDIR) += runsvdir.o
Denis Vlasenko04c63862006-11-17 18:58:49 +000050
Pere Orga5bc8c002011-04-11 03:29:49 +020051//usage:#define runsvdir_trivial_usage
52//usage: "[-P] [-s SCRIPT] DIR"
53//usage:#define runsvdir_full_usage "\n\n"
54//usage: "Start a runsv process for each subdirectory. If it exits, restart it.\n"
55//usage: "\n -P Put each runsv in a new session"
56//usage: "\n -s SCRIPT Run SCRIPT <signo> after signal is processed"
57
Denis Vlasenko04c63862006-11-17 18:58:49 +000058#include <sys/file.h>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000059#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020060#include "common_bufsiz.h"
Denis Vlasenko04c63862006-11-17 18:58:49 +000061#include "runit_lib.h"
62
63#define MAXSERVICES 1000
64
Denis Vlasenko923a79a2008-09-22 21:34:24 +000065/* Should be not needed - all dirs are on same FS, right? */
66#define CHECK_DEVNO_TOO 0
67
Denis Vlasenko45946f82007-08-20 17:27:40 +000068struct service {
Denis Vlasenko923a79a2008-09-22 21:34:24 +000069#if CHECK_DEVNO_TOO
Denis Vlasenko45946f82007-08-20 17:27:40 +000070 dev_t dev;
Denis Vlasenko923a79a2008-09-22 21:34:24 +000071#endif
Denis Vlasenko45946f82007-08-20 17:27:40 +000072 ino_t ino;
73 pid_t pid;
74 smallint isgone;
75};
76
Denis Vlasenkod0a071a2008-03-17 09:33:45 +000077struct globals {
78 struct service *sv;
79 char *svdir;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +000080 int svnum;
Denis Vlasenko923a79a2008-09-22 21:34:24 +000081#if ENABLE_FEATURE_RUNSVDIR_LOG
82 char *rplog;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +000083 struct fd_pair logpipe;
84 struct pollfd pfd[1];
85 unsigned stamplog;
Denis Vlasenko923a79a2008-09-22 21:34:24 +000086#endif
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +010087} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020088#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko923a79a2008-09-22 21:34:24 +000089#define sv (G.sv )
90#define svdir (G.svdir )
91#define svnum (G.svnum )
92#define rplog (G.rplog )
Denis Vlasenko923a79a2008-09-22 21:34:24 +000093#define logpipe (G.logpipe )
94#define pfd (G.pfd )
95#define stamplog (G.stamplog )
Denys Vlasenko47cfbf32016-04-21 18:18:48 +020096#define INIT_G() do { setup_common_bufsiz(); } while (0)
Denis Vlasenko04c63862006-11-17 18:58:49 +000097
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000098static void fatal2_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +000099{
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100100 bb_perror_msg_and_die("%s: fatal: can't %s%s", svdir, m1, m2);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000101 /* was exiting 100 */
102}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000103static void warn3x(const char *m1, const char *m2, const char *m3)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000104{
105 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000106}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000107static void warn2_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000108{
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100109 warn3x("can't ", m1, m2);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000110}
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000111#if ENABLE_FEATURE_RUNSVDIR_LOG
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000112static void warnx(const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000113{
114 warn3x(m1, "", "");
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000115}
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000116#endif
Denis Vlasenko04c63862006-11-17 18:58:49 +0000117
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000118/* inlining + vfork -> bigger code */
119static NOINLINE pid_t runsv(const char *name)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000120{
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000121 pid_t pid;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000122
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000123 /* If we got signaled, stop spawning children at once! */
124 if (bb_got_signal)
125 return 0;
126
127 pid = vfork();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000128 if (pid == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000129 warn2_cannot("vfork", "");
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000130 return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000131 }
132 if (pid == 0) {
133 /* child */
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000134 if (option_mask32 & 1) /* -P option? */
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000135 setsid();
Denis Vlasenko96575962008-10-29 03:42:44 +0000136/* man execv:
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000137 * "Signals set to be caught by the calling process image
138 * shall be set to the default action in the new process image."
Denis Vlasenko96575962008-10-29 03:42:44 +0000139 * Therefore, we do not need this: */
140#if 0
Denis Vlasenko25591c32008-02-16 22:58:56 +0000141 bb_signals(0
Denis Vlasenko96575962008-10-29 03:42:44 +0000142 | (1 << SIGHUP)
143 | (1 << SIGTERM)
Denis Vlasenko25591c32008-02-16 22:58:56 +0000144 , SIG_DFL);
Denis Vlasenko96575962008-10-29 03:42:44 +0000145#endif
Denis Vlasenkof09f4e02009-02-26 12:29:59 +0000146 execlp("runsv", "runsv", name, (char *) NULL);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000147 fatal2_cannot("start runsv ", name);
148 }
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000149 return pid;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000150}
151
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000152/* gcc 4.3.0 does better with NOINLINE */
153static NOINLINE int do_rescan(void)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000154{
155 DIR *dir;
Denys Vlasenkoaebb7422009-08-02 00:55:49 +0200156 struct dirent *d;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000157 int i;
158 struct stat s;
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000159 int need_rescan = 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000160
161 dir = opendir(".");
162 if (!dir) {
163 warn2_cannot("open directory ", svdir);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000164 return 1; /* need to rescan again soon */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000165 }
166 for (i = 0; i < svnum; i++)
167 sv[i].isgone = 1;
Denis Vlasenko8f740942008-05-31 07:00:33 +0000168
169 while (1) {
170 errno = 0;
171 d = readdir(dir);
172 if (!d)
173 break;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000174 if (d->d_name[0] == '.')
175 continue;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000176 if (stat(d->d_name, &s) == -1) {
177 warn2_cannot("stat ", d->d_name);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000178 continue;
179 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000180 if (!S_ISDIR(s.st_mode))
181 continue;
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000182 /* Do we have this service listed already? */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000183 for (i = 0; i < svnum; i++) {
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000184 if ((sv[i].ino == s.st_ino)
185#if CHECK_DEVNO_TOO
186 && (sv[i].dev == s.st_dev)
187#endif
188 ) {
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000189 if (sv[i].pid == 0) /* restart if it has died */
190 goto run_ith_sv;
191 sv[i].isgone = 0; /* "we still see you" */
192 goto next_dentry;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000193 }
194 }
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000195 { /* Not found, make new service */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000196 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
197 if (!svnew) {
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000198 warn2_cannot("start runsv ", d->d_name);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000199 need_rescan = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000200 continue;
201 }
202 sv = svnew;
203 svnum++;
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000204#if CHECK_DEVNO_TOO
Denis Vlasenko04c63862006-11-17 18:58:49 +0000205 sv[i].dev = s.st_dev;
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000206#endif
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000207 sv[i].ino = s.st_ino;
208 run_ith_sv:
209 sv[i].pid = runsv(d->d_name);
210 sv[i].isgone = 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000211 }
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000212 next_dentry: ;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000213 }
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000214 i = errno;
215 closedir(dir);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000216 if (i) { /* readdir failed */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000217 warn2_cannot("read directory ", svdir);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000218 return 1; /* need to rescan again soon */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000219 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000220
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000221 /* Send SIGTERM to runsv whose directories
222 * were no longer found (-> must have been removed) */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000223 for (i = 0; i < svnum; i++) {
224 if (!sv[i].isgone)
225 continue;
226 if (sv[i].pid)
227 kill(sv[i].pid, SIGTERM);
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000228 svnum--;
229 sv[i] = sv[svnum];
230 i--; /* so that we don't skip new sv[i] (bug was here!) */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000231 }
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000232 return need_rescan;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000233}
234
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000235int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000236int runsvdir_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000237{
238 struct stat s;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000239 dev_t last_dev = last_dev; /* for gcc */
240 ino_t last_ino = last_ino; /* for gcc */
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100241 time_t last_mtime;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000242 int curdir;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000243 unsigned stampcheck;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000244 int i;
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100245 int need_rescan;
Denys Vlasenko7db2a7c2015-03-02 17:39:13 +0100246 bool i_am_init;
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000247 char *opt_s_argv[3];
Denis Vlasenko04c63862006-11-17 18:58:49 +0000248
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000249 INIT_G();
250
Denis Vlasenko08ea11a2008-09-11 19:51:11 +0000251 opt_complementary = "-1";
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000252 opt_s_argv[0] = NULL;
253 opt_s_argv[2] = NULL;
254 getopt32(argv, "Ps:", &opt_s_argv[0]);
Denis Vlasenko08ea11a2008-09-11 19:51:11 +0000255 argv += optind;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000256
Denys Vlasenko7db2a7c2015-03-02 17:39:13 +0100257 i_am_init = (getpid() == 1);
Denis Vlasenko96575962008-10-29 03:42:44 +0000258 bb_signals(0
259 | (1 << SIGTERM)
260 | (1 << SIGHUP)
261 /* For busybox's init, SIGTERM == reboot,
Denys Vlasenko7db2a7c2015-03-02 17:39:13 +0100262 * SIGUSR1 == halt,
263 * SIGUSR2 == poweroff,
264 * Ctlr-ALt-Del sends SIGINT to init,
265 * so we need to intercept SIGUSRn and SIGINT too.
Denis Vlasenko96575962008-10-29 03:42:44 +0000266 * Note that we do not implement actual reboot
267 * (killall(TERM) + umount, etc), we just pause
268 * respawing and avoid exiting (-> making kernel oops).
Denys Vlasenko7db2a7c2015-03-02 17:39:13 +0100269 * The user is responsible for the rest.
270 */
271 | (i_am_init ? ((1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGINT)) : 0)
Denis Vlasenko96575962008-10-29 03:42:44 +0000272 , record_signo);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000273 svdir = *argv++;
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000274
275#if ENABLE_FEATURE_RUNSVDIR_LOG
276 /* setup log */
277 if (*argv) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000278 rplog = *argv;
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100279 if (strlen(rplog) < 7) {
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000280 warnx("log must have at least seven characters");
281 } else if (piped_pair(logpipe)) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100282 warnx("can't create pipe for log");
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000283 } else {
284 close_on_exec_on(logpipe.rd);
285 close_on_exec_on(logpipe.wr);
286 ndelay_on(logpipe.rd);
287 ndelay_on(logpipe.wr);
288 if (dup2(logpipe.wr, 2) == -1) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100289 warnx("can't set filedescriptor for log");
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000290 } else {
291 pfd[0].fd = logpipe.rd;
292 pfd[0].events = POLLIN;
293 stamplog = monotonic_sec();
294 goto run;
295 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000296 }
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000297 rplog = NULL;
298 warnx("log service disabled");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000299 }
Denis Vlasenko96575962008-10-29 03:42:44 +0000300 run:
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000301#endif
Denys Vlasenko05e86052010-10-13 12:53:27 +0200302 curdir = open(".", O_RDONLY|O_NDELAY);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000303 if (curdir == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000304 fatal2_cannot("open current directory", "");
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000305 close_on_exec_on(curdir);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000306
Denis Vlasenko45946f82007-08-20 17:27:40 +0000307 stampcheck = monotonic_sec();
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100308 need_rescan = 1;
309 last_mtime = 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000310
311 for (;;) {
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100312 unsigned now;
313 unsigned sig;
314
Denis Vlasenko04c63862006-11-17 18:58:49 +0000315 /* collect children */
316 for (;;) {
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100317 pid_t pid = wait_any_nohang(NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000318 if (pid <= 0)
319 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000320 for (i = 0; i < svnum; i++) {
321 if (pid == sv[i].pid) {
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000322 /* runsv has died */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000323 sv[i].pid = 0;
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000324 need_rescan = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000325 }
326 }
327 }
328
Denis Vlasenko45946f82007-08-20 17:27:40 +0000329 now = monotonic_sec();
330 if ((int)(now - stampcheck) >= 0) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000331 /* wait at least a second */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000332 stampcheck = now + 1;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000333
Denis Vlasenko04c63862006-11-17 18:58:49 +0000334 if (stat(svdir, &s) != -1) {
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000335 if (need_rescan || s.st_mtime != last_mtime
Denis Vlasenko45946f82007-08-20 17:27:40 +0000336 || s.st_ino != last_ino || s.st_dev != last_dev
Denis Vlasenko04c63862006-11-17 18:58:49 +0000337 ) {
338 /* svdir modified */
339 if (chdir(svdir) != -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000340 last_mtime = s.st_mtime;
341 last_dev = s.st_dev;
342 last_ino = s.st_ino;
Eric Lammerts31905f92010-12-06 01:26:26 +0100343 /* if the svdir changed this very second, wait until the
344 * next second, because we won't be able to detect more
345 * changes within this second */
346 while (time(NULL) == last_mtime)
347 usleep(100000);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000348 need_rescan = do_rescan();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000349 while (fchdir(curdir) == -1) {
350 warn2_cannot("change directory, pausing", "");
351 sleep(5);
352 }
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000353 } else {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000354 warn2_cannot("change directory to ", svdir);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000355 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000356 }
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000357 } else {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000358 warn2_cannot("stat ", svdir);
Denis Vlasenko6a2c2cf2008-10-29 12:04:45 +0000359 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000360 }
361
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000362#if ENABLE_FEATURE_RUNSVDIR_LOG
Denis Vlasenko04c63862006-11-17 18:58:49 +0000363 if (rplog) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000364 if ((int)(now - stamplog) >= 0) {
Denis Vlasenko37188322008-02-16 13:20:56 +0000365 write(logpipe.wr, ".", 1);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000366 stamplog = now + 900;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000367 }
368 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000369 pfd[0].revents = 0;
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000370#endif
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100371 {
372 unsigned deadline = (need_rescan ? 1 : 5);
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000373#if ENABLE_FEATURE_RUNSVDIR_LOG
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100374 if (rplog)
375 poll(pfd, 1, deadline*1000);
376 else
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000377#endif
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100378 sleep(deadline);
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100379 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000380
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000381#if ENABLE_FEATURE_RUNSVDIR_LOG
Denis Vlasenko45946f82007-08-20 17:27:40 +0000382 if (pfd[0].revents & POLLIN) {
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000383 char ch;
Denis Vlasenko37188322008-02-16 13:20:56 +0000384 while (read(logpipe.rd, &ch, 1) > 0) {
Denis Vlasenko96575962008-10-29 03:42:44 +0000385 if (ch < ' ')
386 ch = ' ';
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100387 for (i = 6; rplog[i] != '\0'; i++)
Denis Vlasenko96575962008-10-29 03:42:44 +0000388 rplog[i-1] = rplog[i];
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100389 rplog[i-1] = ch;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000390 }
391 }
Denis Vlasenko923a79a2008-09-22 21:34:24 +0000392#endif
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100393 sig = bb_got_signal;
394 if (!sig)
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000395 continue;
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100396 bb_got_signal = 0;
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000397
398 /* -s SCRIPT: useful if we are init.
399 * In this case typically script never returns,
400 * it halts/powers off/reboots the system. */
401 if (opt_s_argv[0]) {
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100402 pid_t pid;
403
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000404 /* Single parameter: signal# */
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100405 opt_s_argv[1] = utoa(sig);
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000406 pid = spawn(opt_s_argv);
407 if (pid > 0) {
Denis Vlasenko93b38202009-02-14 20:58:13 +0000408 /* Remembering to wait for _any_ children,
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000409 * not just pid */
410 while (wait(NULL) != pid)
411 continue;
412 }
413 }
414
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100415 if (sig == SIGHUP) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000416 for (i = 0; i < svnum; i++)
417 if (sv[i].pid)
418 kill(sv[i].pid, SIGTERM);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000419 }
Denis Vlasenko3b35fbb2008-11-11 09:33:24 +0000420 /* SIGHUP or SIGTERM (or SIGUSRn if we are init) */
421 /* Exit unless we are init */
Denys Vlasenko7db2a7c2015-03-02 17:39:13 +0100422 if (!i_am_init)
Denys Vlasenkofa535f32015-03-02 17:37:31 +0100423 return (SIGHUP == sig) ? 111 : EXIT_SUCCESS;
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000424
Denis Vlasenko3b35fbb2008-11-11 09:33:24 +0000425 /* init continues to monitor services forever */
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000426 } /* for (;;) */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000427}