Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/runit/runsvdir.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 6094 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
2     /* TODO: depends on runit_lib.c - review and reduce/eliminate */
3    
4     #include <sys/poll.h>
5     #include <sys/file.h>
6     #include "busybox.h"
7     #include "runit_lib.h"
8    
9     #define MAXSERVICES 1000
10    
11     static char *svdir;
12     static unsigned long dev;
13     static unsigned long ino;
14     static struct service {
15     unsigned long dev;
16     unsigned long ino;
17     int pid;
18     int isgone;
19     } *sv;
20     static int svnum;
21     static int check = 1;
22     static char *rplog;
23     static int rploglen;
24     static int logpipe[2];
25     static iopause_fd io[1];
26     static struct taia stamplog;
27     static int exitsoon;
28     static int pgrp;
29    
30     #define usage() bb_show_usage()
31     static void fatal2_cannot(char *m1, char *m2)
32     {
33     bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
34     /* was exiting 100 */
35     }
36     static void warn3x(char *m1, char *m2, char *m3)
37     {
38     bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
39     }
40     static void warn2_cannot(char *m1, char *m2)
41     {
42     warn3x("cannot ", m1, m2);
43     }
44     static void warnx(char *m1)
45     {
46     warn3x(m1, "", "");
47     }
48    
49     static void s_term(int sig_no)
50     {
51     exitsoon = 1;
52     }
53     static void s_hangup(int sig_no)
54     {
55     exitsoon = 2;
56     }
57    
58     static void runsv(int no, char *name)
59     {
60     int pid = fork();
61    
62     if (pid == -1) {
63     warn2_cannot("fork for ", name);
64     return;
65     }
66     if (pid == 0) {
67     /* child */
68     char *prog[3];
69    
70     prog[0] = "runsv";
71     prog[1] = name;
72     prog[2] = 0;
73     sig_uncatch(sig_hangup);
74     sig_uncatch(sig_term);
75     if (pgrp) setsid();
76     execvp(prog[0], prog);
77     //pathexec_run(*prog, prog, (char* const*)environ);
78     fatal2_cannot("start runsv ", name);
79     }
80     sv[no].pid = pid;
81     }
82    
83     static void runsvdir(void)
84     {
85     DIR *dir;
86     direntry *d;
87     int i;
88     struct stat s;
89    
90     dir = opendir(".");
91     if (!dir) {
92     warn2_cannot("open directory ", svdir);
93     return;
94     }
95     for (i = 0; i < svnum; i++)
96     sv[i].isgone = 1;
97     errno = 0;
98     while ((d = readdir(dir))) {
99     if (d->d_name[0] == '.') continue;
100     if (stat(d->d_name, &s) == -1) {
101     warn2_cannot("stat ", d->d_name);
102     errno = 0;
103     continue;
104     }
105     if (!S_ISDIR(s.st_mode)) continue;
106     for (i = 0; i < svnum; i++) {
107     if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
108     sv[i].isgone = 0;
109     if (!sv[i].pid)
110     runsv(i, d->d_name);
111     break;
112     }
113     }
114     if (i == svnum) {
115     /* new service */
116     struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
117     if (!svnew) {
118     warn3x("cannot start runsv ", d->d_name,
119     " too many services");
120     continue;
121     }
122     sv = svnew;
123     svnum++;
124     memset(&sv[i], 0, sizeof(sv[i]));
125     sv[i].ino = s.st_ino;
126     sv[i].dev = s.st_dev;
127     //sv[i].pid = 0;
128     //sv[i].isgone = 0;
129     runsv(i, d->d_name);
130     check = 1;
131     }
132     }
133     if (errno) {
134     warn2_cannot("read directory ", svdir);
135     closedir(dir);
136     check = 1;
137     return;
138     }
139     closedir(dir);
140    
141     /* SIGTERM removed runsv's */
142     for (i = 0; i < svnum; i++) {
143     if (!sv[i].isgone)
144     continue;
145     if (sv[i].pid)
146     kill(sv[i].pid, SIGTERM);
147     sv[i] = sv[--svnum];
148     check = 1;
149     }
150     }
151    
152     static int setup_log(void)
153     {
154     rploglen = strlen(rplog);
155     if (rploglen < 7) {
156     warnx("log must have at least seven characters");
157     return 0;
158     }
159     if (pipe(logpipe) == -1) {
160     warnx("cannot create pipe for log");
161     return -1;
162     }
163     coe(logpipe[1]);
164     coe(logpipe[0]);
165     ndelay_on(logpipe[0]);
166     ndelay_on(logpipe[1]);
167     if (fd_copy(2, logpipe[1]) == -1) {
168     warnx("cannot set filedescriptor for log");
169     return -1;
170     }
171     io[0].fd = logpipe[0];
172     io[0].events = IOPAUSE_READ;
173     taia_now(&stamplog);
174     return 1;
175     }
176    
177     int runsvdir_main(int argc, char **argv)
178     {
179     struct stat s;
180     time_t mtime = 0;
181     int wstat;
182     int curdir;
183     int pid;
184     struct taia deadline;
185     struct taia now;
186     struct taia stampcheck;
187     char ch;
188     int i;
189    
190     argv++;
191     if (!argv || !*argv) usage();
192     if (**argv == '-') {
193     switch (*(*argv + 1)) {
194     case 'P': pgrp = 1;
195     case '-': ++argv;
196     }
197     if (!argv || !*argv) usage();
198     }
199    
200     sig_catch(sig_term, s_term);
201     sig_catch(sig_hangup, s_hangup);
202     svdir = *argv++;
203     if (argv && *argv) {
204     rplog = *argv;
205     if (setup_log() != 1) {
206     rplog = 0;
207     warnx("log service disabled");
208     }
209     }
210     curdir = open_read(".");
211     if (curdir == -1)
212     fatal2_cannot("open current directory", "");
213     coe(curdir);
214    
215     taia_now(&stampcheck);
216    
217     for (;;) {
218     /* collect children */
219     for (;;) {
220     pid = wait_nohang(&wstat);
221     if (pid <= 0) break;
222     for (i = 0; i < svnum; i++) {
223     if (pid == sv[i].pid) {
224     /* runsv has gone */
225     sv[i].pid = 0;
226     check = 1;
227     break;
228     }
229     }
230     }
231    
232     taia_now(&now);
233     if (now.sec.x < (stampcheck.sec.x - 3)) {
234     /* time warp */
235     warnx("time warp: resetting time stamp");
236     taia_now(&stampcheck);
237     taia_now(&now);
238     if (rplog) taia_now(&stamplog);
239     }
240     if (taia_less(&now, &stampcheck) == 0) {
241     /* wait at least a second */
242     taia_uint(&deadline, 1);
243     taia_add(&stampcheck, &now, &deadline);
244    
245     if (stat(svdir, &s) != -1) {
246     if (check || s.st_mtime != mtime
247     || s.st_ino != ino || s.st_dev != dev
248     ) {
249     /* svdir modified */
250     if (chdir(svdir) != -1) {
251     mtime = s.st_mtime;
252     dev = s.st_dev;
253     ino = s.st_ino;
254     check = 0;
255     if (now.sec.x <= (4611686018427387914ULL + (uint64_t)mtime))
256     sleep(1);
257     runsvdir();
258     while (fchdir(curdir) == -1) {
259     warn2_cannot("change directory, pausing", "");
260     sleep(5);
261     }
262     } else
263     warn2_cannot("change directory to ", svdir);
264     }
265     } else
266     warn2_cannot("stat ", svdir);
267     }
268    
269     if (rplog) {
270     if (taia_less(&now, &stamplog) == 0) {
271     write(logpipe[1], ".", 1);
272     taia_uint(&deadline, 900);
273     taia_add(&stamplog, &now, &deadline);
274     }
275     }
276     taia_uint(&deadline, check ? 1 : 5);
277     taia_add(&deadline, &now, &deadline);
278    
279     sig_block(sig_child);
280     if (rplog)
281     iopause(io, 1, &deadline, &now);
282     else
283     iopause(0, 0, &deadline, &now);
284     sig_unblock(sig_child);
285    
286     if (rplog && (io[0].revents | IOPAUSE_READ))
287     while (read(logpipe[0], &ch, 1) > 0)
288     if (ch) {
289     for (i = 6; i < rploglen; i++)
290     rplog[i-1] = rplog[i];
291     rplog[rploglen-1] = ch;
292     }
293    
294     switch (exitsoon) {
295     case 1:
296     _exit(0);
297     case 2:
298     for (i = 0; i < svnum; i++)
299     if (sv[i].pid)
300     kill(sv[i].pid, SIGTERM);
301     _exit(111);
302     }
303     }
304     /* not reached */
305     return 0;
306     }