cp: make "cp file /dev/node" special case; explained in comments
[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 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>
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 static 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
79 struct svdir {
80         int pid;
81         smallint state;
82         smallint ctrl;
83         smallint want;
84         smallint islog;
85         struct timespec start;
86         int fdlock;
87         int fdcontrol;
88         int fdcontrolwrite;
89 };
90
91 static struct svdir svd[2];
92 static smallint sigterm;
93 static smallint haslog;
94 static smallint pidchanged = 1;
95 static int logpipe[2];
96 static char *dir;
97
98 static void fatal2_cannot(const char *m1, const char *m2)
99 {
100         bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
101         /* was exiting 111 */
102 }
103 static void fatal_cannot(const char *m)
104 {
105         fatal2_cannot(m, "");
106         /* was exiting 111 */
107 }
108 static void fatal2x_cannot(const char *m1, const char *m2)
109 {
110         bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
111         /* was exiting 111 */
112 }
113 static void warn_cannot(const char *m)
114 {
115         bb_perror_msg("%s: warning: cannot %s", dir, m);
116 }
117
118 static void s_child(int sig_no)
119 {
120         write(selfpipe[1], "", 1);
121 }
122
123 static void s_term(int sig_no)
124 {
125         sigterm = 1;
126         write(selfpipe[1], "", 1); /* XXX */
127 }
128
129 static 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
138 static 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
147 static 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
157 static void update_status(struct svdir *s)
158 {
159         ssize_t sz;
160         int fd;
161         svstatus_t status;
162
163         /* pid */
164         if (pidchanged) {
165                 fd = open_trunc_or_warn("supervise/pid.new");
166                 if (fd < 0)
167                         return;
168                 if (s->pid) {
169                         char spid[sizeof(int)*3 + 2];
170                         int size = sprintf(spid, "%u\n", (unsigned)s->pid);
171                         write(fd, spid, size);
172                 }
173                 close(fd);
174                 if (rename_or_warn("supervise/pid.new",
175                     s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
176                         return;
177                 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)
202                         switch (s->want) {
203                         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
215         rename_or_warn("supervise/stat.new",
216                 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
217
218         /* supervise compatibility */
219         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);
223         if (s->ctrl & C_PAUSE)
224                 status.paused = 1;
225         if (s->want == W_UP)
226                 status.want = 'u';
227         else
228                 status.want = 'd';
229         if (s->ctrl & C_TERM)
230                 status.got_term = 1;
231         status.run_or_finish = s->state;
232         fd = open_trunc_or_warn("supervise/status.new");
233         if (fd < 0)
234                 return;
235         sz = write(fd, &status, sizeof(status));
236         close(fd);
237         if (sz != sizeof(status)) {
238                 warn_cannot("write supervise/status.new");
239                 unlink("supervise/status.new");
240                 return;
241         }
242         rename_or_warn("supervise/status.new",
243                 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
244 }
245
246 static 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;
255         strcpy(a, "control/?");
256         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) {
265                                 if (haslog && dup2(logpipe[1], 1) == -1)
266                                         warn_cannot("setup stdout for control/?");
267                                 prog[0] = a;
268                                 prog[1] = NULL;
269                                 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                 }
279         } else {
280                 if (errno != ENOENT)
281                         warn_cannot("stat control/?");
282         }
283         return 0;
284 }
285
286 static void stopservice(struct svdir *s)
287 {
288         if (s->pid && !custom(s, 't')) {
289                 kill(s->pid, SIGTERM);
290                 s->ctrl |= C_TERM;
291                 update_status(s);
292         }
293         if (s->want == W_DOWN) {
294                 kill(s->pid, SIGCONT);
295                 custom(s, 'd');
296                 return;
297         }
298         if (s->want == W_EXIT) {
299                 kill(s->pid, SIGCONT);
300                 custom(s, 'x');
301         }
302 }
303
304 static void startservice(struct svdir *s)
305 {
306         int p;
307         char *run[2];
308
309         if (s->state == S_FINISH)
310                 run[0] = (char*)"./finish";
311         else {
312                 run[0] = (char*)"./run";
313                 custom(s, 'u');
314         }
315         run[1] = NULL;
316
317         if (s->pid != 0)
318                 stopservice(s); /* should never happen */
319         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) {
327                                 xdup2(logpipe[0], 0);
328                                 close(logpipe[1]);
329                                 xchdir("./log");
330                         } else {
331                                 xdup2(logpipe[1], 1);
332                                 close(logpipe[0]);
333                         }
334                 }
335                 signal(SIGCHLD, SIG_DFL);
336                 signal(SIGTERM, SIG_DFL);
337                 sig_unblock(SIGCHLD);
338                 sig_unblock(SIGTERM);
339                 execvp(*run, run);
340                 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
341         }
342         if (s->state != S_FINISH) {
343                 gettimeofday_ns(&s->start);
344                 s->state = S_RUN;
345         }
346         s->pid = p;
347         pidchanged = 1;
348         s->ctrl = C_NOOP;
349         update_status(s);
350 }
351
352 static int ctrl(struct svdir *s, char c)
353 {
354         int sig;
355
356         switch (c) {
357         case 'd': /* down */
358                 s->want = W_DOWN;
359                 update_status(s);
360                 if (s->pid && s->state != S_FINISH)
361                         stopservice(s);
362                 break;
363         case 'u': /* up */
364                 s->want = W_UP;
365                 update_status(s);
366                 if (s->pid == 0)
367                         startservice(s);
368                 break;
369         case 'x': /* exit */
370                 if (s->islog)
371                         break;
372                 s->want = W_EXIT;
373                 update_status(s);
374                 /* FALLTHROUGH */
375         case 't': /* sig term */
376                 if (s->pid && s->state != S_FINISH)
377                         stopservice(s);
378                 break;
379         case 'k': /* sig kill */
380                 if (s->pid && !custom(s, c))
381                         kill(s->pid, SIGKILL);
382                 s->state = S_DOWN;
383                 break;
384         case 'p': /* sig pause */
385                 if (s->pid && !custom(s, c))
386                         kill(s->pid, SIGSTOP);
387                 s->ctrl |= C_PAUSE;
388                 update_status(s);
389                 break;
390         case 'c': /* sig cont */
391                 if (s->pid && !custom(s, c))
392                         kill(s->pid, SIGCONT);
393                 if (s->ctrl & C_PAUSE)
394                         s->ctrl &= ~C_PAUSE;
395                 update_status(s);
396                 break;
397         case 'o': /* once */
398                 s->want = W_DOWN;
399                 update_status(s);
400                 if (!s->pid)
401                         startservice(s);
402                 break;
403         case 'a': /* sig alarm */
404                 sig = SIGALRM;
405                 goto sendsig;
406         case 'h': /* sig hup */
407                 sig = SIGHUP;
408                 goto sendsig;
409         case 'i': /* sig int */
410                 sig = SIGINT;
411                 goto sendsig;
412         case 'q': /* sig quit */
413                 sig = SIGQUIT;
414                 goto sendsig;
415         case '1': /* sig usr1 */
416                 sig = SIGUSR1;
417                 goto sendsig;
418         case '2': /* sig usr2 */
419                 sig = SIGUSR2;
420                 goto sendsig;
421         }
422         return 1;
423  sendsig:
424         if (s->pid && !custom(s, c))
425                 kill(s->pid, sig);
426         return 1;
427 }
428
429 int runsv_main(int argc, char **argv);
430 int runsv_main(int argc, char **argv)
431 {
432         struct stat s;
433         int fd;
434         int r;
435         char buf[256];
436
437         if (!argv[1] || argv[2])
438                 bb_show_usage();
439         dir = argv[1];
440
441         xpipe(selfpipe);
442         coe(selfpipe[0]);
443         coe(selfpipe[1]);
444         ndelay_on(selfpipe[0]);
445         ndelay_on(selfpipe[1]);
446
447         sig_block(SIGCHLD);
448         sig_catch(SIGCHLD, s_child);
449         sig_block(SIGTERM);
450         sig_catch(SIGTERM, s_term);
451
452         xchdir(dir);
453         /* 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; */
459         gettimeofday_ns(&svd[0].start);
460         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 {
466                 if (!S_ISDIR(s.st_mode)) {
467                         errno = 0;
468                         warn_cannot("stat log/down: log is not a directory");
469                 } else {
470                         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;
475                         gettimeofday_ns(&svd[1].start);
476                         if (stat("log/down", &s) != -1)
477                                 svd[1].want = W_DOWN;
478                         xpipe(logpipe);
479                         coe(logpipe[0]);
480                         coe(logpipe[1]);
481                 }
482         }
483
484         if (mkdir("supervise", 0700) == -1) {
485                 r = readlink("supervise", buf, sizeof(buf));
486                 if (r != -1) {
487                         if (r == sizeof(buf))
488                                 fatal2x_cannot("readlink ./supervise", ": name too long");
489                         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)
506                                         fatal2x_cannot("readlink ./log/supervise", ": name too long");
507                                 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
527         mkfifo("log/supervise/control"+4, 0600);
528         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) {
534                 mkfifo("log/supervise/control", 0600);
535                 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         }
541         mkfifo("log/supervise/ok"+4, 0600);
542         fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
543         coe(fd);
544         if (haslog) {
545                 mkfifo("log/supervise/ok", 0600);
546                 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
547                 coe(fd);
548         }
549         for (;;) {
550                 struct pollfd x[3];
551                 unsigned deadline;
552                 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];
562                 x[0].events = POLLIN;
563                 x[1].fd = svd[0].fdcontrol;
564                 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;
568                 sig_unblock(SIGTERM);
569                 sig_unblock(SIGCHLD);
570                 poll(x, 2 + haslog, 3600*1000);
571                 sig_block(SIGTERM);
572                 sig_block(SIGCHLD);
573
574                 while (read(selfpipe[0], &ch, 1) == 1)
575                         continue;
576
577                 for (;;) {
578                         int child;
579                         int wstat;
580
581                         child = wait_nohang(&wstat);
582                         if (!child)
583                                 break;
584                         if ((child == -1) && (errno != EINTR))
585                                 break;
586                         if (child == svd[0].pid) {
587                                 svd[0].pid = 0;
588                                 pidchanged = 1;
589                                 svd[0].ctrl &=~ C_TERM;
590                                 if (svd[0].state != S_FINISH) {
591                                         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                                         }
598                                 }
599                                 svd[0].state = S_DOWN;
600                                 deadline = svd[0].start.tv_sec + 1;
601                                 gettimeofday_ns(&svd[0].start);
602                                 update_status(&svd[0]);
603                                 if (LESS(svd[0].start.tv_sec, deadline))
604                                         sleep(1);
605                         }
606                         if (haslog) {
607                                 if (child == svd[1].pid) {
608                                         svd[1].pid = 0;
609                                         pidchanged = 1;
610                                         svd[1].state = S_DOWN;
611                                         svd[1].ctrl &= ~C_TERM;
612                                         deadline = svd[1].start.tv_sec + 1;
613                                         gettimeofday_ns(&svd[1].start);
614                                         update_status(&svd[1]);
615                                         if (LESS(svd[1].start.tv_sec, deadline))
616                                                 sleep(1);
617                                 }
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]);
640                         }
641                 }
642         }
643         /* not reached */
644         return 0;
645 }