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
45 static struct service *sv;
50 static struct fd_pair logpipe;
51 static struct pollfd pfd[1];
52 static unsigned stamplog;
53 static smallint check = 1;
54 static smallint exitsoon;
55 static smallint set_pgrp;
57 static void fatal2_cannot(const char *m1, const char *m2)
59 bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
62 static void warn3x(const char *m1, const char *m2, const char *m3)
64 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
66 static void warn2_cannot(const char *m1, const char *m2)
68 warn3x("cannot ", m1, m2);
70 static void warnx(const char *m1)
75 static void s_term(int sig_no)
79 static void s_hangup(int sig_no)
84 static void runsv(int no, const char *name)
89 prog[0] = (char*)"runsv";
90 prog[1] = (char*)name;
96 warn2_cannot("vfork", "");
107 execvp(prog[0], prog);
108 fatal2_cannot("start runsv ", name);
113 static void runsvdir(void)
122 warn2_cannot("open directory ", svdir);
125 for (i = 0; i < svnum; i++)
128 while ((d = readdir(dir))) {
129 if (d->d_name[0] == '.')
131 if (stat(d->d_name, &s) == -1) {
132 warn2_cannot("stat ", d->d_name);
136 if (!S_ISDIR(s.st_mode))
138 for (i = 0; i < svnum; i++) {
139 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
148 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
150 warn3x("cannot start runsv ", d->d_name,
151 " too many services");
156 memset(&sv[i], 0, sizeof(sv[i]));
157 sv[i].ino = s.st_ino;
158 sv[i].dev = s.st_dev;
160 /*sv[i].isgone = 0;*/
166 warn2_cannot("read directory ", svdir);
173 /* SIGTERM removed runsv's */
174 for (i = 0; i < svnum; i++) {
178 kill(sv[i].pid, SIGTERM);
184 static int setup_log(void)
186 rploglen = strlen(rplog);
188 warnx("log must have at least seven characters");
191 if (piped_pair(logpipe)) {
192 warnx("cannot create pipe for log");
195 close_on_exec_on(logpipe.rd);
196 close_on_exec_on(logpipe.wr);
197 ndelay_on(logpipe.rd);
198 ndelay_on(logpipe.wr);
199 if (dup2(logpipe.wr, 2) == -1) {
200 warnx("cannot set filedescriptor for log");
203 pfd[0].fd = logpipe.rd;
204 pfd[0].events = POLLIN;
205 stamplog = monotonic_sec();
209 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
210 int runsvdir_main(int argc, 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;
228 if (argv[0][0] == '-') {
229 switch (argv[0][1]) {
230 case 'P': set_pgrp = 1;
237 bb_signals_recursive(1 << SIGTERM, s_term);
238 bb_signals_recursive(1 << SIGHUP, s_hangup);
242 if (setup_log() != 1) {
244 warnx("log service disabled");
247 curdir = open_read(".");
249 fatal2_cannot("open current directory", "");
250 close_on_exec_on(curdir);
252 stampcheck = monotonic_sec();
255 /* collect children */
257 pid = wait_any_nohang(&wstat);
260 for (i = 0; i < svnum; i++) {
261 if (pid == sv[i].pid) {
270 now = monotonic_sec();
271 if ((int)(now - stampcheck) >= 0) {
272 /* wait at least a second */
273 stampcheck = now + 1;
275 if (stat(svdir, &s) != -1) {
276 if (check || s.st_mtime != last_mtime
277 || s.st_ino != last_ino || s.st_dev != last_dev
280 if (chdir(svdir) != -1) {
281 last_mtime = s.st_mtime;
288 while (fchdir(curdir) == -1) {
289 warn2_cannot("change directory, pausing", "");
293 warn2_cannot("change directory to ", svdir);
296 warn2_cannot("stat ", svdir);
300 if ((int)(now - stamplog) >= 0) {
301 write(logpipe.wr, ".", 1);
302 stamplog = now + 900;
308 deadline = (check ? 1 : 5);
310 poll(pfd, 1, deadline*1000);
313 sig_unblock(SIGCHLD);
315 if (pfd[0].revents & POLLIN) {
316 while (read(logpipe.rd, &ch, 1) > 0) {
318 for (i = 6; i < rploglen; i++)
319 rplog[i-1] = rplog[i];
320 rplog[rploglen-1] = ch;
329 for (i = 0; i < svnum; i++)
331 kill(sv[i].pid, SIGTERM);