Contents of /trunk/mkinitrd-magellan/busybox/runit/runsvdir.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File MIME type: text/plain
File size: 6094 byte(s)
Sat Sep 1 22:45:15 2007 UTC (17 years 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 | /* 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 | } |