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
51 struct fd_pair logpipe;
54 smallint check; /* = 1; */
57 #define G (*(struct globals*)&bb_common_bufsiz1)
59 #define svdir (G.svdir )
60 #define rplog (G.rplog )
61 #define svnum (G.svnum )
62 #define rploglen (G.rploglen )
63 #define logpipe (G.logpipe )
65 #define stamplog (G.stamplog )
66 #define check (G.check )
67 #define set_pgrp (G.set_pgrp )
68 #define INIT_G() do { \
72 static void fatal2_cannot(const char *m1, const char *m2)
74 bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
77 static void warn3x(const char *m1, const char *m2, const char *m3)
79 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
81 static void warn2_cannot(const char *m1, const char *m2)
83 warn3x("cannot ", m1, m2);
85 static void warnx(const char *m1)
90 static void runsv(int no, const char *name)
95 prog[0] = (char*)"runsv";
96 prog[1] = (char*)name;
102 warn2_cannot("vfork", "");
113 execvp(prog[0], prog);
114 fatal2_cannot("start runsv ", name);
119 static void runsvdir(void)
128 warn2_cannot("open directory ", svdir);
131 for (i = 0; i < svnum; i++)
139 if (d->d_name[0] == '.')
141 if (stat(d->d_name, &s) == -1) {
142 warn2_cannot("stat ", d->d_name);
146 if (!S_ISDIR(s.st_mode))
148 for (i = 0; i < svnum; i++) {
149 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
158 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
160 warn3x("cannot start runsv ", d->d_name,
161 " too many services");
166 memset(&sv[i], 0, sizeof(sv[i]));
167 sv[i].ino = s.st_ino;
168 sv[i].dev = s.st_dev;
170 /*sv[i].isgone = 0;*/
176 warn2_cannot("read directory ", svdir);
183 /* SIGTERM removed runsv's */
184 for (i = 0; i < svnum; i++) {
188 kill(sv[i].pid, SIGTERM);
190 /* BUG? we deleted sv[i] by copying over sv[last], but we will not check this newly-copied one! */
195 static int setup_log(void)
197 rploglen = strlen(rplog);
199 warnx("log must have at least seven characters");
202 if (piped_pair(logpipe)) {
203 warnx("cannot create pipe for log");
206 close_on_exec_on(logpipe.rd);
207 close_on_exec_on(logpipe.wr);
208 ndelay_on(logpipe.rd);
209 ndelay_on(logpipe.wr);
210 if (dup2(logpipe.wr, 2) == -1) {
211 warnx("cannot set filedescriptor for log");
214 pfd[0].fd = logpipe.rd;
215 pfd[0].events = POLLIN;
216 stamplog = monotonic_sec();
220 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
221 int runsvdir_main(int argc UNUSED_PARAM, char **argv)
224 dev_t last_dev = last_dev; /* for gcc */
225 ino_t last_ino = last_ino; /* for gcc */
226 time_t last_mtime = 0;
238 opt_complementary = "-1";
239 set_pgrp = getopt32(argv, "P");
242 bb_signals_recursive((1 << SIGTERM) | (1 << SIGHUP), record_signo);
246 if (setup_log() != 1) {
248 warnx("log service disabled");
251 curdir = open_read(".");
253 fatal2_cannot("open current directory", "");
254 close_on_exec_on(curdir);
256 stampcheck = monotonic_sec();
259 /* collect children */
261 pid = wait_any_nohang(&wstat);
264 for (i = 0; i < svnum; i++) {
265 if (pid == sv[i].pid) {
274 now = monotonic_sec();
275 if ((int)(now - stampcheck) >= 0) {
276 /* wait at least a second */
277 stampcheck = now + 1;
279 if (stat(svdir, &s) != -1) {
280 if (check || s.st_mtime != last_mtime
281 || s.st_ino != last_ino || s.st_dev != last_dev
284 if (chdir(svdir) != -1) {
285 last_mtime = s.st_mtime;
292 while (fchdir(curdir) == -1) {
293 warn2_cannot("change directory, pausing", "");
297 warn2_cannot("change directory to ", svdir);
300 warn2_cannot("stat ", svdir);
304 if ((int)(now - stamplog) >= 0) {
305 write(logpipe.wr, ".", 1);
306 stamplog = now + 900;
312 deadline = (check ? 1 : 5);
314 poll(pfd, 1, deadline*1000);
317 sig_unblock(SIGCHLD);
319 if (pfd[0].revents & POLLIN) {
320 while (read(logpipe.rd, &ch, 1) > 0) {
322 for (i = 6; i < rploglen; i++)
323 rplog[i-1] = rplog[i];
324 rplog[rploglen-1] = ch;
329 switch (bb_got_signal) {
331 for (i = 0; i < svnum; i++)
333 kill(sv[i].pid, SIGTERM);
336 _exit((SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS);