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
39 static unsigned long dev;
40 static unsigned long ino;
41 static struct service {
51 static int logpipe[2];
52 static iopause_fd io[1];
53 static struct taia stamplog;
57 #define usage() bb_show_usage()
58 static void fatal2_cannot(const char *m1, const char *m2)
60 bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
63 static void warn3x(const char *m1, const char *m2, const char *m3)
65 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
67 static void warn2_cannot(const char *m1, const char *m2)
69 warn3x("cannot ", m1, m2);
71 static void warnx(const char *m1)
76 static void s_term(int sig_no)
80 static void s_hangup(int sig_no)
85 static void runsv(int no, const char *name)
90 warn2_cannot("fork for ", name);
97 prog[0] = (char*)"runsv";
98 prog[1] = (char*)name;
102 signal(SIGHUP, SIG_DFL);
103 signal(SIGTERM, SIG_DFL);
104 BB_EXECVP(prog[0], prog);
105 //pathexec_run(*prog, prog, (char* const*)environ);
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] == '.') continue;
128 if (stat(d->d_name, &s) == -1) {
129 warn2_cannot("stat ", d->d_name);
133 if (!S_ISDIR(s.st_mode)) continue;
134 for (i = 0; i < svnum; i++) {
135 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
144 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
146 warn3x("cannot start runsv ", d->d_name,
147 " too many services");
152 memset(&sv[i], 0, sizeof(sv[i]));
153 sv[i].ino = s.st_ino;
154 sv[i].dev = s.st_dev;
162 warn2_cannot("read directory ", svdir);
169 /* SIGTERM removed runsv's */
170 for (i = 0; i < svnum; i++) {
174 kill(sv[i].pid, SIGTERM);
180 static int setup_log(void)
182 rploglen = strlen(rplog);
184 warnx("log must have at least seven characters");
187 if (pipe(logpipe) == -1) {
188 warnx("cannot create pipe for log");
193 ndelay_on(logpipe[0]);
194 ndelay_on(logpipe[1]);
195 if (dup2(logpipe[1], 2) == -1) {
196 warnx("cannot set filedescriptor for log");
199 io[0].fd = logpipe[0];
200 io[0].events = IOPAUSE_READ;
205 int runsvdir_main(int argc, char **argv);
206 int runsvdir_main(int argc, char **argv)
213 struct taia deadline;
215 struct taia stampcheck;
220 if (!argv || !*argv) usage();
222 switch (*(*argv + 1)) {
226 if (!argv || !*argv) usage();
229 sig_catch(SIGTERM, s_term);
230 sig_catch(SIGHUP, s_hangup);
234 if (setup_log() != 1) {
236 warnx("log service disabled");
239 curdir = open_read(".");
241 fatal2_cannot("open current directory", "");
244 taia_now(&stampcheck);
247 /* collect children */
249 pid = wait_nohang(&wstat);
251 for (i = 0; i < svnum; i++) {
252 if (pid == sv[i].pid) {
262 if (now.sec.x < (stampcheck.sec.x - 3)) {
264 warnx("time warp: resetting time stamp");
265 taia_now(&stampcheck);
267 if (rplog) taia_now(&stamplog);
269 if (taia_less(&now, &stampcheck) == 0) {
270 /* wait at least a second */
271 taia_uint(&deadline, 1);
272 taia_add(&stampcheck, &now, &deadline);
274 if (stat(svdir, &s) != -1) {
275 if (check || s.st_mtime != mtime
276 || s.st_ino != ino || s.st_dev != dev
279 if (chdir(svdir) != -1) {
284 if (now.sec.x <= (4611686018427387914ULL + (uint64_t)mtime))
287 while (fchdir(curdir) == -1) {
288 warn2_cannot("change directory, pausing", "");
292 warn2_cannot("change directory to ", svdir);
295 warn2_cannot("stat ", svdir);
299 if (taia_less(&now, &stamplog) == 0) {
300 write(logpipe[1], ".", 1);
301 taia_uint(&deadline, 900);
302 taia_add(&stamplog, &now, &deadline);
305 taia_uint(&deadline, check ? 1 : 5);
306 taia_add(&deadline, &now, &deadline);
310 iopause(io, 1, &deadline, &now);
312 iopause(0, 0, &deadline, &now);
313 sig_unblock(SIGCHLD);
315 if (rplog && (io[0].revents | IOPAUSE_READ))
316 while (read(logpipe[0], &ch, 1) > 0)
318 for (i = 6; i < rploglen; i++)
319 rplog[i-1] = rplog[i];
320 rplog[rploglen-1] = ch;
327 for (i = 0; i < svnum; i++)
329 kill(sv[i].pid, SIGTERM);