2 Copyright (c) 2001-2006, Gerrit Pape
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 /* TODO: depends on runit_lib.c - review and reduce/eliminate */
34 #include "runit_lib.h"
36 #define MAXSERVICES 1000
38 /* Should be not needed - all dirs are on same FS, right? */
39 #define CHECK_DEVNO_TOO 0
54 #if ENABLE_FEATURE_RUNSVDIR_LOG
57 struct fd_pair logpipe;
61 smallint need_rescan; /* = 1; */
64 #define G (*(struct globals*)&bb_common_bufsiz1)
66 #define svdir (G.svdir )
67 #define svnum (G.svnum )
68 #define rplog (G.rplog )
69 #define rploglen (G.rploglen )
70 #define logpipe (G.logpipe )
72 #define stamplog (G.stamplog )
73 #define need_rescan (G.need_rescan )
74 #define set_pgrp (G.set_pgrp )
75 #define INIT_G() do { \
79 static void fatal2_cannot(const char *m1, const char *m2)
81 bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
84 static void warn3x(const char *m1, const char *m2, const char *m3)
86 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
88 static void warn2_cannot(const char *m1, const char *m2)
90 warn3x("cannot ", m1, m2);
92 #if ENABLE_FEATURE_RUNSVDIR_LOG
93 static void warnx(const char *m1)
99 static void runsv(int no, const char *name)
104 prog[0] = (char*)"runsv";
105 prog[1] = (char*)name;
111 warn2_cannot("vfork", "");
122 execvp(prog[0], prog);
123 fatal2_cannot("start runsv ", name);
128 static void do_rescan(void)
137 warn2_cannot("open directory ", svdir);
140 for (i = 0; i < svnum; i++)
148 if (d->d_name[0] == '.')
150 if (stat(d->d_name, &s) == -1) {
151 warn2_cannot("stat ", d->d_name);
154 if (!S_ISDIR(s.st_mode))
156 for (i = 0; i < svnum; i++) {
157 if ((sv[i].ino == s.st_ino)
159 && (sv[i].dev == s.st_dev)
170 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
172 warn2_cannot("start runsv ", d->d_name);
177 memset(&sv[i], 0, sizeof(sv[i]));
178 sv[i].ino = s.st_ino;
180 sv[i].dev = s.st_dev;
183 /*sv[i].isgone = 0;*/
191 warn2_cannot("read directory ", svdir);
196 /* Send SIGTERM to runsv whose directories were not found (removed) */
197 for (i = 0; i < svnum; i++) {
201 kill(sv[i].pid, SIGTERM);
204 i--; /* so that we don't skip new sv[i] (bug was here!) */
209 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
210 int runsvdir_main(int argc UNUSED_PARAM, char **argv)
213 dev_t last_dev = last_dev; /* for gcc */
214 ino_t last_ino = last_ino; /* for gcc */
215 time_t last_mtime = 0;
226 opt_complementary = "-1";
227 set_pgrp = getopt32(argv, "P");
230 bb_signals_recursive((1 << SIGTERM) | (1 << SIGHUP), record_signo);
233 #if ENABLE_FEATURE_RUNSVDIR_LOG
237 rploglen = strlen(rplog);
239 warnx("log must have at least seven characters");
240 } else if (piped_pair(logpipe)) {
241 warnx("cannot create pipe for log");
243 close_on_exec_on(logpipe.rd);
244 close_on_exec_on(logpipe.wr);
245 ndelay_on(logpipe.rd);
246 ndelay_on(logpipe.wr);
247 if (dup2(logpipe.wr, 2) == -1) {
248 warnx("cannot set filedescriptor for log");
250 pfd[0].fd = logpipe.rd;
251 pfd[0].events = POLLIN;
252 stamplog = monotonic_sec();
257 warnx("log service disabled");
261 curdir = open_read(".");
263 fatal2_cannot("open current directory", "");
264 close_on_exec_on(curdir);
266 stampcheck = monotonic_sec();
269 /* collect children */
271 pid = wait_any_nohang(&wstat);
274 for (i = 0; i < svnum; i++) {
275 if (pid == sv[i].pid) {
284 now = monotonic_sec();
285 if ((int)(now - stampcheck) >= 0) {
286 /* wait at least a second */
287 stampcheck = now + 1;
289 if (stat(svdir, &s) != -1) {
290 if (need_rescan || s.st_mtime != last_mtime
291 || s.st_ino != last_ino || s.st_dev != last_dev
294 if (chdir(svdir) != -1) {
295 last_mtime = s.st_mtime;
302 while (fchdir(curdir) == -1) {
303 warn2_cannot("change directory, pausing", "");
307 warn2_cannot("change directory to ", svdir);
310 warn2_cannot("stat ", svdir);
313 #if ENABLE_FEATURE_RUNSVDIR_LOG
315 if ((int)(now - stamplog) >= 0) {
316 write(logpipe.wr, ".", 1);
317 stamplog = now + 900;
323 deadline = (need_rescan ? 1 : 5);
324 #if ENABLE_FEATURE_RUNSVDIR_LOG
326 poll(pfd, 1, deadline*1000);
330 sig_unblock(SIGCHLD);
332 #if ENABLE_FEATURE_RUNSVDIR_LOG
333 if (pfd[0].revents & POLLIN) {
335 while (read(logpipe.rd, &ch, 1) > 0) {
337 for (i = 6; i < rploglen; i++)
338 rplog[i-1] = rplog[i];
339 rplog[rploglen-1] = ch;
344 switch (bb_got_signal) {
346 for (i = 0; i < svnum; i++)
348 kill(sv[i].pid, SIGTERM);
351 _exit((SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS);