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

Last change on this file since 1770 was 1765, checked in by Bruno Cornec, 16 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.