source: branches/stable/mindi-busybox/runit/runsvdir.c @ 1770

Last change on this file since 1770 was 1765, checked in by Bruno Cornec, 13 years ago

Update to busybox 1.7.2

  • Property svn:eol-style set to native
File size: 7.1 KB
Line 
1/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
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.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29/* TODO: depends on runit_lib.c - review and reduce/eliminate */
30
31#include <sys/poll.h>
32#include <sys/file.h>
33#include "libbb.h"
34#include "runit_lib.h"
35
36#define MAXSERVICES 1000
37
38struct service {
39    dev_t dev;
40    ino_t ino;
41    pid_t pid;
42    smallint isgone;
43};
44
45struct service *sv;
46static char *svdir;
47static int svnum;
48static char *rplog;
49static int rploglen;
50static int logpipe[2];
51static struct pollfd pfd[1];
52static unsigned stamplog;
53static smallint check = 1;
54static smallint exitsoon;
55static smallint set_pgrp;
56
57static void fatal2_cannot(const char *m1, const char *m2)
58{
59    bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
60    /* was exiting 100 */
61}
62static void warn3x(const char *m1, const char *m2, const char *m3)
63{
64    bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
65}
66static void warn2_cannot(const char *m1, const char *m2)
67{
68    warn3x("cannot ", m1, m2);
69}
70static void warnx(const char *m1)
71{
72    warn3x(m1, "", "");
73}
74
75static void s_term(int sig_no)
76{
77    exitsoon = 1;
78}
79static void s_hangup(int sig_no)
80{
81    exitsoon = 2;
82}
83
84static void runsv(int no, const char *name)
85{
86    pid_t pid;
87    char *prog[3];
88
89    prog[0] = (char*)"runsv";
90    prog[1] = (char*)name;
91    prog[2] = NULL;
92
93    pid = vfork();
94
95    if (pid == -1) {
96        warn2_cannot("vfork", "");
97        return;
98    }
99    if (pid == 0) {
100        /* child */
101        if (set_pgrp)
102            setsid();
103        signal(SIGHUP, SIG_DFL);
104        signal(SIGTERM, SIG_DFL);
105        execvp(prog[0], prog);
106        fatal2_cannot("start runsv ", name);
107    }
108    sv[no].pid = pid;
109}
110
111static void runsvdir(void)
112{
113    DIR *dir;
114    direntry *d;
115    int i;
116    struct stat s;
117
118    dir = opendir(".");
119    if (!dir) {
120        warn2_cannot("open directory ", svdir);
121        return;
122    }
123    for (i = 0; i < svnum; i++)
124        sv[i].isgone = 1;
125    errno = 0;
126    while ((d = readdir(dir))) {
127        if (d->d_name[0] == '.')
128            continue;
129        if (stat(d->d_name, &s) == -1) {
130            warn2_cannot("stat ", d->d_name);
131            errno = 0;
132            continue;
133        }
134        if (!S_ISDIR(s.st_mode))
135            continue;
136        for (i = 0; i < svnum; i++) {
137            if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
138                sv[i].isgone = 0;
139                if (!sv[i].pid)
140                    runsv(i, d->d_name);
141                break;
142            }
143        }
144        if (i == svnum) {
145            /* new service */
146            struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
147            if (!svnew) {
148                warn3x("cannot start runsv ", d->d_name,
149                        " too many services");
150                continue;
151            }
152            sv = svnew;
153            svnum++;
154            memset(&sv[i], 0, sizeof(sv[i]));
155            sv[i].ino = s.st_ino;
156            sv[i].dev = s.st_dev;
157            /*sv[i].pid = 0;*/
158            /*sv[i].isgone = 0;*/
159            runsv(i, d->d_name);
160            check = 1;
161        }
162    }
163    if (errno) {
164        warn2_cannot("read directory ", svdir);
165        closedir(dir);
166        check = 1;
167        return;
168    }
169    closedir(dir);
170
171    /* SIGTERM removed runsv's */
172    for (i = 0; i < svnum; i++) {
173        if (!sv[i].isgone)
174            continue;
175        if (sv[i].pid)
176            kill(sv[i].pid, SIGTERM);
177        sv[i] = sv[--svnum];
178        check = 1;
179    }
180}
181
182static int setup_log(void)
183{
184    rploglen = strlen(rplog);
185    if (rploglen < 7) {
186        warnx("log must have at least seven characters");
187        return 0;
188    }
189    if (pipe(logpipe)) {
190        warnx("cannot create pipe for log");
191        return -1;
192    }
193    coe(logpipe[1]);
194    coe(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");
199        return -1;
200    }
201    pfd[0].fd = logpipe[0];
202    pfd[0].events = POLLIN;
203    stamplog = monotonic_sec();
204    return 1;
205}
206
207int runsvdir_main(int argc, char **argv);
208int runsvdir_main(int argc, char **argv)
209{
210    struct stat s;
211    dev_t last_dev = last_dev; /* for gcc */
212    ino_t last_ino = last_ino; /* for gcc */
213    time_t last_mtime = 0;
214    int wstat;
215    int curdir;
216    int pid;
217    unsigned deadline;
218    unsigned now;
219    unsigned stampcheck;
220    char ch;
221    int i;
222
223    argv++;
224    if (!*argv)
225        bb_show_usage();
226    if (argv[0][0] == '-') {
227        switch (argv[0][1]) {
228        case 'P': set_pgrp = 1;
229        case '-': ++argv;
230        }
231        if (!*argv)
232            bb_show_usage();
233    }
234
235    sig_catch(SIGTERM, s_term);
236    sig_catch(SIGHUP, s_hangup);
237    svdir = *argv++;
238    if (argv && *argv) {
239        rplog = *argv;
240        if (setup_log() != 1) {
241            rplog = 0;
242            warnx("log service disabled");
243        }
244    }
245    curdir = open_read(".");
246    if (curdir == -1)
247        fatal2_cannot("open current directory", "");
248    coe(curdir);
249
250    stampcheck = monotonic_sec();
251
252    for (;;) {
253        /* collect children */
254        for (;;) {
255            pid = wait_nohang(&wstat);
256            if (pid <= 0)
257                break;
258            for (i = 0; i < svnum; i++) {
259                if (pid == sv[i].pid) {
260                    /* runsv has gone */
261                    sv[i].pid = 0;
262                    check = 1;
263                    break;
264                }
265            }
266        }
267
268        now = monotonic_sec();
269        if ((int)(now - stampcheck) >= 0) {
270            /* wait at least a second */
271            stampcheck = now + 1;
272
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
276                ) {
277                    /* svdir modified */
278                    if (chdir(svdir) != -1) {
279                        last_mtime = s.st_mtime;
280                        last_dev = s.st_dev;
281                        last_ino = s.st_ino;
282                        check = 0;
283                        //if (now <= mtime)
284                        //  sleep(1);
285                        runsvdir();
286                        while (fchdir(curdir) == -1) {
287                            warn2_cannot("change directory, pausing", "");
288                            sleep(5);
289                        }
290                    } else
291                        warn2_cannot("change directory to ", svdir);
292                }
293            } else
294                warn2_cannot("stat ", svdir);
295        }
296
297        if (rplog) {
298            if ((int)(now - stamplog) >= 0) {
299                write(logpipe[1], ".", 1);
300                stamplog = now + 900;
301            }
302        }
303
304        pfd[0].revents = 0;
305        sig_block(SIGCHLD);
306        deadline = (check ? 1 : 5);
307        if (rplog)
308            poll(pfd, 1, deadline*1000);
309        else
310            sleep(deadline);
311        sig_unblock(SIGCHLD);
312
313        if (pfd[0].revents & POLLIN) {
314            while (read(logpipe[0], &ch, 1) > 0) {
315                if (ch) {
316                    for (i = 6; i < rploglen; i++)
317                        rplog[i-1] = rplog[i];
318                    rplog[rploglen-1] = ch;
319                }
320            }
321        }
322
323        switch (exitsoon) {
324        case 1:
325            _exit(0);
326        case 2:
327            for (i = 0; i < svnum; i++)
328                if (sv[i].pid)
329                    kill(sv[i].pid, SIGTERM);
330            _exit(111);
331        }
332    }
333    /* not reached */
334    return 0;
335}
Note: See TracBrowser for help on using the repository browser.