Annotation of /trunk/mkinitrd-magellan/busybox/runit/runsvdir.c
Parent Directory | 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)
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 | } |