blob: baef6e13fdd1bd66ad169717b60021627de466e6 [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
36static int selfpipe[2];
37
38/* state */
39#define S_DOWN 0
40#define S_RUN 1
41#define S_FINISH 2
42/* ctrl */
43#define C_NOOP 0
44#define C_TERM 1
45#define C_PAUSE 2
46/* want */
47#define W_UP 0
48#define W_DOWN 1
49#define W_EXIT 2
50
51struct svdir {
52 int pid;
Denis Vlasenko3aba6662007-03-09 22:46:06 +000053 smallint state;
54 smallint ctrl;
55 smallint want;
56 smallint islog;
Denis Vlasenko45946f82007-08-20 17:27:40 +000057 struct timespec start;
Denis Vlasenko04c63862006-11-17 18:58:49 +000058 int fdlock;
59 int fdcontrol;
60 int fdcontrolwrite;
Denis Vlasenko04c63862006-11-17 18:58:49 +000061};
Denis Vlasenko04c63862006-11-17 18:58:49 +000062
Denis Vlasenko45946f82007-08-20 17:27:40 +000063static struct svdir svd[2];
Denis Vlasenko3aba6662007-03-09 22:46:06 +000064static smallint sigterm;
65static smallint haslog;
66static smallint pidchanged = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +000067static int logpipe[2];
68static char *dir;
69
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000070static void fatal2_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +000071{
72 bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
73 /* was exiting 111 */
74}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000075static void fatal_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +000076{
77 fatal2_cannot(m, "");
78 /* was exiting 111 */
79}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000080static void fatal2x_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +000081{
82 bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
83 /* was exiting 111 */
84}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000085static void warn_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +000086{
87 bb_perror_msg("%s: warning: cannot %s", dir, m);
88}
Denis Vlasenko04c63862006-11-17 18:58:49 +000089
Denis Vlasenko04c63862006-11-17 18:58:49 +000090static void s_child(int sig_no)
91{
92 write(selfpipe[1], "", 1);
93}
94
95static void s_term(int sig_no)
96{
97 sigterm = 1;
98 write(selfpipe[1], "", 1); /* XXX */
99}
100
101static char *add_str(char *p, const char *to_add)
102{
103 while ((*p = *to_add) != '\0') {
104 p++;
105 to_add++;
106 }
107 return p;
108}
109
110static int open_trunc_or_warn(const char *name)
111{
112 int fd = open_trunc(name);
113 if (fd < 0)
114 bb_perror_msg("%s: warning: cannot open %s",
115 dir, name);
116 return fd;
117}
118
119static int rename_or_warn(const char *old, const char *new)
120{
121 if (rename(old, new) == -1) {
122 bb_perror_msg("%s: warning: cannot rename %s to %s",
123 dir, old, new);
124 return -1;
125 }
126 return 0;
127}
128
Denis Vlasenko45946f82007-08-20 17:27:40 +0000129#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
130
131#include <sys/syscall.h>
132static void gettimeofday_ns(struct timespec *ts)
133{
134 syscall(__NR_clock_gettime, CLOCK_REALTIME, ts);
135}
136
Denis Vlasenko04c63862006-11-17 18:58:49 +0000137static void update_status(struct svdir *s)
138{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000139 ssize_t sz;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000140 int fd;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000141 svstatus_t status;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000142
143 /* pid */
144 if (pidchanged) {
145 fd = open_trunc_or_warn("supervise/pid.new");
146 if (fd < 0)
147 return;
148 if (s->pid) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000149 char spid[sizeof(int)*3 + 2];
150 int size = sprintf(spid, "%u\n", (unsigned)s->pid);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000151 write(fd, spid, size);
152 }
153 close(fd);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000154 if (rename_or_warn("supervise/pid.new",
155 s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
Denis Vlasenko04c63862006-11-17 18:58:49 +0000156 return;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000157 pidchanged = 0;
158 }
159
160 /* stat */
161 fd = open_trunc_or_warn("supervise/stat.new");
162 if (fd < -1)
163 return;
164
165 {
166 char stat_buf[sizeof("finish, paused, got TERM, want down\n")];
167 char *p = stat_buf;
168 switch (s->state) {
169 case S_DOWN:
170 p = add_str(p, "down");
171 break;
172 case S_RUN:
173 p = add_str(p, "run");
174 break;
175 case S_FINISH:
176 p = add_str(p, "finish");
177 break;
178 }
179 if (s->ctrl & C_PAUSE) p = add_str(p, ", paused");
180 if (s->ctrl & C_TERM) p = add_str(p, ", got TERM");
181 if (s->state != S_DOWN)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000182 switch (s->want) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000183 case W_DOWN:
184 p = add_str(p, ", want down");
185 break;
186 case W_EXIT:
187 p = add_str(p, ", want exit");
188 break;
189 }
190 *p++ = '\n';
191 write(fd, stat_buf, p - stat_buf);
192 close(fd);
193 }
194
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000195 rename_or_warn("supervise/stat.new",
196 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000197
198 /* supervise compatibility */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000199 memset(&status, 0, sizeof(status));
200 status.time_be64 = SWAP_BE64(s->start.tv_sec + 0x400000000000000aULL);
201 status.time_nsec_be32 = SWAP_BE32(s->start.tv_nsec);
202 status.pid_le32 = SWAP_LE32(s->pid);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000203 if (s->ctrl & C_PAUSE)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000204 status.paused = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000205 if (s->want == W_UP)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000206 status.want = 'u';
Denis Vlasenko04c63862006-11-17 18:58:49 +0000207 else
Denis Vlasenko45946f82007-08-20 17:27:40 +0000208 status.want = 'd';
Denis Vlasenko04c63862006-11-17 18:58:49 +0000209 if (s->ctrl & C_TERM)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000210 status.got_term = 1;
211 status.run_or_finish = s->state;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000212 fd = open_trunc_or_warn("supervise/status.new");
213 if (fd < 0)
214 return;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000215 sz = write(fd, &status, sizeof(status));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000216 close(fd);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000217 if (sz != sizeof(status)) {
218 warn_cannot("write supervise/status.new");
219 unlink("supervise/status.new");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000220 return;
221 }
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000222 rename_or_warn("supervise/status.new",
223 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000224}
225
226static unsigned custom(struct svdir *s, char c)
227{
228 int pid;
229 int w;
230 char a[10];
231 struct stat st;
232 char *prog[2];
233
234 if (s->islog) return 0;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000235 strcpy(a, "control/?");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000236 a[8] = c;
237 if (stat(a, &st) == 0) {
238 if (st.st_mode & S_IXUSR) {
239 pid = fork();
240 if (pid == -1) {
241 warn_cannot("fork for control/?");
242 return 0;
243 }
244 if (!pid) {
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000245 if (haslog && dup2(logpipe[1], 1) == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000246 warn_cannot("setup stdout for control/?");
247 prog[0] = a;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000248 prog[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000249 execve(a, prog, environ);
250 fatal_cannot("run control/?");
251 }
252 while (wait_pid(&w, pid) == -1) {
253 if (errno == EINTR) continue;
254 warn_cannot("wait for child control/?");
255 return 0;
256 }
257 return !wait_exitcode(w);
258 }
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000259 } else {
260 if (errno != ENOENT)
261 warn_cannot("stat control/?");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000262 }
263 return 0;
264}
265
266static void stopservice(struct svdir *s)
267{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000268 if (s->pid && !custom(s, 't')) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000269 kill(s->pid, SIGTERM);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000270 s->ctrl |= C_TERM;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000271 update_status(s);
272 }
273 if (s->want == W_DOWN) {
274 kill(s->pid, SIGCONT);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000275 custom(s, 'd');
276 return;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000277 }
278 if (s->want == W_EXIT) {
279 kill(s->pid, SIGCONT);
280 custom(s, 'x');
281 }
282}
283
284static void startservice(struct svdir *s)
285{
286 int p;
287 char *run[2];
288
289 if (s->state == S_FINISH)
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000290 run[0] = (char*)"./finish";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000291 else {
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000292 run[0] = (char*)"./run";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000293 custom(s, 'u');
294 }
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000295 run[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000296
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000297 if (s->pid != 0)
298 stopservice(s); /* should never happen */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000299 while ((p = fork()) == -1) {
300 warn_cannot("fork, sleeping");
301 sleep(5);
302 }
303 if (p == 0) {
304 /* child */
305 if (haslog) {
306 if (s->islog) {
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000307 xdup2(logpipe[0], 0);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000308 close(logpipe[1]);
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000309 xchdir("./log");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000310 } else {
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000311 xdup2(logpipe[1], 1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000312 close(logpipe[0]);
313 }
314 }
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000315 signal(SIGCHLD, SIG_DFL);
316 signal(SIGTERM, SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000317 sig_unblock(SIGCHLD);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000318 sig_unblock(SIGTERM);
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000319 execvp(*run, run);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000320 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000321 }
322 if (s->state != S_FINISH) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000323 gettimeofday_ns(&s->start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000324 s->state = S_RUN;
325 }
326 s->pid = p;
327 pidchanged = 1;
328 s->ctrl = C_NOOP;
329 update_status(s);
330}
331
332static int ctrl(struct svdir *s, char c)
333{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000334 int sig;
335
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000336 switch (c) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000337 case 'd': /* down */
338 s->want = W_DOWN;
339 update_status(s);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000340 if (s->pid && s->state != S_FINISH)
341 stopservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000342 break;
343 case 'u': /* up */
344 s->want = W_UP;
345 update_status(s);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000346 if (s->pid == 0)
347 startservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000348 break;
349 case 'x': /* exit */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000350 if (s->islog)
351 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000352 s->want = W_EXIT;
353 update_status(s);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000354 /* FALLTHROUGH */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000355 case 't': /* sig term */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000356 if (s->pid && s->state != S_FINISH)
357 stopservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000358 break;
359 case 'k': /* sig kill */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000360 if (s->pid && !custom(s, c))
361 kill(s->pid, SIGKILL);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000362 s->state = S_DOWN;
363 break;
364 case 'p': /* sig pause */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000365 if (s->pid && !custom(s, c))
366 kill(s->pid, SIGSTOP);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000367 s->ctrl |= C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000368 update_status(s);
369 break;
370 case 'c': /* sig cont */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000371 if (s->pid && !custom(s, c))
372 kill(s->pid, SIGCONT);
373 if (s->ctrl & C_PAUSE)
374 s->ctrl &= ~C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000375 update_status(s);
376 break;
377 case 'o': /* once */
378 s->want = W_DOWN;
379 update_status(s);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000380 if (!s->pid)
381 startservice(s);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000382 break;
383 case 'a': /* sig alarm */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000384 sig = SIGALRM;
385 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000386 case 'h': /* sig hup */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000387 sig = SIGHUP;
388 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000389 case 'i': /* sig int */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000390 sig = SIGINT;
391 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000392 case 'q': /* sig quit */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000393 sig = SIGQUIT;
394 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000395 case '1': /* sig usr1 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000396 sig = SIGUSR1;
397 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000398 case '2': /* sig usr2 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000399 sig = SIGUSR2;
400 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000401 }
402 return 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000403 sendsig:
404 if (s->pid && !custom(s, c))
405 kill(s->pid, sig);
406 return 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000407}
408
Denis Vlasenko06af2162007-02-03 17:28:39 +0000409int runsv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000410int runsv_main(int argc, char **argv)
411{
412 struct stat s;
413 int fd;
414 int r;
415 char buf[256];
416
Denis Vlasenko45946f82007-08-20 17:27:40 +0000417 if (!argv[1] || argv[2])
418 bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000419 dir = argv[1];
420
Denis Vlasenko5a6aedd2007-05-26 16:44:20 +0000421 xpipe(selfpipe);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000422 coe(selfpipe[0]);
423 coe(selfpipe[1]);
424 ndelay_on(selfpipe[0]);
425 ndelay_on(selfpipe[1]);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000426
Denis Vlasenko8c783952007-01-27 22:21:52 +0000427 sig_block(SIGCHLD);
428 sig_catch(SIGCHLD, s_child);
429 sig_block(SIGTERM);
430 sig_catch(SIGTERM, s_term);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000431
432 xchdir(dir);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000433 /* bss: svd[0].pid = 0; */
434 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
435 if (C_NOOP) svd[0].ctrl = C_NOOP;
436 if (W_UP) svd[0].want = W_UP;
437 /* bss: svd[0].islog = 0; */
438 /* bss: svd[1].pid = 0; */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000439 gettimeofday_ns(&svd[0].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000440 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
441
442 if (stat("log", &s) == -1) {
443 if (errno != ENOENT)
444 warn_cannot("stat ./log");
445 } else {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000446 if (!S_ISDIR(s.st_mode)) {
447 errno = 0;
448 warn_cannot("stat log/down: log is not a directory");
449 } else {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000450 haslog = 1;
451 svd[1].state = S_DOWN;
452 svd[1].ctrl = C_NOOP;
453 svd[1].want = W_UP;
454 svd[1].islog = 1;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000455 gettimeofday_ns(&svd[1].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000456 if (stat("log/down", &s) != -1)
457 svd[1].want = W_DOWN;
Denis Vlasenko5a6aedd2007-05-26 16:44:20 +0000458 xpipe(logpipe);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000459 coe(logpipe[0]);
460 coe(logpipe[1]);
461 }
462 }
463
464 if (mkdir("supervise", 0700) == -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000465 r = readlink("supervise", buf, sizeof(buf));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000466 if (r != -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000467 if (r == sizeof(buf))
468 fatal2x_cannot("readlink ./supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000469 buf[r] = 0;
470 mkdir(buf, 0700);
471 } else {
472 if ((errno != ENOENT) && (errno != EINVAL))
473 fatal_cannot("readlink ./supervise");
474 }
475 }
476 svd[0].fdlock = xopen3("log/supervise/lock"+4,
477 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
478 if (lock_exnb(svd[0].fdlock) == -1)
479 fatal_cannot("lock supervise/lock");
480 coe(svd[0].fdlock);
481 if (haslog) {
482 if (mkdir("log/supervise", 0700) == -1) {
483 r = readlink("log/supervise", buf, 256);
484 if (r != -1) {
485 if (r == 256)
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000486 fatal2x_cannot("readlink ./log/supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000487 buf[r] = 0;
488 fd = xopen(".", O_RDONLY|O_NDELAY);
489 xchdir("./log");
490 mkdir(buf, 0700);
491 if (fchdir(fd) == -1)
492 fatal_cannot("change back to service directory");
493 close(fd);
494 }
495 else {
496 if ((errno != ENOENT) && (errno != EINVAL))
497 fatal_cannot("readlink ./log/supervise");
498 }
499 }
500 svd[1].fdlock = xopen3("log/supervise/lock",
501 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
502 if (lock_ex(svd[1].fdlock) == -1)
503 fatal_cannot("lock log/supervise/lock");
504 coe(svd[1].fdlock);
505 }
506
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000507 mkfifo("log/supervise/control"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000508 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
509 coe(svd[0].fdcontrol);
510 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
511 coe(svd[0].fdcontrolwrite);
512 update_status(&svd[0]);
513 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000514 mkfifo("log/supervise/control", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000515 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
516 coe(svd[1].fdcontrol);
517 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
518 coe(svd[1].fdcontrolwrite);
519 update_status(&svd[1]);
520 }
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000521 mkfifo("log/supervise/ok"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000522 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
523 coe(fd);
524 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000525 mkfifo("log/supervise/ok", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000526 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
527 coe(fd);
528 }
529 for (;;) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000530 struct pollfd x[3];
531 unsigned deadline;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000532 char ch;
533
534 if (haslog)
535 if (!svd[1].pid && svd[1].want == W_UP)
536 startservice(&svd[1]);
537 if (!svd[0].pid)
538 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
539 startservice(&svd[0]);
540
541 x[0].fd = selfpipe[0];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000542 x[0].events = POLLIN;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000543 x[1].fd = svd[0].fdcontrol;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000544 x[1].events = POLLIN;
545 /* x[2] is used only if haslog == 1 */
546 x[2].fd = svd[1].fdcontrol;
547 x[2].events = POLLIN;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000548 sig_unblock(SIGTERM);
549 sig_unblock(SIGCHLD);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000550 poll(x, 2 + haslog, 3600*1000);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000551 sig_block(SIGTERM);
552 sig_block(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000553
554 while (read(selfpipe[0], &ch, 1) == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000555 continue;
556
Denis Vlasenko04c63862006-11-17 18:58:49 +0000557 for (;;) {
558 int child;
559 int wstat;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000560
Denis Vlasenko04c63862006-11-17 18:58:49 +0000561 child = wait_nohang(&wstat);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000562 if (!child)
563 break;
564 if ((child == -1) && (errno != EINTR))
565 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000566 if (child == svd[0].pid) {
567 svd[0].pid = 0;
568 pidchanged = 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000569 svd[0].ctrl &=~ C_TERM;
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000570 if (svd[0].state != S_FINISH) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000571 fd = open_read("finish");
572 if (fd != -1) {
573 close(fd);
574 svd[0].state = S_FINISH;
575 update_status(&svd[0]);
576 continue;
577 }
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000578 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000579 svd[0].state = S_DOWN;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000580 deadline = svd[0].start.tv_sec + 1;
581 gettimeofday_ns(&svd[0].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000582 update_status(&svd[0]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000583 if (LESS(svd[0].start.tv_sec, deadline))
584 sleep(1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000585 }
586 if (haslog) {
587 if (child == svd[1].pid) {
588 svd[1].pid = 0;
589 pidchanged = 1;
590 svd[1].state = S_DOWN;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000591 svd[1].ctrl &= ~C_TERM;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000592 deadline = svd[1].start.tv_sec + 1;
593 gettimeofday_ns(&svd[1].start);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000594 update_status(&svd[1]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000595 if (LESS(svd[1].start.tv_sec, deadline))
596 sleep(1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000597 }
598 }
599 }
600 if (read(svd[0].fdcontrol, &ch, 1) == 1)
601 ctrl(&svd[0], ch);
602 if (haslog)
603 if (read(svd[1].fdcontrol, &ch, 1) == 1)
604 ctrl(&svd[1], ch);
605
606 if (sigterm) {
607 ctrl(&svd[0], 'x');
608 sigterm = 0;
609 }
610
611 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
612 if (svd[1].pid == 0)
613 _exit(0);
614 if (svd[1].want != W_EXIT) {
615 svd[1].want = W_EXIT;
616 /* stopservice(&svd[1]); */
617 update_status(&svd[1]);
618 close(logpipe[1]);
619 close(logpipe[0]);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000620 }
621 }
622 }
623 /* not reached */
624 return 0;
625}