httpd: don't send error messages with gzip encoding
[oweals/busybox.git] / runit / runsv.c
1 /*
2 Copyright (c) 2001-2006, Gerrit Pape
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, 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
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /* Busyboxed by Denys 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 #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 */
41 static void gettimeofday_ns(struct timespec *ts)
42 {
43         syscall(__NR_clock_gettime, CLOCK_REALTIME, ts);
44 }
45 #else
46 static 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
64 /* state */
65 #define S_DOWN 0
66 #define S_RUN 1
67 #define S_FINISH 2
68 /* ctrl */
69 #define C_NOOP 0
70 #define C_TERM 1
71 #define C_PAUSE 2
72 /* want */
73 #define W_UP 0
74 #define W_DOWN 1
75 #define W_EXIT 2
76
77 struct svdir {
78         int pid;
79         smallint state;
80         smallint ctrl;
81         smallint sd_want;
82         smallint islog;
83         struct timespec start;
84         int fdlock;
85         int fdcontrol;
86         int fdcontrolwrite;
87         int wstat;
88 };
89
90 struct globals {
91         smallint haslog;
92         smallint sigterm;
93         smallint pidchanged;
94         struct fd_pair selfpipe;
95         struct fd_pair logpipe;
96         char *dir;
97         struct svdir svd[2];
98 } FIX_ALIASING;
99 #define G (*(struct globals*)&bb_common_bufsiz1)
100 #define haslog       (G.haslog      )
101 #define sigterm      (G.sigterm     )
102 #define pidchanged   (G.pidchanged  )
103 #define selfpipe     (G.selfpipe    )
104 #define logpipe      (G.logpipe     )
105 #define dir          (G.dir         )
106 #define svd          (G.svd         )
107 #define INIT_G() do { \
108         pidchanged = 1; \
109 } while (0)
110
111 static void fatal2_cannot(const char *m1, const char *m2)
112 {
113         bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
114         /* was exiting 111 */
115 }
116 static void fatal_cannot(const char *m)
117 {
118         fatal2_cannot(m, "");
119         /* was exiting 111 */
120 }
121 static void fatal2x_cannot(const char *m1, const char *m2)
122 {
123         bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
124         /* was exiting 111 */
125 }
126 static void warn_cannot(const char *m)
127 {
128         bb_perror_msg("%s: warning: cannot %s", dir, m);
129 }
130
131 static void s_child(int sig_no UNUSED_PARAM)
132 {
133         write(selfpipe.wr, "", 1);
134 }
135
136 static void s_term(int sig_no UNUSED_PARAM)
137 {
138         sigterm = 1;
139         write(selfpipe.wr, "", 1); /* XXX */
140 }
141
142 static int open_trunc_or_warn(const char *name)
143 {
144         /* Why O_NDELAY? */
145         int fd = open(name, O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT, 0644);
146         if (fd < 0)
147                 bb_perror_msg("%s: warning: cannot open %s",
148                                 dir, name);
149         return fd;
150 }
151
152 static void update_status(struct svdir *s)
153 {
154         ssize_t sz;
155         int fd;
156         svstatus_t status;
157
158         /* pid */
159         if (pidchanged) {
160                 fd = open_trunc_or_warn("supervise/pid.new");
161                 if (fd < 0)
162                         return;
163                 if (s->pid) {
164                         char spid[sizeof(int)*3 + 2];
165                         int size = sprintf(spid, "%u\n", (unsigned)s->pid);
166                         write(fd, spid, size);
167                 }
168                 close(fd);
169                 if (rename_or_warn("supervise/pid.new",
170                     s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
171                         return;
172                 pidchanged = 0;
173         }
174
175         /* stat */
176         fd = open_trunc_or_warn("supervise/stat.new");
177         if (fd < -1)
178                 return;
179
180         {
181                 char stat_buf[sizeof("finish, paused, got TERM, want down\n")];
182                 char *p = stat_buf;
183                 switch (s->state) {
184                 case S_DOWN:
185                         p = stpcpy(p, "down");
186                         break;
187                 case S_RUN:
188                         p = stpcpy(p, "run");
189                         break;
190                 case S_FINISH:
191                         p = stpcpy(p, "finish");
192                         break;
193                 }
194                 if (s->ctrl & C_PAUSE)
195                         p = stpcpy(p, ", paused");
196                 if (s->ctrl & C_TERM)
197                         p = stpcpy(p, ", got TERM");
198                 if (s->state != S_DOWN)
199                         switch (s->sd_want) {
200                         case W_DOWN:
201                                 p = stpcpy(p, ", want down");
202                                 break;
203                         case W_EXIT:
204                                 p = stpcpy(p, ", want exit");
205                                 break;
206                         }
207                 *p++ = '\n';
208                 write(fd, stat_buf, p - stat_buf);
209                 close(fd);
210         }
211
212         rename_or_warn("supervise/stat.new",
213                 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
214
215         /* supervise compatibility */
216         memset(&status, 0, sizeof(status));
217         status.time_be64 = SWAP_BE64(s->start.tv_sec + 0x400000000000000aULL);
218         status.time_nsec_be32 = SWAP_BE32(s->start.tv_nsec);
219         status.pid_le32 = SWAP_LE32(s->pid);
220         if (s->ctrl & C_PAUSE)
221                 status.paused = 1;
222         if (s->sd_want == W_UP)
223                 status.want = 'u';
224         else
225                 status.want = 'd';
226         if (s->ctrl & C_TERM)
227                 status.got_term = 1;
228         status.run_or_finish = s->state;
229         fd = open_trunc_or_warn("supervise/status.new");
230         if (fd < 0)
231                 return;
232         sz = write(fd, &status, sizeof(status));
233         close(fd);
234         if (sz != sizeof(status)) {
235                 warn_cannot("write supervise/status.new");
236                 unlink("supervise/status.new");
237                 return;
238         }
239         rename_or_warn("supervise/status.new",
240                 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
241 }
242
243 static unsigned custom(struct svdir *s, char c)
244 {
245         pid_t pid;
246         int w;
247         char a[10];
248         struct stat st;
249
250         if (s->islog)
251                 return 0;
252         strcpy(a, "control/?");
253         a[8] = c; /* replace '?' */
254         if (stat(a, &st) == 0) {
255                 if (st.st_mode & S_IXUSR) {
256                         pid = vfork();
257                         if (pid == -1) {
258                                 warn_cannot("vfork for control/?");
259                                 return 0;
260                         }
261                         if (pid == 0) {
262                                 /* child */
263                                 if (haslog && dup2(logpipe.wr, 1) == -1)
264                                         warn_cannot("setup stdout for control/?");
265                                 execl(a, a, (char *) NULL);
266                                 fatal_cannot("run control/?");
267                         }
268                         /* parent */
269                         if (safe_waitpid(pid, &w, 0) == -1) {
270                                 warn_cannot("wait for child control/?");
271                                 return 0;
272                         }
273                         return WEXITSTATUS(w) == 0;
274                 }
275         } else {
276                 if (errno != ENOENT)
277                         warn_cannot("stat control/?");
278         }
279         return 0;
280 }
281
282 static void stopservice(struct svdir *s)
283 {
284         if (s->pid && !custom(s, 't')) {
285                 kill(s->pid, SIGTERM);
286                 s->ctrl |= C_TERM;
287                 update_status(s);
288         }
289         if (s->sd_want == W_DOWN) {
290                 kill(s->pid, SIGCONT);
291                 custom(s, 'd');
292                 return;
293         }
294         if (s->sd_want == W_EXIT) {
295                 kill(s->pid, SIGCONT);
296                 custom(s, 'x');
297         }
298 }
299
300 static void startservice(struct svdir *s)
301 {
302         int p;
303         const char *arg[4];
304         char exitcode[sizeof(int)*3 + 2];
305
306         if (s->state == S_FINISH) {
307 /* Two arguments are given to ./finish. The first one is ./run exit code,
308  * or -1 if ./run didnt exit normally. The second one is
309  * the least significant byte of the exit status as determined by waitpid;
310  * for instance it is 0 if ./run exited normally, and the signal number
311  * if ./run was terminated by a signal. If runsv cannot start ./run
312  * for some reason, the exit code is 111 and the status is 0.
313  */
314                 arg[0] = "./finish";
315                 arg[1] = "-1";
316                 if (WIFEXITED(s->wstat)) {
317                         *utoa_to_buf(WEXITSTATUS(s->wstat), exitcode, sizeof(exitcode)) = '\0';
318                         arg[1] = exitcode;
319                 }
320                 //arg[2] = "0";
321                 //if (WIFSIGNALED(s->wstat)) {
322                         arg[2] = utoa(WTERMSIG(s->wstat));
323                 //}
324                 arg[3] = NULL;
325         } else {
326                 arg[0] = "./run";
327                 arg[1] = NULL;
328                 custom(s, 'u');
329         }
330
331         if (s->pid != 0)
332                 stopservice(s); /* should never happen */
333         while ((p = vfork()) == -1) {
334                 warn_cannot("vfork, sleeping");
335                 sleep(5);
336         }
337         if (p == 0) {
338                 /* child */
339                 if (haslog) {
340                         /* NB: bug alert! right order is close, then dup2 */
341                         if (s->islog) {
342                                 xchdir("./log");
343                                 close(logpipe.wr);
344                                 xdup2(logpipe.rd, 0);
345                         } else {
346                                 close(logpipe.rd);
347                                 xdup2(logpipe.wr, 1);
348                         }
349                 }
350                 /* Non-ignored signals revert to SIG_DFL on exec anyway */
351                 /*bb_signals(0
352                         + (1 << SIGCHLD)
353                         + (1 << SIGTERM)
354                         , SIG_DFL);*/
355                 sig_unblock(SIGCHLD);
356                 sig_unblock(SIGTERM);
357                 execv(arg[0], (char**) arg);
358                 fatal2_cannot(s->islog ? "start log/" : "start ", arg[0]);
359         }
360         /* parent */
361         if (s->state != S_FINISH) {
362                 gettimeofday_ns(&s->start);
363                 s->state = S_RUN;
364         }
365         s->pid = p;
366         pidchanged = 1;
367         s->ctrl = C_NOOP;
368         update_status(s);
369 }
370
371 static int ctrl(struct svdir *s, char c)
372 {
373         int sig;
374
375         switch (c) {
376         case 'd': /* down */
377                 s->sd_want = W_DOWN;
378                 update_status(s);
379                 if (s->pid && s->state != S_FINISH)
380                         stopservice(s);
381                 break;
382         case 'u': /* up */
383                 s->sd_want = W_UP;
384                 update_status(s);
385                 if (s->pid == 0)
386                         startservice(s);
387                 break;
388         case 'x': /* exit */
389                 if (s->islog)
390                         break;
391                 s->sd_want = W_EXIT;
392                 update_status(s);
393                 /* FALLTHROUGH */
394         case 't': /* sig term */
395                 if (s->pid && s->state != S_FINISH)
396                         stopservice(s);
397                 break;
398         case 'k': /* sig kill */
399                 if (s->pid && !custom(s, c))
400                         kill(s->pid, SIGKILL);
401                 s->state = S_DOWN;
402                 break;
403         case 'p': /* sig pause */
404                 if (s->pid && !custom(s, c))
405                         kill(s->pid, SIGSTOP);
406                 s->ctrl |= C_PAUSE;
407                 update_status(s);
408                 break;
409         case 'c': /* sig cont */
410                 if (s->pid && !custom(s, c))
411                         kill(s->pid, SIGCONT);
412                 s->ctrl &= ~C_PAUSE;
413                 update_status(s);
414                 break;
415         case 'o': /* once */
416                 s->sd_want = W_DOWN;
417                 update_status(s);
418                 if (!s->pid)
419                         startservice(s);
420                 break;
421         case 'a': /* sig alarm */
422                 sig = SIGALRM;
423                 goto sendsig;
424         case 'h': /* sig hup */
425                 sig = SIGHUP;
426                 goto sendsig;
427         case 'i': /* sig int */
428                 sig = SIGINT;
429                 goto sendsig;
430         case 'q': /* sig quit */
431                 sig = SIGQUIT;
432                 goto sendsig;
433         case '1': /* sig usr1 */
434                 sig = SIGUSR1;
435                 goto sendsig;
436         case '2': /* sig usr2 */
437                 sig = SIGUSR2;
438                 goto sendsig;
439         }
440         return 1;
441  sendsig:
442         if (s->pid && !custom(s, c))
443                 kill(s->pid, sig);
444         return 1;
445 }
446
447 int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
448 int runsv_main(int argc UNUSED_PARAM, char **argv)
449 {
450         struct stat s;
451         int fd;
452         int r;
453         char buf[256];
454
455         INIT_G();
456
457         dir = single_argv(argv);
458
459         xpiped_pair(selfpipe);
460         close_on_exec_on(selfpipe.rd);
461         close_on_exec_on(selfpipe.wr);
462         ndelay_on(selfpipe.rd);
463         ndelay_on(selfpipe.wr);
464
465         sig_block(SIGCHLD);
466         bb_signals_recursive_norestart(1 << SIGCHLD, s_child);
467         sig_block(SIGTERM);
468         bb_signals_recursive_norestart(1 << SIGTERM, s_term);
469
470         xchdir(dir);
471         /* bss: svd[0].pid = 0; */
472         if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
473         if (C_NOOP) svd[0].ctrl = C_NOOP;
474         if (W_UP) svd[0].sd_want = W_UP;
475         /* bss: svd[0].islog = 0; */
476         /* bss: svd[1].pid = 0; */
477         gettimeofday_ns(&svd[0].start);
478         if (stat("down", &s) != -1)
479                 svd[0].sd_want = W_DOWN;
480
481         if (stat("log", &s) == -1) {
482                 if (errno != ENOENT)
483                         warn_cannot("stat ./log");
484         } else {
485                 if (!S_ISDIR(s.st_mode)) {
486                         errno = 0;
487                         warn_cannot("stat log/down: log is not a directory");
488                 } else {
489                         haslog = 1;
490                         svd[1].state = S_DOWN;
491                         svd[1].ctrl = C_NOOP;
492                         svd[1].sd_want = W_UP;
493                         svd[1].islog = 1;
494                         gettimeofday_ns(&svd[1].start);
495                         if (stat("log/down", &s) != -1)
496                                 svd[1].sd_want = W_DOWN;
497                         xpiped_pair(logpipe);
498                         close_on_exec_on(logpipe.rd);
499                         close_on_exec_on(logpipe.wr);
500                 }
501         }
502
503         if (mkdir("supervise", 0700) == -1) {
504                 r = readlink("supervise", buf, sizeof(buf));
505                 if (r != -1) {
506                         if (r == sizeof(buf))
507                                 fatal2x_cannot("readlink ./supervise", ": name too long");
508                         buf[r] = 0;
509                         mkdir(buf, 0700);
510                 } else {
511                         if ((errno != ENOENT) && (errno != EINVAL))
512                                 fatal_cannot("readlink ./supervise");
513                 }
514         }
515         svd[0].fdlock = xopen3("log/supervise/lock"+4,
516                         O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
517         if (flock(svd[0].fdlock, LOCK_EX | LOCK_NB) == -1)
518                 fatal_cannot("lock supervise/lock");
519         close_on_exec_on(svd[0].fdlock);
520         if (haslog) {
521                 if (mkdir("log/supervise", 0700) == -1) {
522                         r = readlink("log/supervise", buf, 256);
523                         if (r != -1) {
524                                 if (r == 256)
525                                         fatal2x_cannot("readlink ./log/supervise", ": name too long");
526                                 buf[r] = 0;
527                                 fd = xopen(".", O_RDONLY|O_NDELAY);
528                                 xchdir("./log");
529                                 mkdir(buf, 0700);
530                                 if (fchdir(fd) == -1)
531                                         fatal_cannot("change back to service directory");
532                                 close(fd);
533                         }
534                         else {
535                                 if ((errno != ENOENT) && (errno != EINVAL))
536                                         fatal_cannot("readlink ./log/supervise");
537                         }
538                 }
539                 svd[1].fdlock = xopen3("log/supervise/lock",
540                                 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
541                 if (flock(svd[1].fdlock, LOCK_EX) == -1)
542                         fatal_cannot("lock log/supervise/lock");
543                 close_on_exec_on(svd[1].fdlock);
544         }
545
546         mkfifo("log/supervise/control"+4, 0600);
547         svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
548         close_on_exec_on(svd[0].fdcontrol);
549         svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
550         close_on_exec_on(svd[0].fdcontrolwrite);
551         update_status(&svd[0]);
552         if (haslog) {
553                 mkfifo("log/supervise/control", 0600);
554                 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
555                 close_on_exec_on(svd[1].fdcontrol);
556                 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
557                 close_on_exec_on(svd[1].fdcontrolwrite);
558                 update_status(&svd[1]);
559         }
560         mkfifo("log/supervise/ok"+4, 0600);
561         fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
562         close_on_exec_on(fd);
563         if (haslog) {
564                 mkfifo("log/supervise/ok", 0600);
565                 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
566                 close_on_exec_on(fd);
567         }
568         for (;;) {
569                 struct pollfd x[3];
570                 unsigned deadline;
571                 char ch;
572
573                 if (haslog)
574                         if (!svd[1].pid && svd[1].sd_want == W_UP)
575                                 startservice(&svd[1]);
576                 if (!svd[0].pid)
577                         if (svd[0].sd_want == W_UP || svd[0].state == S_FINISH)
578                                 startservice(&svd[0]);
579
580                 x[0].fd = selfpipe.rd;
581                 x[0].events = POLLIN;
582                 x[1].fd = svd[0].fdcontrol;
583                 x[1].events = POLLIN;
584                 /* x[2] is used only if haslog == 1 */
585                 x[2].fd = svd[1].fdcontrol;
586                 x[2].events = POLLIN;
587                 sig_unblock(SIGTERM);
588                 sig_unblock(SIGCHLD);
589                 poll(x, 2 + haslog, 3600*1000);
590                 sig_block(SIGTERM);
591                 sig_block(SIGCHLD);
592
593                 while (read(selfpipe.rd, &ch, 1) == 1)
594                         continue;
595
596                 for (;;) {
597                         pid_t child;
598                         int wstat;
599
600                         child = wait_any_nohang(&wstat);
601                         if (!child)
602                                 break;
603                         if ((child == -1) && (errno != EINTR))
604                                 break;
605                         if (child == svd[0].pid) {
606                                 svd[0].wstat = wstat;
607                                 svd[0].pid = 0;
608                                 pidchanged = 1;
609                                 svd[0].ctrl &= ~C_TERM;
610                                 if (svd[0].state != S_FINISH) {
611                                         fd = open("finish", O_RDONLY|O_NDELAY);
612                                         if (fd != -1) {
613                                                 close(fd);
614                                                 svd[0].state = S_FINISH;
615                                                 update_status(&svd[0]);
616                                                 continue;
617                                         }
618                                 }
619                                 svd[0].state = S_DOWN;
620                                 deadline = svd[0].start.tv_sec + 1;
621                                 gettimeofday_ns(&svd[0].start);
622                                 update_status(&svd[0]);
623                                 if (LESS(svd[0].start.tv_sec, deadline))
624                                         sleep(1);
625                         }
626                         if (haslog) {
627                                 if (child == svd[1].pid) {
628                                         svd[0].wstat = wstat;
629                                         svd[1].pid = 0;
630                                         pidchanged = 1;
631                                         svd[1].state = S_DOWN;
632                                         svd[1].ctrl &= ~C_TERM;
633                                         deadline = svd[1].start.tv_sec + 1;
634                                         gettimeofday_ns(&svd[1].start);
635                                         update_status(&svd[1]);
636                                         if (LESS(svd[1].start.tv_sec, deadline))
637                                                 sleep(1);
638                                 }
639                         }
640                 } /* for (;;) */
641                 if (read(svd[0].fdcontrol, &ch, 1) == 1)
642                         ctrl(&svd[0], ch);
643                 if (haslog)
644                         if (read(svd[1].fdcontrol, &ch, 1) == 1)
645                                 ctrl(&svd[1], ch);
646
647                 if (sigterm) {
648                         ctrl(&svd[0], 'x');
649                         sigterm = 0;
650                 }
651
652                 if (svd[0].sd_want == W_EXIT && svd[0].state == S_DOWN) {
653                         if (svd[1].pid == 0)
654                                 _exit(EXIT_SUCCESS);
655                         if (svd[1].sd_want != W_EXIT) {
656                                 svd[1].sd_want = W_EXIT;
657                                 /* stopservice(&svd[1]); */
658                                 update_status(&svd[1]);
659                                 close(logpipe.wr);
660                                 close(logpipe.rd);
661                         }
662                 }
663         } /* for (;;) */
664         /* not reached */
665         return 0;
666 }