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; */
58 #define G (*(struct globals*)&bb_common_bufsiz1)
60 #define svdir (G.svdir )
61 #define rplog (G.rplog )
62 #define svnum (G.svnum )
63 #define rploglen (G.rploglen )
64 #define logpipe (G.logpipe )
66 #define stamplog (G.stamplog )
67 #define check (G.check )
68 #define exitsoon (G.exitsoon )
69 #define set_pgrp (G.set_pgrp )
70 #define INIT_G() do { \
74 static void fatal2_cannot(const char *m1, const char *m2)
76 bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
79 static void warn3x(const char *m1, const char *m2, const char *m3)
81 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
83 static void warn2_cannot(const char *m1, const char *m2)
85 warn3x("cannot ", m1, m2);
87 static void warnx(const char *m1)
92 static void s_term(int sig_no ATTRIBUTE_UNUSED)
96 static void s_hangup(int sig_no ATTRIBUTE_UNUSED)
101 static void runsv(int no, const char *name)
106 prog[0] = (char*)"runsv";
107 prog[1] = (char*)name;
113 warn2_cannot("vfork", "");
124 execvp(prog[0], prog);
125 fatal2_cannot("start runsv ", name);
130 static void runsvdir(void)
139 warn2_cannot("open directory ", svdir);
142 for (i = 0; i < svnum; i++)
150 if (d->d_name[0] == '.')
152 if (stat(d->d_name, &s) == -1) {
153 warn2_cannot("stat ", d->d_name);
157 if (!S_ISDIR(s.st_mode))
159 for (i = 0; i < svnum; i++) {
160 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
169 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
171 warn3x("cannot start runsv ", d->d_name,
172 " too many services");
177 memset(&sv[i], 0, sizeof(sv[i]));
178 sv[i].ino = s.st_ino;
179 sv[i].dev = s.st_dev;
181 /*sv[i].isgone = 0;*/
187 warn2_cannot("read directory ", svdir);
194 /* SIGTERM removed runsv's */
195 for (i = 0; i < svnum; i++) {
199 kill(sv[i].pid, SIGTERM);
201 /* BUG? we deleted sv[i] by copying over sv[last], but we will not check this newly-copied one! */
206 static int setup_log(void)
208 rploglen = strlen(rplog);
210 warnx("log must have at least seven characters");
213 if (piped_pair(logpipe)) {
214 warnx("cannot create pipe for log");
217 close_on_exec_on(logpipe.rd);
218 close_on_exec_on(logpipe.wr);
219 ndelay_on(logpipe.rd);
220 ndelay_on(logpipe.wr);
221 if (dup2(logpipe.wr, 2) == -1) {
222 warnx("cannot set filedescriptor for log");
225 pfd[0].fd = logpipe.rd;
226 pfd[0].events = POLLIN;
227 stamplog = monotonic_sec();
231 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
232 int runsvdir_main(int argc ATTRIBUTE_UNUSED, char **argv)
235 dev_t last_dev = last_dev; /* for gcc */
236 ino_t last_ino = last_ino; /* for gcc */
237 time_t last_mtime = 0;
252 if (argv[0][0] == '-') {
253 switch (argv[0][1]) {
254 case 'P': set_pgrp = 1;
261 bb_signals_recursive(1 << SIGTERM, s_term);
262 bb_signals_recursive(1 << SIGHUP, s_hangup);
266 if (setup_log() != 1) {
268 warnx("log service disabled");
271 curdir = open_read(".");
273 fatal2_cannot("open current directory", "");
274 close_on_exec_on(curdir);
276 stampcheck = monotonic_sec();
279 /* collect children */
281 pid = wait_any_nohang(&wstat);
284 for (i = 0; i < svnum; i++) {
285 if (pid == sv[i].pid) {
294 now = monotonic_sec();
295 if ((int)(now - stampcheck) >= 0) {
296 /* wait at least a second */
297 stampcheck = now + 1;
299 if (stat(svdir, &s) != -1) {
300 if (check || s.st_mtime != last_mtime
301 || s.st_ino != last_ino || s.st_dev != last_dev
304 if (chdir(svdir) != -1) {
305 last_mtime = s.st_mtime;
312 while (fchdir(curdir) == -1) {
313 warn2_cannot("change directory, pausing", "");
317 warn2_cannot("change directory to ", svdir);
320 warn2_cannot("stat ", svdir);
324 if ((int)(now - stamplog) >= 0) {
325 write(logpipe.wr, ".", 1);
326 stamplog = now + 900;
332 deadline = (check ? 1 : 5);
334 poll(pfd, 1, deadline*1000);
337 sig_unblock(SIGCHLD);
339 if (pfd[0].revents & POLLIN) {
340 while (read(logpipe.rd, &ch, 1) > 0) {
342 for (i = 6; i < rploglen; i++)
343 rplog[i-1] = rplog[i];
344 rplog[rploglen-1] = ch;
353 for (i = 0; i < svnum; i++)
355 kill(sv[i].pid, SIGTERM);