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;
101 sig_uncatch(SIGTERM);
103 BB_EXECVP(prog[0], prog);
104 //pathexec_run(*prog, prog, (char* const*)environ);
105 fatal2_cannot("start runsv ", name);
110 static void runsvdir(void)
119 warn2_cannot("open directory ", svdir);
122 for (i = 0; i < svnum; i++)
125 while ((d = readdir(dir))) {
126 if (d->d_name[0] == '.') continue;
127 if (stat(d->d_name, &s) == -1) {
128 warn2_cannot("stat ", d->d_name);
132 if (!S_ISDIR(s.st_mode)) continue;
133 for (i = 0; i < svnum; i++) {
134 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
143 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
145 warn3x("cannot start runsv ", d->d_name,
146 " too many services");
151 memset(&sv[i], 0, sizeof(sv[i]));
152 sv[i].ino = s.st_ino;
153 sv[i].dev = s.st_dev;
161 warn2_cannot("read directory ", svdir);
168 /* SIGTERM removed runsv's */
169 for (i = 0; i < svnum; i++) {
173 kill(sv[i].pid, SIGTERM);
179 static int setup_log(void)
181 rploglen = strlen(rplog);
183 warnx("log must have at least seven characters");
186 if (pipe(logpipe) == -1) {
187 warnx("cannot create pipe for log");
192 ndelay_on(logpipe[0]);
193 ndelay_on(logpipe[1]);
194 if (dup2(logpipe[1], 2) == -1) {
195 warnx("cannot set filedescriptor for log");
198 io[0].fd = logpipe[0];
199 io[0].events = IOPAUSE_READ;
204 int runsvdir_main(int argc, char **argv);
205 int runsvdir_main(int argc, char **argv)
212 struct taia deadline;
214 struct taia stampcheck;
219 if (!argv || !*argv) usage();
221 switch (*(*argv + 1)) {
225 if (!argv || !*argv) usage();
228 sig_catch(SIGTERM, s_term);
229 sig_catch(SIGHUP, s_hangup);
233 if (setup_log() != 1) {
235 warnx("log service disabled");
238 curdir = open_read(".");
240 fatal2_cannot("open current directory", "");
243 taia_now(&stampcheck);
246 /* collect children */
248 pid = wait_nohang(&wstat);
250 for (i = 0; i < svnum; i++) {
251 if (pid == sv[i].pid) {
261 if (now.sec.x < (stampcheck.sec.x - 3)) {
263 warnx("time warp: resetting time stamp");
264 taia_now(&stampcheck);
266 if (rplog) taia_now(&stamplog);
268 if (taia_less(&now, &stampcheck) == 0) {
269 /* wait at least a second */
270 taia_uint(&deadline, 1);
271 taia_add(&stampcheck, &now, &deadline);
273 if (stat(svdir, &s) != -1) {
274 if (check || s.st_mtime != mtime
275 || s.st_ino != ino || s.st_dev != dev
278 if (chdir(svdir) != -1) {
283 if (now.sec.x <= (4611686018427387914ULL + (uint64_t)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 (taia_less(&now, &stamplog) == 0) {
299 write(logpipe[1], ".", 1);
300 taia_uint(&deadline, 900);
301 taia_add(&stamplog, &now, &deadline);
304 taia_uint(&deadline, check ? 1 : 5);
305 taia_add(&deadline, &now, &deadline);
309 iopause(io, 1, &deadline, &now);
311 iopause(0, 0, &deadline, &now);
312 sig_unblock(SIGCHLD);
314 if (rplog && (io[0].revents | IOPAUSE_READ))
315 while (read(logpipe[0], &ch, 1) > 0)
317 for (i = 6; i < rploglen; i++)
318 rplog[i-1] = rplog[i];
319 rplog[rploglen-1] = ch;
326 for (i = 0; i < svnum; i++)
328 kill(sv[i].pid, SIGTERM);