1 /* 2 * Copyright (c) 2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Handle remote listen/connect and parsing operations. 36 */ 37 38 #include "svc.h" 39 40 pthread_mutex_t serial_mtx; 41 time_t LastStart; /* uptime */ 42 time_t LastStop; /* uptime */ 43 pid_t DirectPid = -1; 44 runstate_t RunState = RS_STOPPED; 45 command_t *InitCmd; 46 int RestartCounter; 47 48 static void *logger_thread(void *arg); 49 static void setstate_stopped(command_t *cmd, struct timespec *ts); 50 static int setup_gid(command_t *cmd); 51 static int setup_uid(command_t *cmd); 52 static int setup_jail(command_t *cmd); 53 static int setup_chroot(command_t *cmd); 54 static int setup_devfs(command_t *cmd, const char *dir, int domount); 55 static int escapewrite(FILE *fp, char *buf, int n, int *statep); 56 57 int 58 execute_init(command_t *cmd) 59 { 60 char buf[32]; 61 pid_t pid; 62 pid_t stoppingpid = -1; 63 pthread_t logtd; 64 time_t nextstop = 0; 65 int lfd; /* unix domain listen socket */ 66 int pfd; /* pid file */ 67 int xfd; 68 int rc; 69 int fds[2]; 70 char c; 71 72 if (cmd->label == NULL || cmd->ext_ac == 0) { 73 fprintf(cmd->fp, "init requires a label and command\n"); 74 return 1; 75 } 76 fprintf(cmd->fp, "initializing new service: %s\n", cmd->label); 77 78 if ((xfd = open("/dev/null", O_RDWR)) < 0) { 79 fprintf(cmd->fp, "Unable to open /dev/null: %s\n", 80 strerror(errno)); 81 return 1; 82 } 83 84 /* 85 * Setup pidfile and unix domain listen socket and lock the 86 * pidfile. 87 */ 88 rc = setup_pid_and_socket(cmd, &lfd, &pfd); 89 if (rc) 90 return rc; 91 92 /* 93 * Detach the service 94 */ 95 if (cmd->foreground) { 96 /* 97 * Stay in foreground. 98 */ 99 fds[0] = -1; 100 fds[1] = -1; 101 pid = 0; 102 } else { 103 if (pipe(fds) < 0) { 104 fprintf(cmd->fp, "Unable to create pipe: %s\n", 105 strerror(errno)); 106 close(lfd); 107 close(pfd); 108 remove_pid_and_socket(cmd, cmd->label); 109 return 1; 110 } 111 pid = fork(); 112 } 113 114 if (pid != 0) { 115 /* 116 * Parent 117 */ 118 close(fds[1]); 119 if (pid < 0) { 120 fprintf(cmd->fp, "fork failed: %s\n", strerror(errno)); 121 close(lfd); 122 close(pfd); 123 close(fds[0]); 124 close(fds[1]); 125 remove_pid_and_socket(cmd, cmd->label); 126 return 1; 127 } else { 128 /* 129 * Fill-in pfd before returning. 130 */ 131 snprintf(buf, sizeof(buf), "%d\n", (int)pid); 132 write(pfd, buf, strlen(buf)); 133 } 134 close(lfd); 135 close(pfd); 136 137 /* 138 * Wait for child to completely detach from the tty 139 * before returning. 140 */ 141 read(fds[0], &c, 1); 142 close(fds[0]); 143 144 return 0; 145 } 146 147 /* 148 * Forked child is now the service demon. 149 * 150 * Detach from terminal, scrap tty, set process title. 151 */ 152 if (cmd->proctitle) { 153 setproctitle("%s - %s", cmd->label, cmd->proctitle); 154 } else { 155 setproctitle("%s", cmd->label); 156 } 157 if (cmd->mountdev) { 158 if (cmd->jaildir) 159 setup_devfs(cmd, cmd->jaildir, 1); 160 else if (cmd->rootdir) 161 setup_devfs(cmd, cmd->rootdir, 1); 162 } 163 164 if (cmd->foreground == 0) { 165 close(fds[0]); 166 fds[0] = -1; 167 } 168 169 if (xfd != 0) /* scrap tty inputs */ 170 dup2(xfd, 0); 171 if (cmd->foreground == 0) { 172 int tfd; 173 174 if (xfd != 1) /* scrap tty outputs */ 175 dup2(xfd, 1); 176 if (xfd != 2) 177 dup2(xfd, 2); 178 179 if ((tfd = open("/dev/tty", O_RDWR)) >= 0) { 180 ioctl(tfd, TIOCNOTTY, 0); /* no controlling tty */ 181 close(tfd); 182 } 183 setsid(); /* new session */ 184 } 185 186 /* 187 * Setup log file. The log file must not use descriptors 0, 1, or 2. 188 */ 189 if (cmd->logfile && strcmp(cmd->logfile, "/dev/null") == 0) 190 cmd->logfd = -1; 191 else if (cmd->logfile) 192 cmd->logfd = open(cmd->logfile, O_WRONLY|O_CREAT|O_APPEND, 0640); 193 else if (cmd->foreground) 194 cmd->logfd = dup(1); 195 else 196 cmd->logfd = -1; 197 198 /* 199 * Signal parent that we are completely detached now. 200 */ 201 c = 1; 202 if (cmd->foreground == 0) { 203 write(fds[1], &c, 1); 204 close(fds[1]); 205 fds[1] = -1; 206 } 207 InitCmd = cmd; 208 209 /* 210 * Setup log pipe. The logger thread copies the pipe to a buffer 211 * for the 'log' directive and also writes it to logfd. 212 */ 213 pipe(cmd->logfds); 214 if (cmd->fp != stdout) 215 fclose(cmd->fp); 216 cmd->fp = fdopen(cmd->logfds[1], "w"); 217 218 if (xfd > 2) { 219 close(xfd); 220 xfd = -1; 221 } 222 223 pthread_cond_init(&cmd->logcond, NULL); 224 225 /* 226 * Start accept thread for unix domain listen socket. 227 */ 228 pthread_mutex_lock(&serial_mtx); 229 pthread_create(&logtd, NULL, logger_thread, cmd); 230 remote_listener(cmd, lfd); 231 232 /* 233 * Become the reaper for all children recursively. 234 */ 235 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0) { 236 fprintf(cmd->fp, "svc is unable to become the " 237 "reaper for its children\n"); 238 fflush(cmd->fp); 239 } 240 241 /* 242 * Initial service start 243 */ 244 execute_start(cmd); 245 246 /* 247 * Main loop is the reaper 248 */ 249 for (;;) { 250 union reaper_info info; 251 struct timespec ts; 252 int status; 253 int dt; 254 pid_t usepid; 255 256 /* 257 * If we are running just block doing normal reaping, 258 * if we are stopping we have to poll for reaping while 259 * we handle stopping. 260 */ 261 fflush(cmd->fp); 262 if (RunState == RS_STARTED) { 263 pthread_mutex_unlock(&serial_mtx); 264 pid = wait3(&status, 0, NULL); 265 pthread_mutex_lock(&serial_mtx); 266 } else { 267 pid = wait3(&status, WNOHANG, NULL); 268 } 269 clock_gettime(CLOCK_MONOTONIC_FAST, &ts); 270 271 if (pid > 0) { 272 if (pid == DirectPid) { 273 fprintf(cmd->fp, 274 "svc %s: lost direct child %d\n", 275 cmd->label, pid); 276 fflush(cmd->fp); 277 DirectPid = -1; 278 if (cmd->restart_some) { 279 setstate_stopped(cmd, &ts); 280 } /* else still considered normal run state */ 281 } else if (cmd->debug) { 282 /* 283 * Reap random disconnected child, but don't 284 * spew to the log unless debugging is 285 * enabled. 286 */ 287 fprintf(cmd->fp, 288 "svc %s: reap indirect child %d\n", 289 cmd->label, 290 (int)pid); 291 } 292 } 293 294 /* 295 * Calculate the pid to potentially act on and/or 296 * determine if any children still exist. 297 */ 298 if (DirectPid >= 0) { 299 usepid = DirectPid; 300 } else if (procctl(P_PID, getpid(), 301 PROC_REAP_STATUS, &info) == 0) { 302 usepid = info.status.pid_head; 303 } else { 304 usepid = -1; 305 } 306 if (cmd->debug) { 307 fprintf(stderr, "svc %s: usepid %d\n", 308 cmd->label, usepid); 309 fflush(stderr); 310 } 311 312 /* 313 * If stoppingpid changes we have to reset the TERM->KILL 314 * timer. 315 */ 316 if (usepid < 0) { 317 setstate_stopped(cmd, &ts); 318 } else if (stoppingpid != usepid && 319 (RunState == RS_STOPPING2 || 320 RunState == RS_STOPPING3)) { 321 RunState = RS_STOPPING1; 322 } 323 stoppingpid = usepid; 324 325 /* 326 * State machine 327 */ 328 switch(RunState) { 329 case RS_STARTED: 330 if (usepid < 0) 331 setstate_stopped(cmd, &ts); 332 break; 333 case RS_STOPPED: 334 dt = (int)(ts.tv_sec - LastStop); 335 336 if (cmd->exit_mode) { 337 /* 338 * Service demon was told to exit on service 339 * stop (-x passed to init). 340 */ 341 fprintf(cmd->fp, 342 "svc %s: service demon exiting\n", 343 cmd->label); 344 remove_pid_and_socket(cmd, cmd->label); 345 goto exitloop; 346 } else if (cmd->manual_stop) { 347 /* 348 * Service demon was told to stop via 349 * commanded (not automatic) action. We 350 * do not auto-restart the service in 351 * this situation. 352 */ 353 pthread_mutex_unlock(&serial_mtx); 354 if (dt < 0 || dt > 60) 355 sleep(60); 356 else 357 sleep(1); 358 pthread_mutex_lock(&serial_mtx); 359 } else if (cmd->restart_some || cmd->restart_all) { 360 /* 361 * Handle automatic restarts 362 */ 363 if (dt > cmd->restart_timo) { 364 execute_start(cmd); 365 } else { 366 pthread_mutex_unlock(&serial_mtx); 367 sleep(1); 368 pthread_mutex_lock(&serial_mtx); 369 } 370 } else { 371 /* 372 * No automatic restart was configured, 373 * wait for commanded action. 374 */ 375 pthread_mutex_unlock(&serial_mtx); 376 if (dt < 0 || dt > 60) 377 sleep(60); 378 else 379 sleep(1); 380 pthread_mutex_lock(&serial_mtx); 381 } 382 break; 383 case RS_STOPPING1: 384 /* 385 * Reset TERM->KILL timer 386 */ 387 nextstop = ts.tv_sec; 388 RunState = RS_STOPPING2; 389 /* fall through */ 390 case RS_STOPPING2: 391 if (cmd->termkill_timo == 0) { 392 nextstop = ts.tv_sec - 1; 393 } else { 394 kill(stoppingpid, SIGTERM); 395 fprintf(cmd->fp, "svc %s: sigterm %d\n", 396 cmd->label, stoppingpid); 397 sleep(1); 398 } 399 RunState = RS_STOPPING3; 400 /* fall through */ 401 case RS_STOPPING3: 402 dt = (int)(ts.tv_sec - nextstop); 403 if (dt > cmd->termkill_timo) { 404 fprintf(cmd->fp, "svc %s: sigkill %d\n", 405 cmd->label, stoppingpid); 406 kill(stoppingpid, SIGKILL); 407 } 408 sleep(1); 409 break; 410 } 411 } 412 exitloop: 413 pthread_mutex_unlock(&serial_mtx); 414 if (cmd->mountdev) { 415 if (cmd->jaildir) 416 setup_devfs(cmd, cmd->jaildir, 0); 417 else if (cmd->rootdir) 418 setup_devfs(cmd, cmd->rootdir, 0); 419 } 420 exit(0); 421 /* does not return */ 422 } 423 424 int 425 execute_start(command_t *cmd) 426 { 427 struct timespec ts; 428 int maxwait = 60; 429 430 while (RunState == RS_STOPPING1 || 431 RunState == RS_STOPPING2 || 432 RunState == RS_STOPPING3) { 433 fprintf(cmd->fp, 434 "svc %s: Waiting for previous action to complete\n", 435 cmd->label); 436 fflush(cmd->fp); 437 pthread_mutex_unlock(&serial_mtx); 438 sleep(1); 439 pthread_mutex_lock(&serial_mtx); 440 if (--maxwait == 0) { 441 fprintf(cmd->fp, 442 "svc %s: Giving up waiting for action\n", 443 cmd->label); 444 fflush(cmd->fp); 445 break; 446 } 447 } 448 if (RunState == RS_STARTED) { 449 fprintf(cmd->fp, "svc %s: Already started pid %d\n", 450 cmd->label, DirectPid); 451 fflush(cmd->fp); 452 return 0; 453 } 454 455 clock_gettime(CLOCK_MONOTONIC_FAST, &ts); 456 if ((DirectPid = fork()) == 0) { 457 fflush(InitCmd->fp); 458 /* leave stdin /dev/null */ 459 dup2(fileno(InitCmd->fp), 1); /* setup stdout */ 460 dup2(fileno(InitCmd->fp), 2); /* setup stderr */ 461 closefrom(3); 462 463 if (cmd->jaildir) /* jail or chroot */ 464 setup_jail(cmd); 465 else if (cmd->rootdir) 466 setup_chroot(cmd); 467 468 setup_gid(cmd); 469 setup_uid(cmd); 470 execvp(InitCmd->ext_av[0], InitCmd->ext_av); 471 exit(99); 472 } 473 if (DirectPid >= 0) { 474 RunState = RS_STARTED; 475 LastStart = ts.tv_sec; 476 } else { 477 setstate_stopped(InitCmd, &ts); 478 } 479 InitCmd->manual_stop = 0; 480 fprintf(cmd->fp, "svc %s: Starting pid %d\n", cmd->label, DirectPid); 481 fflush(cmd->fp); 482 483 return 0; 484 } 485 486 int 487 execute_restart(command_t *cmd) 488 { 489 int rc; 490 491 rc = execute_stop(cmd) + execute_start(cmd); 492 return rc; 493 } 494 495 int 496 execute_stop(command_t *cmd) 497 { 498 union reaper_info info; 499 struct timespec ts; 500 int save_restart_some; 501 int save_restart_all; 502 int maxwait = 60; 503 504 save_restart_some = InitCmd->restart_some; 505 save_restart_all = InitCmd->restart_all; 506 if (cmd->commanded) 507 InitCmd->manual_stop = 1; 508 if (cmd->commanded && (cmd->restart_some || cmd->restart_all)) { 509 InitCmd->restart_some = cmd->restart_some; 510 InitCmd->restart_all = cmd->restart_all; 511 } 512 fprintf(cmd->fp, "svc %s: Stopping\n", cmd->label); 513 fflush(cmd->fp); 514 515 /* 516 * Start the kill chain going so the master loop's wait3 wakes up. 517 */ 518 if (DirectPid >= 0) { 519 kill(DirectPid, SIGTERM); 520 } else { 521 if (procctl(P_PID, getpid(), PROC_REAP_STATUS, &info) == 0 && 522 info.status.pid_head > 0) { 523 kill(info.status.pid_head, SIGTERM); 524 } 525 } 526 527 clock_gettime(CLOCK_MONOTONIC_FAST, &ts); 528 LastStop = ts.tv_sec; 529 RunState = RS_STOPPING1; 530 531 /* 532 * If commanded (verses automatic), we are running remote in our 533 * own thread and we need to wait for the action to complete. 534 */ 535 if (cmd->commanded) { 536 while (RunState == RS_STOPPING1 || 537 RunState == RS_STOPPING2 || 538 RunState == RS_STOPPING3) { 539 fprintf(cmd->fp, 540 "svc %s: Waiting for service to stop\n", 541 cmd->label); 542 fflush(cmd->fp); 543 pthread_mutex_unlock(&serial_mtx); 544 sleep(1); 545 pthread_mutex_lock(&serial_mtx); 546 if (--maxwait == 0) { 547 fprintf(cmd->fp, 548 "svc %s: Giving up waiting for stop\n", 549 cmd->label); 550 fflush(cmd->fp); 551 break; 552 } 553 } 554 if (cmd->restart_some || cmd->restart_all) { 555 InitCmd->restart_some = save_restart_some; 556 InitCmd->restart_all = save_restart_all; 557 } 558 } 559 560 return 0; 561 } 562 563 int 564 execute_exit(command_t *cmd) 565 { 566 if (cmd->commanded) { 567 InitCmd->restart_some = 0; 568 InitCmd->restart_all = 1; /* kill all children */ 569 InitCmd->exit_mode = 1; /* exit after stop */ 570 } else { 571 cmd->exit_mode = 1; 572 } 573 fprintf(cmd->fp, "svc %s: Stopping and Exiting\n", cmd->label); 574 execute_stop(cmd); 575 576 return 0; 577 } 578 579 int 580 execute_list(command_t *cmd) 581 { 582 fprintf(cmd->fp, "%-16s\n", cmd->label); 583 584 return 0; 585 } 586 587 int 588 execute_status(command_t *cmd) 589 { 590 const char *state; 591 592 switch(RunState) { 593 case RS_STOPPED: 594 if (InitCmd && InitCmd->exit_mode) 595 state = "stopped (exiting)"; 596 else if (InitCmd && InitCmd->manual_stop) 597 state = "stopped (manual)"; 598 else 599 state = "stopped"; 600 break; 601 case RS_STARTED: 602 state = "running"; 603 break; 604 case RS_STOPPING1: 605 case RS_STOPPING2: 606 case RS_STOPPING3: 607 state = "killing"; 608 break; 609 default: 610 state = "unknown"; 611 break; 612 } 613 614 fprintf(cmd->fp, "%-16s %s\n", cmd->label, state); 615 616 return 0; 617 } 618 619 int 620 execute_log(command_t *cmd) 621 { 622 int lbsize = (int)sizeof(cmd->logbuf); 623 int lbmask = lbsize - 1; 624 int windex; 625 int n; 626 int lastnl; 627 int dotstate; 628 char buf[LOGCHUNK]; 629 630 assert(InitCmd); 631 632 /* 633 * mode 0 - Dump everything then exit 634 * mode 1 - Dump everything then block/loop 635 * mode 2 - Skeep to end then block/loop 636 */ 637 if (cmd->tail_mode == 2) 638 windex = InitCmd->logwindex; 639 else 640 windex = InitCmd->logwindex - InitCmd->logcount; 641 lastnl = 1; 642 dotstate = 0; /* 0=start-of-line 1=middle-of-line 2=dot */ 643 644 for (;;) { 645 /* 646 * Calculate the amount of data we missed and determine 647 * if some data was lost. 648 */ 649 n = InitCmd->logwindex - windex; 650 if (n < 0 || n > InitCmd->logcount) { 651 windex = InitCmd->logwindex - InitCmd->logcount; 652 pthread_mutex_unlock(&serial_mtx); 653 fprintf(cmd->fp, "\n(LOG DATA LOST)\n"); 654 pthread_mutex_lock(&serial_mtx); 655 continue; 656 } 657 658 /* 659 * Circular buffer and copy size limitations. If no 660 * data ready, wait for some. 661 */ 662 if (n > lbsize - (windex & lbmask)) 663 n = lbsize - (windex & lbmask); 664 if (n > LOGCHUNK) 665 n = LOGCHUNK; 666 if (n == 0) { 667 if (cmd->tail_mode == 0) 668 break; 669 pthread_cond_wait(&InitCmd->logcond, &serial_mtx); 670 continue; 671 } 672 bcopy(InitCmd->logbuf + (windex & lbmask), buf, n); 673 674 /* 675 * Dump log output, escape any '.' on a line by itself. 676 */ 677 pthread_mutex_unlock(&serial_mtx); 678 n = escapewrite(cmd->fp, buf, n, &dotstate); 679 fflush(cmd->fp); 680 if (n > 0) 681 lastnl = (buf[n-1] == '\n'); 682 pthread_mutex_lock(&serial_mtx); 683 684 if (n < 0) 685 break; 686 windex += n; 687 } 688 if (lastnl == 0) { 689 pthread_mutex_unlock(&serial_mtx); 690 fprintf(cmd->fp, "\n"); 691 pthread_mutex_lock(&serial_mtx); 692 } 693 return 0; 694 } 695 696 /* 697 * Change or reopen logfile. 698 */ 699 int 700 execute_logfile(command_t *cmd) 701 { 702 char *logfile; 703 int fd; 704 int rc; 705 706 assert(InitCmd); 707 708 logfile = cmd->logfile; 709 if (cmd->ext_av && cmd->ext_av[0]) 710 logfile = cmd->ext_av[0]; 711 if (logfile == NULL) 712 logfile = InitCmd->logfile; 713 714 rc = 0; 715 if (logfile) { 716 if (InitCmd->logfile && 717 strcmp(InitCmd->logfile, logfile) == 0) { 718 fprintf(cmd->fp, "svc %s: Reopen logfile %s\n", 719 cmd->label, logfile); 720 } else { 721 fprintf(cmd->fp, "svc %s: Change logfile to %s\n", 722 cmd->label, logfile); 723 } 724 if (InitCmd->logfd >= 0) { 725 close(InitCmd->logfd); 726 InitCmd->logfd = -1; 727 } 728 if (strcmp(logfile, "/dev/null") == 0) { 729 sreplace(&InitCmd->logfile, logfile); 730 } else { 731 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0640); 732 if (fd >= 0) { 733 InitCmd->logfd = fd; 734 sreplace(&InitCmd->logfile, logfile); 735 } else { 736 fprintf(cmd->fp, 737 "svc %s: Unable to open/create " 738 "\"%s\": %s\n", 739 cmd->label, 740 logfile, strerror(errno)); 741 rc = 1; 742 } 743 } 744 } 745 return rc; 746 } 747 748 int 749 execute_help(command_t *cmd) 750 { 751 fprintf(cmd->fp, 752 "svc [options] directive [label [additional_args]]\n" 753 "\n" 754 "Directives: init start stop stopall restart exit\n" 755 " kill list status log logf tailf logfile\n" 756 " help\n" 757 ); 758 return 0; 759 } 760 761 static 762 void * 763 logger_thread(void *arg) 764 { 765 command_t *cmd = arg; 766 int lbsize = (int)sizeof(cmd->logbuf); 767 int lbmask = lbsize - 1; 768 int windex; 769 int n; 770 771 pthread_detach(pthread_self()); 772 pthread_mutex_lock(&serial_mtx); 773 for (;;) { 774 /* 775 * slip circular buffer to make room for new data. 776 */ 777 n = cmd->logcount - (lbsize - LOGCHUNK); 778 if (n > 0) { 779 cmd->logcount -= n; 780 cmd->logwindex += n; 781 } 782 windex = cmd->logwindex & lbmask; 783 n = lbsize - windex; 784 if (n > LOGCHUNK) 785 n = LOGCHUNK; 786 pthread_mutex_unlock(&serial_mtx); 787 n = read(cmd->logfds[0], cmd->logbuf + windex, n); 788 pthread_mutex_lock(&serial_mtx); 789 if (n > 0) { 790 if (cmd->logfd >= 0) 791 write(cmd->logfd, cmd->logbuf + windex, n); 792 cmd->logcount += n; 793 cmd->logwindex += n; 794 pthread_cond_signal(&cmd->logcond); 795 } 796 if (n == 0 || (n < 0 && errno != EINTR)) 797 break; 798 } 799 pthread_mutex_unlock(&serial_mtx); 800 return NULL; 801 } 802 803 /* 804 * Put us in the STOPPED state if we are not already there, and 805 * handle post-stop options (aka sync). 806 */ 807 static 808 void 809 setstate_stopped(command_t *cmd, struct timespec *ts) 810 { 811 if (RunState != RS_STOPPED) { 812 RunState = RS_STOPPED; 813 LastStop = ts->tv_sec; 814 if (cmd->sync_mode) /* support -s option */ 815 sync(); 816 } 817 } 818 819 static 820 int 821 setup_gid(command_t *cmd) 822 { 823 int i; 824 825 if (cmd->gid_mode && 826 setgid(cmd->grent.gr_gid) < 0) { 827 fprintf(cmd->fp, "unable to setgid to \"%s\": %s\n", 828 cmd->grent.gr_name, strerror(errno)); 829 return 1; 830 } 831 832 /* 833 * -G overrides all group ids. 834 */ 835 if (cmd->ngroups) { 836 if (setgroups(cmd->ngroups, cmd->groups) < 0) { 837 fprintf(cmd->fp, "unable to setgroups to ("); 838 for (i = 0; i < cmd->ngroups; ++i) { 839 if (i) 840 fprintf(cmd->fp, ", "); 841 fprintf(cmd->fp, "%d", cmd->groups[i]); 842 } 843 fprintf(cmd->fp, "): %s\n", strerror(errno)); 844 return 1; 845 } 846 } 847 return 0; 848 } 849 850 static 851 int 852 setup_uid(command_t *cmd) 853 { 854 fprintf(stderr, "UIDMODE %d %d\n", cmd->uid_mode, cmd->pwent.pw_uid); 855 if (cmd->uid_mode && 856 cmd->gid_mode == 0 && 857 cmd->ngroups == 0 && 858 setgid(cmd->pwent.pw_gid) < 0) { 859 fprintf(cmd->fp, "unable to setgid for user \"%s\": %s\n", 860 cmd->pwent.pw_name, 861 strerror(errno)); 862 return 1; 863 } 864 if (cmd->uid_mode && 865 setuid(cmd->pwent.pw_uid) < 0) { 866 fprintf(cmd->fp, "unable to setuid for user \"%s\": %s\n", 867 cmd->pwent.pw_name, 868 strerror(errno)); 869 return 1; 870 } 871 return 0; 872 } 873 874 static 875 int 876 setup_jail(command_t *cmd) 877 { 878 struct jail info; 879 char hostbuf[256]; 880 881 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0) { 882 fprintf(cmd->fp, "gethostname() failed: %s\n", strerror(errno)); 883 return 1; 884 } 885 /* make sure it is zero terminated */ 886 hostbuf[sizeof(hostbuf) -1] = 0; 887 888 bzero(&info, sizeof(info)); 889 info.version = 1; 890 info.path = cmd->jaildir; 891 info.hostname = hostbuf; 892 /* info.n_ips, sockaddr_storage ips[] */ 893 894 if (jail(&info) < 0) { 895 fprintf(cmd->fp, "unable to create jail \"%s\": %s\n", 896 cmd->rootdir, 897 strerror(errno)); 898 return 1; 899 } 900 return 0; 901 } 902 903 static 904 int 905 setup_chroot(command_t *cmd) 906 { 907 if (chroot(cmd->rootdir) < 0) { 908 fprintf(cmd->fp, "unable to chroot to \"%s\": %s\n", 909 cmd->rootdir, 910 strerror(errno)); 911 return 1; 912 } 913 return 0; 914 } 915 916 static 917 int 918 setup_devfs(command_t *cmd, const char *dir, int domount) 919 { 920 struct devfs_mount_info info; 921 struct statfs fs; 922 int rc = 0; 923 char *path; 924 925 bzero(&info, sizeof(info)); 926 info.flags = 0; 927 asprintf(&path, "%s/dev", dir); 928 929 if (domount) { 930 if (statfs(path, &fs) == 0 && 931 strcmp(fs.f_fstypename, "devfs") == 0) { 932 fprintf(cmd->fp, "devfs already mounted\n"); 933 } else 934 if (mount("devfs", path, MNT_NOEXEC|MNT_NOSUID, &info) < 0) { 935 fprintf(cmd->fp, "cannot mount devfs on %s: %s\n", 936 path, strerror(errno)); 937 rc = 1; 938 } 939 } else { 940 if (statfs(path, &fs) < 0 || 941 strcmp(fs.f_fstypename, "devfs") != 0) { 942 fprintf(cmd->fp, "devfs already unmounted\n"); 943 } else 944 if (unmount(path, 0) < 0) { 945 fprintf(cmd->fp, "cannot unmount devfs from %s: %s\n", 946 path, strerror(errno)); 947 rc = 1; 948 } 949 } 950 free(path); 951 return rc; 952 } 953 954 /* 955 * Escape writes. A '.' on a line by itself must be escaped to '..'. 956 */ 957 static 958 int 959 escapewrite(FILE *fp, char *buf, int n, int *statep) 960 { 961 int b; 962 int i; 963 int r; 964 char c; 965 966 b = 0; 967 r = 0; 968 i = 0; 969 while (i < n) { 970 for (i = b; i < n; ++i) { 971 c = buf[i]; 972 973 switch(*statep) { 974 case 0: 975 /* 976 * beginning of line 977 */ 978 if (c == '.') 979 *statep = 2; 980 else if (c != '\n') 981 *statep = 1; 982 break; 983 case 1: 984 /* 985 * middle of line 986 */ 987 if (c == '\n') 988 *statep = 0; 989 break; 990 case 2: 991 /* 992 * dot was output at beginning of line 993 */ 994 if (c == '\n') 995 *statep = 3; 996 else 997 *statep = 1; 998 break; 999 default: 1000 break; 1001 } 1002 if (*statep == 3) /* flush with escape */ 1003 break; 1004 } 1005 if (i != b) { 1006 n = fwrite(buf, 1, i - b, fp); 1007 if (n > 0) 1008 r += n; 1009 if (n < 0) 1010 r = -1; 1011 } 1012 if (*statep == 3) { /* added escape */ 1013 n = fwrite(".", 1, 1, fp); 1014 /* escapes not counted in r */ 1015 *statep = 1; 1016 if (n < 0) 1017 r = -1; 1018 } 1019 if (r < 0) 1020 break; 1021 } 1022 return r; 1023 } 1024