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++)
145 while ((d = readdir(dir))) {
146 if (d->d_name[0] == '.')
148 if (stat(d->d_name, &s) == -1) {
149 warn2_cannot("stat ", d->d_name);
153 if (!S_ISDIR(s.st_mode))
155 for (i = 0; i < svnum; i++) {
156 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
165 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
167 warn3x("cannot start runsv ", d->d_name,
168 " too many services");
173 memset(&sv[i], 0, sizeof(sv[i]));
174 sv[i].ino = s.st_ino;
175 sv[i].dev = s.st_dev;
177 /*sv[i].isgone = 0;*/
183 warn2_cannot("read directory ", svdir);
190 /* SIGTERM removed runsv's */
191 for (i = 0; i < svnum; i++) {
195 kill(sv[i].pid, SIGTERM);
201 static int setup_log(void)
203 rploglen = strlen(rplog);
205 warnx("log must have at least seven characters");
208 if (piped_pair(logpipe)) {
209 warnx("cannot create pipe for log");
212 close_on_exec_on(logpipe.rd);
213 close_on_exec_on(logpipe.wr);
214 ndelay_on(logpipe.rd);
215 ndelay_on(logpipe.wr);
216 if (dup2(logpipe.wr, 2) == -1) {
217 warnx("cannot set filedescriptor for log");
220 pfd[0].fd = logpipe.rd;
221 pfd[0].events = POLLIN;
222 stamplog = monotonic_sec();
226 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
227 int runsvdir_main(int argc ATTRIBUTE_UNUSED, char **argv)
230 dev_t last_dev = last_dev; /* for gcc */
231 ino_t last_ino = last_ino; /* for gcc */
232 time_t last_mtime = 0;
247 if (argv[0][0] == '-') {
248 switch (argv[0][1]) {
249 case 'P': set_pgrp = 1;
256 bb_signals_recursive(1 << SIGTERM, s_term);
257 bb_signals_recursive(1 << SIGHUP, s_hangup);
261 if (setup_log() != 1) {
263 warnx("log service disabled");
266 curdir = open_read(".");
268 fatal2_cannot("open current directory", "");
269 close_on_exec_on(curdir);
271 stampcheck = monotonic_sec();
274 /* collect children */
276 pid = wait_any_nohang(&wstat);
279 for (i = 0; i < svnum; i++) {
280 if (pid == sv[i].pid) {
289 now = monotonic_sec();
290 if ((int)(now - stampcheck) >= 0) {
291 /* wait at least a second */
292 stampcheck = now + 1;
294 if (stat(svdir, &s) != -1) {
295 if (check || s.st_mtime != last_mtime
296 || s.st_ino != last_ino || s.st_dev != last_dev
299 if (chdir(svdir) != -1) {
300 last_mtime = s.st_mtime;
307 while (fchdir(curdir) == -1) {
308 warn2_cannot("change directory, pausing", "");
312 warn2_cannot("change directory to ", svdir);
315 warn2_cannot("stat ", svdir);
319 if ((int)(now - stamplog) >= 0) {
320 write(logpipe.wr, ".", 1);
321 stamplog = now + 900;
327 deadline = (check ? 1 : 5);
329 poll(pfd, 1, deadline*1000);
332 sig_unblock(SIGCHLD);
334 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;
348 for (i = 0; i < svnum; i++)
350 kill(sv[i].pid, SIGTERM);