runsv.c (15915B)
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <unistd.h> 4 #include <stdio.h> 5 #include <signal.h> 6 #include <poll.h> 7 #include "iopause.h" 8 #include "strerr.h" 9 #include "error.h" 10 #include "taia.h" 11 #include "sig.h" 12 #include "env.h" 13 #include "coe.h" 14 #include "ndelay.h" 15 #include "fifo.h" 16 #include "open.h" 17 #include "lock.h" 18 #include "wait.h" 19 #include <sys/wait.h> 20 #include "fd.h" 21 #include "buffer.h" 22 #include "fmt.h" 23 #include "byte.h" 24 25 #define USAGE " dir" 26 27 static char *progname; 28 static int selfpipe[2]; 29 30 /* state */ 31 #define S_DOWN 0 32 #define S_RUN 1 33 #define S_FINISH 2 34 /* ctrl */ 35 #define C_NOOP 0 36 #define C_TERM 1 37 #define C_PAUSE 2 38 /* want */ 39 #define W_UP 0 40 #define W_DOWN 1 41 #define W_EXIT 2 42 43 struct svdir { 44 int pid; 45 int state; 46 int ctrl; 47 int want; 48 struct taia start; 49 int wstat; 50 int fdlock; 51 int fdcontrol; 52 int fdcontrolwrite; 53 int islog; 54 }; 55 static struct svdir svd[2]; 56 57 static int sigterm =0; 58 static int haslog =0; 59 static int pidchanged =1; 60 static int logpipe[2]; 61 static char *dir; 62 63 static void usage () { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); } 64 65 static void fatal(char *m) 66 { 67 strerr_die5sys(111, "runsv ", dir, ": fatal: ", m, ": "); 68 } 69 static void fatal2(char *m1, char *m2) 70 { 71 strerr_die6sys(111, "runsv ", dir, ": fatal: ", m1, m2, ": "); 72 } 73 static void fatalx(char *m1, char *m2) 74 { 75 strerr_die5x(111, "runsv ", dir, ": fatal: ", m1, m2); 76 } 77 static void warn(char *m) 78 { 79 strerr_warn5("runsv ", dir, ": warning: ", m, ": ", &strerr_sys); 80 } 81 static void warn2(char *m1, char *m2) 82 { 83 strerr_warn6("runsv ", dir, ": warning: ", m1, m2, ": ", &strerr_sys); 84 } 85 static void warnx(char *m1, char *m2, char *m3) 86 { 87 strerr_warn6("runsv ", dir, ": warning: ", m1, m2, m3, 0); 88 } 89 90 static void stopservice(struct svdir *); 91 92 static void s_child() { write(selfpipe[1], "", 1); } 93 static void s_term() 94 { 95 sigterm =1; 96 write(selfpipe[1], "", 1); /* XXX */ 97 } 98 99 static void update_status(struct svdir *s) 100 { 101 unsigned long l; 102 int fd; 103 char status[20]; 104 char bspace[64]; 105 buffer b; 106 char spid[FMT_ULONG]; 107 char *fstatus ="supervise/status"; 108 char *fstatusnew ="supervise/status.new"; 109 char *fstat ="supervise/stat"; 110 char *fstatnew ="supervise/stat.new"; 111 char *fpid ="supervise/pid"; 112 char *fpidnew ="supervise/pid.new"; 113 114 if (s->islog) { 115 fstatus ="log/supervise/status"; 116 fstatusnew ="log/supervise/status.new"; 117 fstat ="log/supervise/stat"; 118 fstatnew ="log/supervise/stat.new"; 119 fpid ="log/supervise/pid"; 120 fpidnew ="log/supervise/pid.new"; 121 } 122 123 /* pid */ 124 if (pidchanged) { 125 if ((fd =open_trunc(fpidnew)) == -1) { 126 warn2("unable to open ", fpidnew); 127 return; 128 } 129 buffer_init(&b, buffer_unixwrite, fd, bspace, sizeof bspace); 130 spid[fmt_ulong(spid, (unsigned long)s->pid)] =0; 131 if (s->pid) { 132 buffer_puts(&b, spid); 133 buffer_puts(&b, "\n"); 134 buffer_flush(&b); 135 } 136 close(fd); 137 if (rename(fpidnew, fpid) == -1) { 138 warn2("unable to rename pid.new to ", fpid); 139 return; 140 } 141 pidchanged =0; 142 } 143 144 /* stat */ 145 if ((fd =open_trunc(fstatnew)) == -1) { 146 warn2("unable to open ", fstatnew); 147 return; 148 } 149 buffer_init(&b, buffer_unixwrite, fd, bspace, sizeof bspace); 150 switch (s->state) { 151 case S_DOWN: 152 buffer_puts(&b, "down"); 153 break; 154 case S_RUN: 155 buffer_puts(&b, "run"); 156 break; 157 case S_FINISH: 158 buffer_puts(&b, "finish"); 159 break; 160 } 161 if (s->ctrl & C_PAUSE) buffer_puts(&b, ", paused"); 162 if (s->ctrl & C_TERM) buffer_puts(&b, ", got TERM"); 163 if (s->state != S_DOWN) 164 switch(s->want) { 165 case W_DOWN: 166 buffer_puts(&b, ", want down"); 167 break; 168 case W_EXIT: 169 buffer_puts(&b, ", want exit"); 170 break; 171 } 172 buffer_puts(&b, "\n"); 173 buffer_flush(&b); 174 close(fd); 175 if (rename(fstatnew, fstat) == -1) 176 warn2("unable to rename stat.new to ", fstat); 177 178 /* supervise compatibility */ 179 taia_pack(status, &s->start); 180 l =(unsigned long)s->pid; 181 status[12] =l; l >>=8; 182 status[13] =l; l >>=8; 183 status[14] =l; l >>=8; 184 status[15] =l; 185 if (s->ctrl & C_PAUSE) 186 status[16] =1; 187 else 188 status[16] =0; 189 if (s->want == W_UP) 190 status[17] ='u'; 191 else 192 status[17] ='d'; 193 if (s->ctrl & C_TERM) 194 status[18] =1; 195 else 196 status[18] =0; 197 status[19] =s->state; 198 if ((fd =open_trunc(fstatusnew)) == -1) { 199 warn2("unable to open ", fstatusnew); 200 return; 201 } 202 if ((l =write(fd, status, sizeof status)) == -1) { 203 warn2("unable to write ", fstatusnew); 204 close(fd); 205 unlink(fstatusnew); 206 return; 207 } 208 close(fd); 209 if (l < sizeof status) { 210 warnx("unable to write ", fstatusnew, ": partial write."); 211 return; 212 } 213 if (rename(fstatusnew, fstatus) == -1) 214 warn2("unable to rename status.new to ", fstatus); 215 } 216 static unsigned int custom(struct svdir *s, char c) 217 { 218 int pid; 219 int w; 220 char a[10]; 221 struct stat st; 222 char *prog[2]; 223 224 if (s->islog) return(0); 225 byte_copy(a, 10, "control/?"); 226 a[8] =c; 227 if (stat(a, &st) == 0) { 228 if (st.st_mode & S_IXUSR) { 229 if ((pid =fork()) == -1) { 230 warn2("unable to fork for ", a); 231 return(0); 232 } 233 if (! pid) { 234 if (haslog && fd_copy(1, logpipe[1]) == -1) 235 warn2("unable to setup stdout for ", a); 236 prog[0] =a; 237 prog[1] =0; 238 execve(a, prog, environ); 239 fatal("unable to run control/?"); 240 } 241 while (wait_pid(&w, pid) == -1) { 242 if (errno == error_intr) continue; 243 warn2("unable to wait for child ", a); 244 return(0); 245 } 246 return(! wait_exitcode(w)); 247 } 248 } 249 else { 250 if (errno == error_noent) return(0); 251 warn2("unable to stat ", a); 252 } 253 return(0); 254 } 255 static void stopservice(struct svdir *s) 256 { 257 if (s->pid && ! custom(s, 't')) { 258 kill(s->pid, SIGTERM); 259 s->ctrl |=C_TERM; 260 update_status(s); 261 } 262 if (s->want == W_DOWN) { 263 kill(s->pid, SIGCONT); 264 custom(s, 'd'); return; 265 } 266 if (s->want == W_EXIT) { 267 kill(s->pid, SIGCONT); 268 custom(s, 'x'); 269 } 270 } 271 272 static void startservice(struct svdir *s) 273 { 274 int p; 275 char *run[4]; 276 char code[FMT_ULONG]; 277 char stat[FMT_ULONG]; 278 279 if (s->state == S_FINISH) { 280 run[0] ="./finish"; 281 code[fmt_ulong(code, wait_exitcode(s->wstat))] =0; 282 run[1] =wait_crashed(s->wstat) ? "-1" : code; 283 stat[fmt_ulong(stat, s->wstat & 0xff)] =0; 284 run[2] =stat; 285 run[3] =0; 286 } 287 else { 288 run[0] ="./run"; 289 custom(s, 'u'); 290 run[1] =0; 291 } 292 293 if (s->pid != 0) stopservice(s); /* should never happen */ 294 while ((p =fork()) == -1) { 295 warn("unable to fork, sleeping"); 296 sleep(5); 297 } 298 if (p == 0) { 299 /* child */ 300 if (haslog) { 301 if (s->islog) { 302 if (fd_copy(0, logpipe[0]) == -1) 303 fatal("unable to setup filedescriptor for ./log/run"); 304 close(logpipe[1]); 305 if (chdir("./log") == -1) 306 fatal("unable to change directory to ./log"); 307 } 308 else { 309 if (fd_copy(1, logpipe[1]) == -1) 310 fatal("unable to setup filedescriptor for ./run"); 311 close(logpipe[0]); 312 } 313 } 314 sig_uncatch(sig_child); 315 sig_unblock(sig_child); 316 sig_uncatch(sig_term); 317 sig_unblock(sig_term); 318 execve(*run, run, environ); 319 if (s->islog) 320 fatal2("unable to start log/", *run); 321 else 322 fatal2("unable to start ", *run); 323 } 324 if (s->state != S_FINISH) { 325 taia_now(&s->start); 326 s->state =S_RUN; 327 } 328 s->pid =p; 329 pidchanged =1; 330 s->ctrl =C_NOOP; 331 update_status(s); 332 } 333 static int ctrl(struct svdir *s, char c) 334 { 335 switch(c) { 336 case 'd': /* down */ 337 s->want =W_DOWN; 338 update_status(s); 339 if (s->state == S_RUN) stopservice(s); 340 break; 341 case 'u': /* up */ 342 s->want =W_UP; 343 update_status(s); 344 if (s->state == S_DOWN) startservice(s); 345 break; 346 case 'x': /* exit */ 347 if (s->islog) break; 348 s->want =W_EXIT; 349 update_status(s); 350 if (s->state == S_RUN) stopservice(s); 351 break; 352 case 't': /* sig term */ 353 if (s->state == S_RUN) stopservice(s); 354 break; 355 case 'k': /* sig kill */ 356 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGKILL); 357 s->state =S_DOWN; 358 break; 359 case 'p': /* sig pause */ 360 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGSTOP); 361 s->ctrl |=C_PAUSE; 362 update_status(s); 363 break; 364 case 'c': /* sig cont */ 365 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGCONT); 366 if (s->ctrl & C_PAUSE) s->ctrl &=~C_PAUSE; 367 update_status(s); 368 break; 369 case 'o': /* once */ 370 s->want =W_DOWN; 371 update_status(s); 372 if (s->state == S_DOWN) startservice(s); 373 break; 374 case 'a': /* sig alarm */ 375 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGALRM); 376 break; 377 case 'h': /* sig hup */ 378 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGHUP); 379 break; 380 case 'i': /* sig int */ 381 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGINT); 382 break; 383 case 'q': /* sig quit */ 384 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGQUIT); 385 break; 386 case '1': /* sig usr1 */ 387 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGUSR1); 388 break; 389 case '2': /* sig usr2 */ 390 if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGUSR2); 391 break; 392 } 393 return(1); 394 } 395 396 int main(int argc, char **argv) { 397 struct stat s; 398 int fd; 399 int r; 400 char buf[256]; 401 402 progname =argv[0]; 403 if (! argv[1] || argv[2]) usage(); 404 dir =argv[1]; 405 406 if (pipe(selfpipe) == -1) fatal("unable to create selfpipe"); 407 coe(selfpipe[0]); 408 coe(selfpipe[1]); 409 ndelay_on(selfpipe[0]); 410 ndelay_on(selfpipe[1]); 411 412 sig_block(sig_child); 413 sig_catch(sig_child, s_child); 414 sig_block(sig_term); 415 sig_catch(sig_term, s_term); 416 417 if (chdir(dir) == -1) fatal("unable to change to directory"); 418 svd[0].pid =0; 419 svd[0].state =S_DOWN; 420 svd[0].ctrl =C_NOOP; 421 svd[0].want =W_UP; 422 svd[0].islog =0; 423 svd[1].pid =0; 424 taia_now(&svd[0].start); 425 if (stat("down", &s) != -1) svd[0].want =W_DOWN; 426 427 if (stat("log", &s) == -1) { 428 if (errno != error_noent) 429 warn("unable to stat() ./log: "); 430 } 431 else { 432 if (! S_ISDIR(s.st_mode)) 433 warnx("./log", 0, ": not a directory."); 434 else { 435 haslog =1; 436 svd[1].state =S_DOWN; 437 svd[1].ctrl =C_NOOP; 438 svd[1].want =W_UP; 439 svd[1].islog =1; 440 taia_now(&svd[1].start); 441 if (stat("log/down", &s) != -1) 442 svd[1].want =W_DOWN; 443 if (pipe(logpipe) == -1) 444 fatal("unable to create log pipe"); 445 coe(logpipe[0]); 446 coe(logpipe[1]); 447 } 448 } 449 450 if (mkdir("supervise", 0700) == -1) { 451 if ((r =readlink("supervise", buf, 256)) != -1) { 452 if (r == 256) 453 fatalx("unable to readlink ./supervise: ", "name too long"); 454 buf[r] =0; 455 mkdir(buf, 0700); 456 } 457 else { 458 if ((errno != ENOENT) && (errno != EINVAL)) 459 fatal("unable to readlink ./supervise"); 460 } 461 } 462 if ((svd[0].fdlock =open_append("supervise/lock")) == -1) 463 fatal("unable to open supervise/lock"); 464 if (lock_exnb(svd[0].fdlock) == -1) fatal("unable to lock supervise/lock"); 465 coe(svd[0].fdlock); 466 if (haslog) { 467 if (mkdir("log/supervise", 0700) == -1) { 468 if ((r =readlink("log/supervise", buf, 256)) != -1) { 469 if (r == 256) 470 fatalx("unable to readlink ./log/supervise: ", "name too long"); 471 buf[r] =0; 472 if ((fd =open_read(".")) == -1) 473 fatal("unable to open current directory"); 474 if (chdir("./log") == -1) 475 fatal("unable to change directory to ./log"); 476 mkdir(buf, 0700); 477 if (fchdir(fd) == -1) 478 fatal("unable to change back to service directory"); 479 close(fd); 480 } 481 else { 482 if ((errno != ENOENT) && (errno != EINVAL)) 483 fatal("unable to readlink ./log/supervise"); 484 } 485 } 486 if ((svd[1].fdlock =open_append("log/supervise/lock")) == -1) 487 fatal("unable to open log/supervise/lock"); 488 if (lock_ex(svd[1].fdlock) == -1) 489 fatal("unable to lock log/supervise/lock"); 490 coe(svd[1].fdlock); 491 } 492 493 mkfifo("supervise/control", 0600); 494 if (stat("supervise/control", &s) == -1) 495 fatal("unable to stat supervise/control"); 496 if (!S_ISFIFO(s.st_mode)) 497 fatalx("supervise/control exists but is not a fifo", ""); 498 if ((svd[0].fdcontrol =open_read("supervise/control")) == -1) 499 fatal("unable to open supervise/control"); 500 coe(svd[0].fdcontrol); 501 if ((svd[0].fdcontrolwrite =open_write("supervise/control")) == -1) 502 fatal("unable to open supervise/control"); 503 coe(svd[0].fdcontrolwrite); 504 update_status(&svd[0]); 505 if (haslog) { 506 mkfifo("log/supervise/control", 0600); 507 if (stat("supervise/control", &s) == -1) 508 fatal("unable to stat log/supervise/control"); 509 if (!S_ISFIFO(s.st_mode)) 510 fatalx("log/supervise/control exists but is not a fifo", ""); 511 if ((svd[1].fdcontrol =open_read("log/supervise/control")) == -1) 512 fatal("unable to open log/supervise/control"); 513 coe(svd[1].fdcontrol); 514 if ((svd[1].fdcontrolwrite =open_write("log/supervise/control")) == -1) 515 fatal("unable to open log/supervise/control"); 516 coe(svd[1].fdcontrolwrite); 517 update_status(&svd[1]); 518 } 519 mkfifo("supervise/ok",0600); 520 if ((fd =open_read("supervise/ok")) == -1) 521 fatal("unable to read supervise/ok"); 522 coe(fd); 523 if (haslog) { 524 mkfifo("log/supervise/ok",0600); 525 if ((fd =open_read("log/supervise/ok")) == -1) 526 fatal("unable to read log/supervise/ok"); 527 coe(fd); 528 } 529 for (;;) { 530 struct pollfd x[3]; 531 struct taia deadline; 532 struct taia now; 533 char ch; 534 535 if (haslog) 536 if (! svd[1].pid && (svd[1].want == W_UP)) 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]; 542 x[0].events =POLLIN; 543 x[1].fd =svd[0].fdcontrol; 544 x[1].events =POLLIN; 545 if (haslog) { 546 x[2].fd =svd[1].fdcontrol; 547 x[2].events =POLLIN; 548 } 549 taia_now(&now); 550 taia_uint(&deadline, 3600); 551 taia_add(&deadline, &now, &deadline); 552 553 sig_unblock(sig_term); 554 sig_unblock(sig_child); 555 iopause(x, 2 +haslog, &deadline, &now); 556 sig_block(sig_term); 557 sig_block(sig_child); 558 559 while (read(selfpipe[0], &ch, 1) == 1) 560 ; 561 for (;;) { 562 int child; 563 int wstat; 564 565 child =waitpid( -1, &wstat, WNOHANG ); 566 if (!child) break; 567 if ((child == -1) && (errno != error_intr)) break; 568 if (child == svd[0].pid) { 569 svd[0].pid =0; 570 pidchanged =1; 571 svd[0].wstat =wstat; 572 svd[0].ctrl &=~C_TERM; 573 if (svd[0].state != S_FINISH) 574 if ((fd =open_read("finish")) != -1) { 575 close(fd); 576 svd[0].state =S_FINISH; 577 update_status(&svd[0]); 578 continue; 579 } 580 svd[0].state =S_DOWN; 581 taia_uint(&deadline, 1); 582 taia_add(&deadline, &svd[0].start, &deadline); 583 taia_now(&svd[0].start); 584 update_status(&svd[0]); 585 if (taia_less(&svd[0].start, &deadline)) sleep(1); 586 } 587 if (haslog) { 588 if (child == svd[1].pid) { 589 svd[1].pid =0; 590 pidchanged =1; 591 svd[1].state =S_DOWN; 592 svd[1].ctrl &=~C_TERM; 593 taia_uint(&deadline, 1); 594 taia_add(&deadline, &svd[1].start, &deadline); 595 taia_now(&svd[1].start); 596 update_status(&svd[1]); 597 if (taia_less(&svd[1].start, &deadline)) sleep(1); 598 } 599 } 600 } 601 if (read(svd[0].fdcontrol, &ch, 1) == 1) ctrl(&svd[0], ch); 602 if (haslog) 603 if (read(svd[1].fdcontrol, &ch, 1) == 1) ctrl(&svd[1], ch); 604 605 if (sigterm) { ctrl(&svd[0], 'x'); sigterm =0; } 606 607 if ((svd[0].want == W_EXIT) && (svd[0].state == S_DOWN)) { 608 if (svd[1].pid == 0) _exit(0); 609 if (svd[1].want != W_EXIT) { 610 svd[1].want =W_EXIT; 611 /* stopservice(&svd[1]); */ 612 update_status(&svd[1]); 613 if (close(logpipe[1]) == -1) warn("unable to close logpipe[1]"); 614 if (close(logpipe[0]) == -1) warn("unable to close logpipe[0]"); 615 } 616 } 617 } 618 }