blob: b35c2663006ec47f02d0c2ca7a76824fe3fdc922 [file] [log] [blame]
Denis Vlasenko8a164052007-03-12 23:34:52 +00001/*
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
Denis Vlasenko04c63862006-11-17 18:58:49 +000028/* 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>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000033#include "libbb.h"
Denis Vlasenko04c63862006-11-17 18:58:49 +000034#include "runit_lib.h"
35
Denis Vlasenko7bc53602007-08-31 21:45:52 +000036#if ENABLE_MONOTONIC_SYSCALL
37#include <sys/syscall.h>
38
39/* libc has incredibly messy way of doing this,
40 * typically requiring -lrt. We just skip all this mess */
41static void gettimeofday_ns(struct timespec *ts)
42{
43 syscall(__NR_clock_gettime, CLOCK_REALTIME, ts);
44}
45#else
46static void gettimeofday_ns(struct timespec *ts)
47{
48 if (sizeof(struct timeval) == sizeof(struct timespec)
49 && sizeof(((struct timeval*)ts)->tv_usec) == sizeof(ts->tv_nsec)
50 ) {
51 /* Cheat */
52 gettimeofday((void*)ts, NULL);
53 ts->tv_nsec *= 1000;
54 } else {
55 extern void BUG_need_to_implement_gettimeofday_ns(void);
56 BUG_need_to_implement_gettimeofday_ns();
57 }
58}
59#endif
60
61/* Compare possibly overflowing unsigned counters */
62#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
63
Denis Vlasenko04c63862006-11-17 18:58:49 +000064static int selfpipe[2];
65
66/* state */
67#define S_DOWN 0
68#define S_RUN 1
69#define S_FINISH 2
70/* ctrl */
71#define C_NOOP 0
72#define C_TERM 1
73#define C_PAUSE 2
74/* want */
75#define W_UP 0
76#define W_DOWN 1
77#define W_EXIT 2
78
79struct svdir {
80 int pid;
Denis Vlasenko3aba6662007-03-09 22:46:06 +000081 smallint state;
82 smallint ctrl;
83 smallint want;
84 smallint islog;
Denis Vlasenko45946f82007-08-20 17:27:40 +000085 struct timespec start;
Denis Vlasenko04c63862006-11-17 18:58:49 +000086 int fdlock;
87 int fdcontrol;
88 int fdcontrolwrite;
Denis Vlasenko04c63862006-11-17 18:58:49 +000089};
Denis Vlasenko04c63862006-11-17 18:58:49 +000090
Denis Vlasenko45946f82007-08-20 17:27:40 +000091static struct svdir svd[2];
Denis Vlasenko3aba6662007-03-09 22:46:06 +000092static smallint sigterm;
93static smallint haslog;
94static smallint pidchanged = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +000095static int logpipe[2];
96static char *dir;
97
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000098static void fatal2_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +000099{
100 bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
101 /* was exiting 111 */
102}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000103static void fatal_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000104{
105 fatal2_cannot(m, "");
106 /* was exiting 111 */
107}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000108static void fatal2x_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000109{
110 bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
111 /* was exiting 111 */
112}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000113static void warn_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000114{
115 bb_perror_msg("%s: warning: cannot %s", dir, m);
116}
Denis Vlasenko04c63862006-11-17 18:58:49 +0000117
Denis Vlasenko04c63862006-11-17 18:58:49 +0000118static void s_child(int sig_no)
119{
120 write(selfpipe[1], "", 1);
121}
122
123static void s_term(int sig_no)
124{
125 sigterm = 1;
126 write(selfpipe[1], "", 1); /* XXX */
127}
128
129static char *add_str(char *p, const char *to_add)
130{
131 while ((*p = *to_add) != '\0') {
132 p++;
133 to_add++;
134 }
135 return p;
136}
137
138static int open_trunc_or_warn(const char *name)
139{
140 int fd = open_trunc(name);
141 if (fd < 0)
142 bb_perror_msg("%s: warning: cannot open %s",
143 dir, name);
144 return fd;
145}
146
147static int rename_or_warn(const char *old, const char *new)
148{
149 if (rename(old, new) == -1) {
150 bb_perror_msg("%s: warning: cannot rename %s to %s",
151 dir, old, new);
152 return -1;
153 }
154 return 0;
155}
156
157static void update_status(struct svdir *s)
158{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000159 ssize_t sz;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000160 int fd;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000161 svstatus_t status;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000162
163 /* pid */
164 if (pidchanged) {
165 fd = open_trunc_or_warn("supervise/pid.new");
166 if (fd < 0)
167 return;
168 if (s->pid) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000169 char spid[sizeof(int)*3 + 2];
170 int size = sprintf(spid, "%u\n", (unsigned)s->pid);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000171 write(fd, spid, size);
172 }
173 close(fd);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000174 if (rename_or_warn("supervise/pid.new",
175 s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
Denis Vlasenko04c63862006-11-17 18:58:49 +0000176 return;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000177 pidchanged = 0;
178 }
179
180 /* stat */
181 fd = open_trunc_or_warn("supervise/stat.new");
182 if (fd < -1)
183 return;
184
185 {
186 char stat_buf[sizeof("finish, paused, got TERM, want down\n")];
187 char *p = stat_buf;
188 switch (s->state) {
189 case S_DOWN:
190 p = add_str(p, "down");
191 break;
192 case S_RUN:
193 p = add_str(p, "run");
194 break;
195 case S_FINISH:
196 p = add_str(p, "finish");
197 break;
198 }
199 if (s->ctrl & C_PAUSE) p = add_str(p, ", paused");
200 if (s->ctrl & C_TERM) p = add_str(p, ", got TERM");
201 if (s->state != S_DOWN)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000202 switch (s->want) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000203 case W_DOWN:
204 p = add_str(p, ", want down");
205 break;
206 case W_EXIT:
207 p = add_str(p, ", want exit");
208 break;
209 }
210 *p++ = '\n';
211 write(fd, stat_buf, p - stat_buf);
212 close(fd);
213 }
214
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000215 rename_or_warn("supervise/stat.new",
216 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000217
218 /* supervise compatibility */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000219 memset(&status, 0, sizeof(status));
220 status.time_be64 = SWAP_BE64(s->start.tv_sec + 0x400000000000000aULL);
221 status.time_nsec_be32 = SWAP_BE32(s->start.tv_nsec);
222 status.pid_le32 = SWAP_LE32(s->pid);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000223 if (s->ctrl & C_PAUSE)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000224 status.paused = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000225 if (s->want == W_UP)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000226 status.want = 'u';
Denis Vlasenko04c63862006-11-17 18:58:49 +0000227 else
Denis Vlasenko45946f82007-08-20 17:27:40 +0000228 status.want = 'd';
Denis Vlasenko04c63862006-11-17 18:58:49 +0000229 if (s->ctrl & C_TERM)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000230 status.got_term = 1;
231 status.run_or_finish = s->state;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000232 fd = open_trunc_or_warn("supervise/status.new");
233 if (fd < 0)
234 return;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000235 sz = write(fd, &status, sizeof(status));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000236 close(fd);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000237 if (sz != sizeof(status)) {
238 warn_cannot("write supervise/status.new");
239 unlink("supervise/status.new");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000240 return;
241 }
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000242 rename_or_warn("supervise/status.new",
243 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000244}
245
246static unsigned custom(struct svdir *s, char c)
247{
248 int pid;
249 int w;
250 char a[10];
251 struct stat st;
252 char *prog[2];
253
254 if (s->islog) return 0;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000255 strcpy(a, "control/?");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000256 a[8] = c;
257 if (stat(a, &st) == 0) {
258 if (st.st_mode & S_IXUSR) {
259 pid = fork();
260 if (pid == -1) {
261 warn_cannot("fork for control/?");
262 return 0;
263 }
264 if (!pid) {
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000265 if (haslog && dup2(logpipe[1], 1) == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000266 warn_cannot("setup stdout for control/?");
267 prog[0] = a;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000268 prog[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000269 execve(a, prog, environ);
270 fatal_cannot("run control/?");
271 }
272 while (wait_pid(&w, pid) == -1) {
273 if (errno == EINTR) continue;
274 warn_cannot("wait for child control/?");
275 return 0;
276 }
277 return !wait_exitcode(w);
278 }
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000279 } else {
280 if (errno != ENOENT)
281 warn_cannot("stat control/?");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000282 }
283 return 0;
284}
285
286static void stopservice(struct svdir *s)
287{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000288 if (s->pid && !custom(s, 't')) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000289 kill(s->pid, SIGTERM);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000290 s->ctrl |= C_TERM;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000291 update_status(s);
292 }
293 if (s->want == W_DOWN) {
294 kill(s->pid, SIGCONT);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000295 custom(s, 'd');
296 return;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000297 }
298 if (s->want == W_EXIT) {
299 kill(s->pid, SIGCONT);
300 custom(s, 'x');
301 }
302}
303
304static void startservice(struct svdir *s)
305{
306 int p;
307 char *run[2];
308
309 if (s->state == S_FINISH)
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000310 run[0] = (char*)"./finish";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000311 else {
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000312 run[0] = (char*)"./run";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000313 custom(s, 'u');
314 }
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000315 run[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000316
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000317 if (s->pid != 0)
318 stopservice(s); /* should never happen */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000319 while ((p = fork()) == -1) {
320 warn_cannot("fork, sleeping");
321 sleep(5);
322 }
323 if (p == 0) {
324 /* child */
325 if (haslog) {
326 if (s->islog) {
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000327 xdup2(logpipe[0], 0);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000328 close(logpipe[1]);
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000329 xchdir("./log");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000330 } else {
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000331 xdup2(logpipe[1], 1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000332 close(logpipe[0]);
333 }
334 }
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000335 signal(SIGCHLD, SIG_DFL);
336 signal(SIGTERM, SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000337 sig_unblock(SIGCHLD);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000338 sig_unblock(SIGTERM);
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000339 execvp(*run, run);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000340 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000341 }
342 if (s->state != S_FINISH) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000343 gettimeofday_ns(&s->start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000344 s->state = S_RUN;
345 }
346 s->pid = p;
347 pidchanged = 1;
348 s->ctrl = C_NOOP;
349 update_status(s);
350}
351
352static int ctrl(struct svdir *s, char c)
353{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000354 int sig;
355
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000356 switch (c) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000357 case 'd': /* down */
358 s->want = W_DOWN;
359 update_status(s);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000360 if (s->pid && s->state != S_FINISH)
361 stopservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000362 break;
363 case 'u': /* up */
364 s->want = W_UP;
365 update_status(s);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000366 if (s->pid == 0)
367 startservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000368 break;
369 case 'x': /* exit */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000370 if (s->islog)
371 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000372 s->want = W_EXIT;
373 update_status(s);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000374 /* FALLTHROUGH */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000375 case 't': /* sig term */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000376 if (s->pid && s->state != S_FINISH)
377 stopservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000378 break;
379 case 'k': /* sig kill */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000380 if (s->pid && !custom(s, c))
381 kill(s->pid, SIGKILL);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000382 s->state = S_DOWN;
383 break;
384 case 'p': /* sig pause */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000385 if (s->pid && !custom(s, c))
386 kill(s->pid, SIGSTOP);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000387 s->ctrl |= C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000388 update_status(s);
389 break;
390 case 'c': /* sig cont */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000391 if (s->pid && !custom(s, c))
392 kill(s->pid, SIGCONT);
393 if (s->ctrl & C_PAUSE)
394 s->ctrl &= ~C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000395 update_status(s);
396 break;
397 case 'o': /* once */
398 s->want = W_DOWN;
399 update_status(s);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000400 if (!s->pid)
401 startservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000402 break;
403 case 'a': /* sig alarm */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000404 sig = SIGALRM;
405 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000406 case 'h': /* sig hup */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000407 sig = SIGHUP;
408 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000409 case 'i': /* sig int */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000410 sig = SIGINT;
411 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000412 case 'q': /* sig quit */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000413 sig = SIGQUIT;
414 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000415 case '1': /* sig usr1 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000416 sig = SIGUSR1;
417 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000418 case '2': /* sig usr2 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000419 sig = SIGUSR2;
420 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000421 }
422 return 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000423 sendsig:
424 if (s->pid && !custom(s, c))
425 kill(s->pid, sig);
426 return 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000427}
428
Denis Vlasenko06af2162007-02-03 17:28:39 +0000429int runsv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000430int runsv_main(int argc, char **argv)
431{
432 struct stat s;
433 int fd;
434 int r;
435 char buf[256];
436
Denis Vlasenko45946f82007-08-20 17:27:40 +0000437 if (!argv[1] || argv[2])
438 bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000439 dir = argv[1];
440
Denis Vlasenko5a6aedd2007-05-26 16:44:20 +0000441 xpipe(selfpipe);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000442 coe(selfpipe[0]);
443 coe(selfpipe[1]);
444 ndelay_on(selfpipe[0]);
445 ndelay_on(selfpipe[1]);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000446
Denis Vlasenko8c783952007-01-27 22:21:52 +0000447 sig_block(SIGCHLD);
448 sig_catch(SIGCHLD, s_child);
449 sig_block(SIGTERM);
450 sig_catch(SIGTERM, s_term);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000451
452 xchdir(dir);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000453 /* bss: svd[0].pid = 0; */
454 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
455 if (C_NOOP) svd[0].ctrl = C_NOOP;
456 if (W_UP) svd[0].want = W_UP;
457 /* bss: svd[0].islog = 0; */
458 /* bss: svd[1].pid = 0; */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000459 gettimeofday_ns(&svd[0].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000460 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
461
462 if (stat("log", &s) == -1) {
463 if (errno != ENOENT)
464 warn_cannot("stat ./log");
465 } else {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000466 if (!S_ISDIR(s.st_mode)) {
467 errno = 0;
468 warn_cannot("stat log/down: log is not a directory");
469 } else {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000470 haslog = 1;
471 svd[1].state = S_DOWN;
472 svd[1].ctrl = C_NOOP;
473 svd[1].want = W_UP;
474 svd[1].islog = 1;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000475 gettimeofday_ns(&svd[1].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000476 if (stat("log/down", &s) != -1)
477 svd[1].want = W_DOWN;
Denis Vlasenko5a6aedd2007-05-26 16:44:20 +0000478 xpipe(logpipe);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000479 coe(logpipe[0]);
480 coe(logpipe[1]);
481 }
482 }
483
484 if (mkdir("supervise", 0700) == -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000485 r = readlink("supervise", buf, sizeof(buf));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000486 if (r != -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000487 if (r == sizeof(buf))
488 fatal2x_cannot("readlink ./supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000489 buf[r] = 0;
490 mkdir(buf, 0700);
491 } else {
492 if ((errno != ENOENT) && (errno != EINVAL))
493 fatal_cannot("readlink ./supervise");
494 }
495 }
496 svd[0].fdlock = xopen3("log/supervise/lock"+4,
497 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
498 if (lock_exnb(svd[0].fdlock) == -1)
499 fatal_cannot("lock supervise/lock");
500 coe(svd[0].fdlock);
501 if (haslog) {
502 if (mkdir("log/supervise", 0700) == -1) {
503 r = readlink("log/supervise", buf, 256);
504 if (r != -1) {
505 if (r == 256)
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000506 fatal2x_cannot("readlink ./log/supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000507 buf[r] = 0;
508 fd = xopen(".", O_RDONLY|O_NDELAY);
509 xchdir("./log");
510 mkdir(buf, 0700);
511 if (fchdir(fd) == -1)
512 fatal_cannot("change back to service directory");
513 close(fd);
514 }
515 else {
516 if ((errno != ENOENT) && (errno != EINVAL))
517 fatal_cannot("readlink ./log/supervise");
518 }
519 }
520 svd[1].fdlock = xopen3("log/supervise/lock",
521 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
522 if (lock_ex(svd[1].fdlock) == -1)
523 fatal_cannot("lock log/supervise/lock");
524 coe(svd[1].fdlock);
525 }
526
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000527 mkfifo("log/supervise/control"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000528 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
529 coe(svd[0].fdcontrol);
530 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
531 coe(svd[0].fdcontrolwrite);
532 update_status(&svd[0]);
533 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000534 mkfifo("log/supervise/control", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000535 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
536 coe(svd[1].fdcontrol);
537 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
538 coe(svd[1].fdcontrolwrite);
539 update_status(&svd[1]);
540 }
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000541 mkfifo("log/supervise/ok"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000542 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
543 coe(fd);
544 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000545 mkfifo("log/supervise/ok", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000546 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
547 coe(fd);
548 }
549 for (;;) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000550 struct pollfd x[3];
551 unsigned deadline;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000552 char ch;
553
554 if (haslog)
555 if (!svd[1].pid && svd[1].want == W_UP)
556 startservice(&svd[1]);
557 if (!svd[0].pid)
558 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
559 startservice(&svd[0]);
560
561 x[0].fd = selfpipe[0];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000562 x[0].events = POLLIN;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000563 x[1].fd = svd[0].fdcontrol;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000564 x[1].events = POLLIN;
565 /* x[2] is used only if haslog == 1 */
566 x[2].fd = svd[1].fdcontrol;
567 x[2].events = POLLIN;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000568 sig_unblock(SIGTERM);
569 sig_unblock(SIGCHLD);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000570 poll(x, 2 + haslog, 3600*1000);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000571 sig_block(SIGTERM);
572 sig_block(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000573
574 while (read(selfpipe[0], &ch, 1) == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000575 continue;
576
Denis Vlasenko04c63862006-11-17 18:58:49 +0000577 for (;;) {
578 int child;
579 int wstat;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000580
Denis Vlasenko04c63862006-11-17 18:58:49 +0000581 child = wait_nohang(&wstat);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000582 if (!child)
583 break;
584 if ((child == -1) && (errno != EINTR))
585 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000586 if (child == svd[0].pid) {
587 svd[0].pid = 0;
588 pidchanged = 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000589 svd[0].ctrl &=~ C_TERM;
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000590 if (svd[0].state != S_FINISH) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000591 fd = open_read("finish");
592 if (fd != -1) {
593 close(fd);
594 svd[0].state = S_FINISH;
595 update_status(&svd[0]);
596 continue;
597 }
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000598 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000599 svd[0].state = S_DOWN;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000600 deadline = svd[0].start.tv_sec + 1;
601 gettimeofday_ns(&svd[0].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000602 update_status(&svd[0]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000603 if (LESS(svd[0].start.tv_sec, deadline))
604 sleep(1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000605 }
606 if (haslog) {
607 if (child == svd[1].pid) {
608 svd[1].pid = 0;
609 pidchanged = 1;
610 svd[1].state = S_DOWN;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000611 svd[1].ctrl &= ~C_TERM;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000612 deadline = svd[1].start.tv_sec + 1;
613 gettimeofday_ns(&svd[1].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000614 update_status(&svd[1]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000615 if (LESS(svd[1].start.tv_sec, deadline))
616 sleep(1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000617 }
618 }
619 }
620 if (read(svd[0].fdcontrol, &ch, 1) == 1)
621 ctrl(&svd[0], ch);
622 if (haslog)
623 if (read(svd[1].fdcontrol, &ch, 1) == 1)
624 ctrl(&svd[1], ch);
625
626 if (sigterm) {
627 ctrl(&svd[0], 'x');
628 sigterm = 0;
629 }
630
631 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
632 if (svd[1].pid == 0)
633 _exit(0);
634 if (svd[1].want != W_EXIT) {
635 svd[1].want = W_EXIT;
636 /* stopservice(&svd[1]); */
637 update_status(&svd[1]);
638 close(logpipe[1]);
639 close(logpipe[0]);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000640 }
641 }
642 }
643 /* not reached */
644 return 0;
645}