Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1123 - (hide annotations) (download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 9675 byte(s)
-updated to busybox-1.17.1
1 niro 816 /*
2     Copyright (c) 2001-2006, Gerrit Pape
3     All rights reserved.
4    
5     Redistribution and use in source and binary forms, with or without
6     modification, 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    
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.
26     */
27    
28     /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 niro 532 /* TODO: depends on runit_lib.c - review and reduce/eliminate */
30    
31     #include <sys/poll.h>
32     #include <sys/file.h>
33 niro 816 #include "libbb.h"
34 niro 532 #include "runit_lib.h"
35    
36     #define MAXSERVICES 1000
37    
38 niro 816 /* Should be not needed - all dirs are on same FS, right? */
39     #define CHECK_DEVNO_TOO 0
40 niro 532
41 niro 816 struct service {
42     #if CHECK_DEVNO_TOO
43     dev_t dev;
44     #endif
45     ino_t ino;
46     pid_t pid;
47     smallint isgone;
48     };
49    
50     struct globals {
51     struct service *sv;
52     char *svdir;
53     int svnum;
54     #if ENABLE_FEATURE_RUNSVDIR_LOG
55     char *rplog;
56     int rploglen;
57     struct fd_pair logpipe;
58     struct pollfd pfd[1];
59     unsigned stamplog;
60     #endif
61 niro 1123 } FIX_ALIASING;
62 niro 816 #define G (*(struct globals*)&bb_common_bufsiz1)
63     #define sv (G.sv )
64     #define svdir (G.svdir )
65     #define svnum (G.svnum )
66     #define rplog (G.rplog )
67     #define rploglen (G.rploglen )
68     #define logpipe (G.logpipe )
69     #define pfd (G.pfd )
70     #define stamplog (G.stamplog )
71     #define INIT_G() do { \
72     } while (0)
73    
74     static void fatal2_cannot(const char *m1, const char *m2)
75 niro 532 {
76 niro 984 bb_perror_msg_and_die("%s: fatal: can't %s%s", svdir, m1, m2);
77 niro 532 /* was exiting 100 */
78     }
79 niro 816 static void warn3x(const char *m1, const char *m2, const char *m3)
80 niro 532 {
81     bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
82     }
83 niro 816 static void warn2_cannot(const char *m1, const char *m2)
84 niro 532 {
85 niro 984 warn3x("can't ", m1, m2);
86 niro 532 }
87 niro 816 #if ENABLE_FEATURE_RUNSVDIR_LOG
88     static void warnx(const char *m1)
89 niro 532 {
90     warn3x(m1, "", "");
91     }
92 niro 816 #endif
93 niro 532
94 niro 816 /* inlining + vfork -> bigger code */
95     static NOINLINE pid_t runsv(const char *name)
96 niro 532 {
97 niro 816 pid_t pid;
98 niro 532
99 niro 816 /* If we got signaled, stop spawning children at once! */
100     if (bb_got_signal)
101     return 0;
102 niro 532
103 niro 816 pid = vfork();
104 niro 532 if (pid == -1) {
105 niro 816 warn2_cannot("vfork", "");
106     return 0;
107 niro 532 }
108     if (pid == 0) {
109     /* child */
110 niro 816 if (option_mask32 & 1) /* -P option? */
111     setsid();
112     /* man execv:
113     * "Signals set to be caught by the calling process image
114     * shall be set to the default action in the new process image."
115     * Therefore, we do not need this: */
116     #if 0
117     bb_signals(0
118     | (1 << SIGHUP)
119     | (1 << SIGTERM)
120     , SIG_DFL);
121     #endif
122 niro 984 execlp("runsv", "runsv", name, (char *) NULL);
123 niro 532 fatal2_cannot("start runsv ", name);
124     }
125 niro 816 return pid;
126 niro 532 }
127    
128 niro 816 /* gcc 4.3.0 does better with NOINLINE */
129     static NOINLINE int do_rescan(void)
130 niro 532 {
131     DIR *dir;
132 niro 984 struct dirent *d;
133 niro 532 int i;
134     struct stat s;
135 niro 816 int need_rescan = 0;
136 niro 532
137     dir = opendir(".");
138     if (!dir) {
139     warn2_cannot("open directory ", svdir);
140 niro 816 return 1; /* need to rescan again soon */
141 niro 532 }
142     for (i = 0; i < svnum; i++)
143     sv[i].isgone = 1;
144 niro 816
145     while (1) {
146     errno = 0;
147     d = readdir(dir);
148     if (!d)
149     break;
150     if (d->d_name[0] == '.')
151     continue;
152 niro 532 if (stat(d->d_name, &s) == -1) {
153     warn2_cannot("stat ", d->d_name);
154     continue;
155     }
156 niro 816 if (!S_ISDIR(s.st_mode))
157     continue;
158     /* Do we have this service listed already? */
159 niro 532 for (i = 0; i < svnum; i++) {
160 niro 816 if ((sv[i].ino == s.st_ino)
161     #if CHECK_DEVNO_TOO
162     && (sv[i].dev == s.st_dev)
163     #endif
164     ) {
165     if (sv[i].pid == 0) /* restart if it has died */
166     goto run_ith_sv;
167     sv[i].isgone = 0; /* "we still see you" */
168     goto next_dentry;
169 niro 532 }
170     }
171 niro 816 { /* Not found, make new service */
172 niro 532 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
173     if (!svnew) {
174 niro 816 warn2_cannot("start runsv ", d->d_name);
175     need_rescan = 1;
176 niro 532 continue;
177     }
178     sv = svnew;
179     svnum++;
180 niro 816 #if CHECK_DEVNO_TOO
181     sv[i].dev = s.st_dev;
182     #endif
183 niro 532 sv[i].ino = s.st_ino;
184 niro 816 run_ith_sv:
185     sv[i].pid = runsv(d->d_name);
186     sv[i].isgone = 0;
187 niro 532 }
188 niro 816 next_dentry: ;
189 niro 532 }
190 niro 816 i = errno;
191     closedir(dir);
192     if (i) { /* readdir failed */
193 niro 532 warn2_cannot("read directory ", svdir);
194 niro 816 return 1; /* need to rescan again soon */
195 niro 532 }
196    
197 niro 816 /* Send SIGTERM to runsv whose directories
198     * were no longer found (-> must have been removed) */
199 niro 532 for (i = 0; i < svnum; i++) {
200     if (!sv[i].isgone)
201     continue;
202     if (sv[i].pid)
203     kill(sv[i].pid, SIGTERM);
204 niro 816 svnum--;
205     sv[i] = sv[svnum];
206     i--; /* so that we don't skip new sv[i] (bug was here!) */
207 niro 532 }
208 niro 816 return need_rescan;
209 niro 532 }
210    
211 niro 816 int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
212     int runsvdir_main(int argc UNUSED_PARAM, char **argv)
213 niro 532 {
214     struct stat s;
215 niro 816 dev_t last_dev = last_dev; /* for gcc */
216     ino_t last_ino = last_ino; /* for gcc */
217     time_t last_mtime = 0;
218 niro 532 int wstat;
219     int curdir;
220 niro 816 pid_t pid;
221     unsigned deadline;
222     unsigned now;
223     unsigned stampcheck;
224 niro 532 int i;
225 niro 816 int need_rescan = 1;
226     char *opt_s_argv[3];
227 niro 532
228 niro 816 INIT_G();
229 niro 532
230 niro 816 opt_complementary = "-1";
231     opt_s_argv[0] = NULL;
232     opt_s_argv[2] = NULL;
233     getopt32(argv, "Ps:", &opt_s_argv[0]);
234     argv += optind;
235    
236     bb_signals(0
237     | (1 << SIGTERM)
238     | (1 << SIGHUP)
239     /* For busybox's init, SIGTERM == reboot,
240     * SIGUSR1 == halt
241     * SIGUSR2 == poweroff
242     * so we need to intercept SIGUSRn too.
243     * Note that we do not implement actual reboot
244     * (killall(TERM) + umount, etc), we just pause
245     * respawing and avoid exiting (-> making kernel oops).
246     * The user is responsible for the rest. */
247     | (getpid() == 1 ? ((1 << SIGUSR1) | (1 << SIGUSR2)) : 0)
248     , record_signo);
249 niro 532 svdir = *argv++;
250 niro 816
251     #if ENABLE_FEATURE_RUNSVDIR_LOG
252     /* setup log */
253     if (*argv) {
254 niro 532 rplog = *argv;
255 niro 816 rploglen = strlen(rplog);
256     if (rploglen < 7) {
257     warnx("log must have at least seven characters");
258     } else if (piped_pair(logpipe)) {
259 niro 984 warnx("can't create pipe for log");
260 niro 816 } else {
261     close_on_exec_on(logpipe.rd);
262     close_on_exec_on(logpipe.wr);
263     ndelay_on(logpipe.rd);
264     ndelay_on(logpipe.wr);
265     if (dup2(logpipe.wr, 2) == -1) {
266 niro 984 warnx("can't set filedescriptor for log");
267 niro 816 } else {
268     pfd[0].fd = logpipe.rd;
269     pfd[0].events = POLLIN;
270     stamplog = monotonic_sec();
271     goto run;
272     }
273 niro 532 }
274 niro 816 rplog = NULL;
275     warnx("log service disabled");
276 niro 532 }
277 niro 816 run:
278     #endif
279 niro 532 curdir = open_read(".");
280     if (curdir == -1)
281     fatal2_cannot("open current directory", "");
282 niro 816 close_on_exec_on(curdir);
283 niro 532
284 niro 816 stampcheck = monotonic_sec();
285 niro 532
286     for (;;) {
287     /* collect children */
288     for (;;) {
289 niro 816 pid = wait_any_nohang(&wstat);
290     if (pid <= 0)
291     break;
292 niro 532 for (i = 0; i < svnum; i++) {
293     if (pid == sv[i].pid) {
294 niro 816 /* runsv has died */
295 niro 532 sv[i].pid = 0;
296 niro 816 need_rescan = 1;
297 niro 532 }
298     }
299     }
300    
301 niro 816 now = monotonic_sec();
302     if ((int)(now - stampcheck) >= 0) {
303 niro 532 /* wait at least a second */
304 niro 816 stampcheck = now + 1;
305 niro 532
306     if (stat(svdir, &s) != -1) {
307 niro 816 if (need_rescan || s.st_mtime != last_mtime
308     || s.st_ino != last_ino || s.st_dev != last_dev
309 niro 532 ) {
310     /* svdir modified */
311     if (chdir(svdir) != -1) {
312 niro 816 last_mtime = s.st_mtime;
313     last_dev = s.st_dev;
314     last_ino = s.st_ino;
315     //if (now <= mtime)
316     // sleep(1);
317     need_rescan = do_rescan();
318 niro 532 while (fchdir(curdir) == -1) {
319     warn2_cannot("change directory, pausing", "");
320     sleep(5);
321     }
322 niro 816 } else {
323 niro 532 warn2_cannot("change directory to ", svdir);
324 niro 816 }
325 niro 532 }
326 niro 816 } else {
327 niro 532 warn2_cannot("stat ", svdir);
328 niro 816 }
329 niro 532 }
330    
331 niro 816 #if ENABLE_FEATURE_RUNSVDIR_LOG
332 niro 532 if (rplog) {
333 niro 816 if ((int)(now - stamplog) >= 0) {
334     write(logpipe.wr, ".", 1);
335     stamplog = now + 900;
336 niro 532 }
337     }
338 niro 816 pfd[0].revents = 0;
339     #endif
340     deadline = (need_rescan ? 1 : 5);
341     sig_block(SIGCHLD);
342     #if ENABLE_FEATURE_RUNSVDIR_LOG
343 niro 532 if (rplog)
344 niro 816 poll(pfd, 1, deadline*1000);
345 niro 532 else
346 niro 816 #endif
347     sleep(deadline);
348     sig_unblock(SIGCHLD);
349 niro 532
350 niro 816 #if ENABLE_FEATURE_RUNSVDIR_LOG
351     if (pfd[0].revents & POLLIN) {
352     char ch;
353     while (read(logpipe.rd, &ch, 1) > 0) {
354     if (ch < ' ')
355     ch = ' ';
356     for (i = 6; i < rploglen; i++)
357     rplog[i-1] = rplog[i];
358     rplog[rploglen-1] = ch;
359     }
360     }
361     #endif
362     if (!bb_got_signal)
363     continue;
364 niro 532
365 niro 816 /* -s SCRIPT: useful if we are init.
366     * In this case typically script never returns,
367     * it halts/powers off/reboots the system. */
368     if (opt_s_argv[0]) {
369     /* Single parameter: signal# */
370     opt_s_argv[1] = utoa(bb_got_signal);
371     pid = spawn(opt_s_argv);
372     if (pid > 0) {
373 niro 984 /* Remembering to wait for _any_ children,
374 niro 816 * not just pid */
375     while (wait(NULL) != pid)
376     continue;
377     }
378     }
379    
380 niro 984 if (bb_got_signal == SIGHUP) {
381 niro 532 for (i = 0; i < svnum; i++)
382     if (sv[i].pid)
383     kill(sv[i].pid, SIGTERM);
384 niro 984 }
385     /* SIGHUP or SIGTERM (or SIGUSRn if we are init) */
386     /* Exit unless we are init */
387     if (getpid() != 1)
388 niro 816 return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS;
389    
390 niro 984 /* init continues to monitor services forever */
391 niro 816 bb_got_signal = 0;
392     } /* for (;;) */
393 niro 532 }