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 Denis 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 int logpipe[2];
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", "");
103 signal(SIGHUP, SIG_DFL);
104 signal(SIGTERM, SIG_DFL);
105 execvp(prog[0], prog);
106 fatal2_cannot("start runsv ", name);
111 static void runsvdir(void)
120 warn2_cannot("open directory ", svdir);
123 for (i = 0; i < svnum; i++)
126 while ((d = readdir(dir))) {
127 if (d->d_name[0] == '.')
129 if (stat(d->d_name, &s) == -1) {
130 warn2_cannot("stat ", d->d_name);
134 if (!S_ISDIR(s.st_mode))
136 for (i = 0; i < svnum; i++) {
137 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
146 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
148 warn3x("cannot start runsv ", d->d_name,
149 " too many services");
154 memset(&sv[i], 0, sizeof(sv[i]));
155 sv[i].ino = s.st_ino;
156 sv[i].dev = s.st_dev;
158 /*sv[i].isgone = 0;*/
164 warn2_cannot("read directory ", svdir);
171 /* SIGTERM removed runsv's */
172 for (i = 0; i < svnum; i++) {
176 kill(sv[i].pid, SIGTERM);
182 static int setup_log(void)
184 rploglen = strlen(rplog);
186 warnx("log must have at least seven characters");
190 warnx("cannot create pipe for log");
193 close_on_exec_on(logpipe[1]);
194 close_on_exec_on(logpipe[0]);
195 ndelay_on(logpipe[0]);
196 ndelay_on(logpipe[1]);
197 if (dup2(logpipe[1], 2) == -1) {
198 warnx("cannot set filedescriptor for log");
201 pfd[0].fd = logpipe[0];
202 pfd[0].events = POLLIN;
203 stamplog = monotonic_sec();
207 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
208 int runsvdir_main(int argc, char **argv)
211 dev_t last_dev = last_dev; /* for gcc */
212 ino_t last_ino = last_ino; /* for gcc */
213 time_t last_mtime = 0;
226 if (argv[0][0] == '-') {
227 switch (argv[0][1]) {
228 case 'P': set_pgrp = 1;
235 sig_catch(SIGTERM, s_term);
236 sig_catch(SIGHUP, s_hangup);
240 if (setup_log() != 1) {
242 warnx("log service disabled");
245 curdir = open_read(".");
247 fatal2_cannot("open current directory", "");
248 close_on_exec_on(curdir);
250 stampcheck = monotonic_sec();
253 /* collect children */
255 pid = wait_nohang(&wstat);
258 for (i = 0; i < svnum; i++) {
259 if (pid == sv[i].pid) {
268 now = monotonic_sec();
269 if ((int)(now - stampcheck) >= 0) {
270 /* wait at least a second */
271 stampcheck = now + 1;
273 if (stat(svdir, &s) != -1) {
274 if (check || s.st_mtime != last_mtime
275 || s.st_ino != last_ino || s.st_dev != last_dev
278 if (chdir(svdir) != -1) {
279 last_mtime = s.st_mtime;
286 while (fchdir(curdir) == -1) {
287 warn2_cannot("change directory, pausing", "");
291 warn2_cannot("change directory to ", svdir);
294 warn2_cannot("stat ", svdir);
298 if ((int)(now - stamplog) >= 0) {
299 write(logpipe[1], ".", 1);
300 stamplog = now + 900;
306 deadline = (check ? 1 : 5);
308 poll(pfd, 1, deadline*1000);
311 sig_unblock(SIGCHLD);
313 if (pfd[0].revents & POLLIN) {
314 while (read(logpipe[0], &ch, 1) > 0) {
316 for (i = 6; i < rploglen; i++)
317 rplog[i-1] = rplog[i];
318 rplog[rploglen-1] = ch;
327 for (i = 0; i < svnum; i++)
329 kill(sv[i].pid, SIGTERM);