1 /* 2 * Copyright (c) 1980,1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)init.c 5.19 (Berkeley) 03/25/91"; 9 #endif not lint 10 11 #include <sys/types.h> 12 #include <sys/file.h> 13 #include <sys/signal.h> 14 #include <sys/reboot.h> 15 #include <sys/syslog.h> 16 #include <sys/stat.h> 17 #include <sys/ioctl.h> 18 #include <setjmp.h> 19 #include <utmp.h> 20 #include <errno.h> 21 #include <ttyent.h> 22 #include "pathnames.h" 23 24 #define CMDSIZ 200 /* max string length for getty or window command*/ 25 #define ALL p = itab; p ; p = p->next 26 #define EVER ;; 27 #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 28 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 29 30 char shell[] = _PATH_BSHELL; 31 char minus[] = "-"; 32 char runc[] = _PATH_RC; 33 char ctty[] = _PATH_CONSOLE; 34 35 struct tab 36 { 37 char line[UT_LINESIZE]; 38 char comn[CMDSIZ]; 39 char xflag; 40 int pid; 41 int wpid; /* window system pid for SIGHUP */ 42 char wcmd[CMDSIZ]; /* command to start window system process */ 43 time_t gettytime; 44 int gettycnt; 45 time_t windtime; 46 int windcnt; 47 struct tab *next; 48 } *itab; 49 50 int fi; 51 int mergflag; 52 char tty[20]; 53 jmp_buf sjbuf, shutpass; 54 55 char *strcpy(), *strcat(); 56 long lseek(); 57 void idle(), merge(), reset(); 58 59 struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 60 61 main(argc, argv) 62 char **argv; 63 { 64 /* insure proper semantics for setjmp/longjmp */ 65 static int howto, oldhowto, started = 0; 66 #if defined(tahoe) 67 register int r12; /* make sure r11 gets bootflags */ 68 #endif 69 #if defined(vax) || defined(tahoe) || defined(hp300) 70 /* howto passed in high-order register XXX */ 71 register int r11; /* passed thru from boot */ 72 #ifdef __GNUC__ 73 #ifdef hp300 74 asm("movl d7,%0" : "=rm" (howto)); 75 #else 76 asm("movl r11,%0" : "=rm" (howto)); 77 #endif 78 #else 79 howto = r11; 80 #endif /* __GNUC__ */ 81 #else /* vax || tahoe || hp300 */ 82 /* howto passed as argument */ 83 howto = 0; 84 #endif /* ! (vax || tahoe || hp300) */ 85 86 /* 87 * We expect a single options argument from the kernel. 88 * If it is present, we ignore anything in registers from above. 89 */ 90 if (argc > 1 && argv[1][0] == '-') { 91 char *cp; 92 93 howto = 0; 94 cp = &argv[1][1]; 95 while (*cp) switch (*cp++) { 96 #ifdef notyet 97 case 'f': 98 howto |= RB_FASTBOOT; 99 break; 100 #endif 101 case 's': 102 howto |= RB_SINGLE; 103 break; 104 } 105 } 106 if (getuid() != 0) 107 exit(1); 108 openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 109 if (setsid() < 0) 110 syslog(LOG_ERR, "setsid failed (initial) %m"); 111 sigvec(SIGTERM, &rvec, (struct sigvec *)0); 112 signal(SIGTSTP, idle); 113 signal(SIGTTIN, SIG_IGN); 114 signal(SIGTTOU, SIG_IGN); 115 (void) setjmp(sjbuf); 116 for (; ; ) { 117 oldhowto = howto; 118 howto = RB_SINGLE; 119 if (started && setjmp(shutpass) == 0) 120 shutdown(); 121 started = 1; 122 if (oldhowto & RB_SINGLE) 123 single(); 124 if (runcom(oldhowto) == 0) 125 continue; 126 merge(); 127 multiple(); 128 } 129 } 130 131 void shutreset(); 132 133 shutdown() 134 { 135 register i; 136 register struct tab *p, *p1; 137 138 signal(SIGHUP, SIG_IGN); 139 for (p = itab; p ; ) { 140 term(p); 141 p1 = p->next; 142 free(p); 143 p = p1; 144 } 145 itab = (struct tab *)0; 146 signal(SIGALRM, shutreset); 147 (void) kill(-1, SIGTERM); /* one chance to catch it */ 148 sleep(5); 149 alarm(30); 150 for (i = 0; i < 5; i++) 151 kill(-1, SIGKILL); 152 while (wait((int *)0) != -1) 153 ; 154 alarm(0); 155 shutend(); 156 } 157 158 char shutfailm[] = "init: WARNING: something is hung (won't die); ps axl advised\n"; 159 160 void 161 shutreset() 162 { 163 int status; 164 165 if (fork() == 0) { 166 int ct = open(ctty, 1); 167 write(ct, shutfailm, sizeof (shutfailm)); 168 sleep(5); 169 exit(1); 170 } 171 sleep(5); 172 shutend(); 173 longjmp(shutpass, 1); 174 } 175 176 shutend() 177 { 178 register i; 179 180 acct(0); 181 signal(SIGALRM, SIG_DFL); 182 for (i = 0; i < 10; i++) 183 close(i); 184 logwtmp("~", "shutdown", ""); 185 } 186 187 single() 188 { 189 register pid; 190 register xpid; 191 int fd; 192 extern int errno; 193 194 do { 195 pid = fork(); 196 if (pid == 0) { 197 signal(SIGTERM, SIG_DFL); 198 signal(SIGHUP, SIG_DFL); 199 signal(SIGALRM, SIG_DFL); 200 signal(SIGTSTP, SIG_IGN); 201 if (setsid() < 0) 202 syslog(LOG_ERR, "setsid failed (single): %m"); 203 (void) revoke(ctty); 204 if ((fd = open(ctty, O_RDWR)) < 0) { 205 syslog(LOG_ERR, "open %s: %m", ctty); 206 exit(1); 207 } 208 if (ioctl(fd, TIOCSCTTY, 0) < 0) 209 syslog(LOG_ERR, "TIOCSCTTY failed: %m"); 210 dup2(fd, 0); 211 dup2(fd, 1); 212 dup2(fd, 2); 213 if (fd > 2) 214 close(fd); 215 execl(shell, minus, (char *)0); 216 perror(shell); 217 exit(0); 218 } 219 while ((xpid = wait((int *)0)) != pid) 220 if (xpid == -1 && errno == ECHILD) 221 break; 222 } while (xpid == -1); 223 } 224 225 runcom(oldhowto) 226 int oldhowto; 227 { 228 register pid; 229 int fd, status; 230 231 pid = fork(); 232 if (pid == 0) { 233 signal(SIGTSTP, SIG_IGN); 234 signal(SIGHUP, SIG_IGN); 235 if ((fd = open(ctty, O_RDWR)) < 0) 236 syslog(LOG_ERR, "open %s: %m", ctty); 237 else { 238 dup2(fd, 0); 239 dup2(fd, 1); 240 dup2(fd, 2); 241 if (fd > 2) 242 close(fd); 243 } 244 if (setsid() < 0) 245 syslog(LOG_ERR, "setsid failed (runcom) %m"); 246 if (ioctl(0, TIOCSCTTY, 0) < 0) 247 syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m"); 248 if (oldhowto & RB_SINGLE) 249 execl(shell, shell, runc, (char *)0); 250 else 251 execl(shell, shell, runc, "autoboot", (char *)0); 252 exit(1); 253 } 254 while (wait(&status) != pid) 255 ; 256 if (status) 257 return (0); 258 logwtmp("~", "reboot", ""); 259 return (1); 260 } 261 262 struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 263 /* 264 * Multi-user. Listen for users leaving, SIGHUP's 265 * which indicate ttys has changed, and SIGTERM's which 266 * are used to shutdown the system. 267 */ 268 multiple() 269 { 270 extern int errno; 271 register struct tab *p; 272 register pid; 273 int omask; 274 275 sigvec(SIGHUP, &mvec, (struct sigvec *)0); 276 for (EVER) { 277 pid = wait((int *)0); 278 /* SHOULD FIX THIS IN THE KERNEL */ 279 if (pid == -1 && errno != EINTR) 280 return; 281 omask = sigblock(sigmask(SIGHUP)); 282 for (ALL) { 283 /* must restart window system BEFORE emulator */ 284 if (p->wpid == pid || p->wpid == -1) 285 wstart(p); 286 if (p->pid == pid || p->pid == -1) { 287 /* disown the window system */ 288 if (p->wpid) 289 kill(p->wpid, SIGHUP); 290 cleanutmp(p); 291 dfork(p); 292 } 293 } 294 sigsetmask(omask); 295 } 296 } 297 298 /* 299 * Merge current contents of ttys file 300 * into in-core table of configured tty lines. 301 * Entered as signal handler for SIGHUP. 302 */ 303 #define FOUND 1 304 #define CHANGE 2 305 #define WCHANGE 4 306 307 void 308 merge() 309 { 310 register struct tab *p; 311 register struct ttyent *t; 312 register struct tab *p1; 313 314 for (ALL) 315 p->xflag = 0; 316 setttyent(); 317 while (t = getttyent()) { 318 if ((t->ty_status & TTY_ON) == 0) 319 continue; 320 for (ALL) { 321 if (SCMPN(p->line, t->ty_name)) 322 continue; 323 p->xflag |= FOUND; 324 if (SCMPN(p->comn, t->ty_getty)) { 325 p->xflag |= CHANGE; 326 SCPYN(p->comn, t->ty_getty); 327 } 328 if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 329 p->xflag |= WCHANGE|CHANGE; 330 SCPYN(p->wcmd, t->ty_window); 331 } 332 goto contin1; 333 } 334 335 /* 336 * Make space for a new one 337 */ 338 p1 = (struct tab *)calloc(1, sizeof(*p1)); 339 if (!p1) { 340 syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 341 goto contin1; 342 } 343 /* 344 * Put new terminal at the end of the linked list. 345 */ 346 if (itab) { 347 for (p = itab; p->next ; p = p->next) 348 ; 349 p->next = p1; 350 } else 351 itab = p1; 352 353 p = p1; 354 SCPYN(p->line, t->ty_name); 355 p->xflag |= FOUND|CHANGE; 356 SCPYN(p->comn, t->ty_getty); 357 if (t->ty_window && strcmp(t->ty_window, "") != 0) { 358 p->xflag |= WCHANGE; 359 SCPYN(p->wcmd, t->ty_window); 360 } 361 contin1: 362 ; 363 } 364 endttyent(); 365 p1 = (struct tab *)0; 366 for (ALL) { 367 if ((p->xflag&FOUND) == 0) { 368 term(p); 369 wterm(p); 370 if (p1) 371 p1->next = p->next; 372 else 373 itab = p->next; 374 free(p); 375 p = p1 ? p1 : itab; 376 } else { 377 /* window system should be started first */ 378 if (p->xflag&WCHANGE) { 379 wterm(p); 380 wstart(p); 381 } 382 if (p->xflag&CHANGE) { 383 term(p); 384 dfork(p); 385 } 386 } 387 p1 = p; 388 } 389 } 390 391 term(p) 392 register struct tab *p; 393 { 394 395 if (p->pid != 0) { 396 cleanutmp(p); 397 kill(p->pid, SIGKILL); 398 } 399 p->pid = 0; 400 /* send SIGHUP to get rid of connections */ 401 if (p->wpid > 0) 402 kill(p->wpid, SIGHUP); 403 } 404 405 dfork(p) 406 struct tab *p; 407 { 408 register pid; 409 time_t t; 410 int dowait = 0; 411 412 time(&t); 413 p->gettycnt++; 414 if ((t - p->gettytime) >= 60) { 415 p->gettytime = t; 416 p->gettycnt = 1; 417 } else if (p->gettycnt >= 5) { 418 dowait = 1; 419 p->gettytime = t; 420 p->gettycnt = 1; 421 } 422 pid = fork(); 423 if (pid == 0) { 424 signal(SIGTERM, SIG_DFL); 425 signal(SIGHUP, SIG_IGN); 426 sigsetmask(0); /* since can be called from masked code */ 427 if (dowait) { 428 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 429 closelog(); 430 sleep(30); 431 } 432 if (setsid() < 0) 433 syslog(LOG_ERR, "setsid failed(dfork) %m"); 434 execit(p->comn, p->line); 435 exit(0); 436 } 437 p->pid = pid; 438 } 439 440 cleanutmp(p) 441 register struct tab *p; 442 { 443 if (logout(p->line)) { 444 logwtmp(p->line, "", ""); 445 /* 446 * After a proper login force reset 447 * of error detection code in dfork. 448 */ 449 p->gettytime = 0; 450 p->windtime = 0; 451 } 452 } 453 454 void 455 reset() 456 { 457 longjmp(sjbuf, 1); 458 } 459 460 jmp_buf idlebuf; 461 462 void 463 idlehup() 464 { 465 longjmp(idlebuf, 1); 466 } 467 468 void 469 idle() 470 { 471 register struct tab *p; 472 register pid; 473 474 signal(SIGHUP, idlehup); 475 for (EVER) { 476 if (setjmp(idlebuf)) 477 return; 478 pid = wait((int *) 0); 479 if (pid == -1) { 480 sigpause(0); 481 continue; 482 } 483 for (ALL) { 484 /* if window system dies, mark it for restart */ 485 if (p->wpid == pid) 486 p->wpid = -1; 487 if (p->pid == pid) { 488 cleanutmp(p); 489 p->pid = -1; 490 } 491 } 492 } 493 } 494 495 wterm(p) 496 register struct tab *p; 497 { 498 if (p->wpid != 0) { 499 kill(p->wpid, SIGKILL); 500 } 501 p->wpid = 0; 502 } 503 504 wstart(p) 505 register struct tab *p; 506 { 507 register pid; 508 time_t t; 509 int dowait = 0; 510 511 time(&t); 512 p->windcnt++; 513 if ((t - p->windtime) >= 60) { 514 p->windtime = t; 515 p->windcnt = 1; 516 } else if (p->windcnt >= 5) { 517 dowait = 1; 518 p->windtime = t; 519 p->windcnt = 1; 520 } 521 522 pid = fork(); 523 524 if (pid == 0) { 525 signal(SIGTERM, SIG_DFL); 526 signal(SIGHUP, SIG_IGN); 527 sigsetmask(0); /* since can be called from masked code */ 528 if (dowait) { 529 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 530 closelog(); 531 sleep(30); 532 } 533 if (setsid() < 0) 534 syslog(LOG_ERR, "setsid failed (window) %m"); 535 execit(p->wcmd, p->line); 536 exit(0); 537 } 538 p->wpid = pid; 539 } 540 541 #define NARGS 20 /* must be at least 4 */ 542 #define ARGLEN 512 /* total size for all the argument strings */ 543 544 execit(s, arg) 545 char *s; 546 char *arg; /* last argument on line */ 547 { 548 char *argv[NARGS], args[ARGLEN], *envp[1]; 549 register char *sp = s; 550 register char *ap = args; 551 register char c; 552 register int i; 553 554 /* 555 * First we have to set up the argument vector. 556 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 557 */ 558 for (i = 1; i < NARGS - 2; i++) { 559 argv[i] = ap; 560 for (EVER) { 561 if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 562 *ap = '\0'; 563 goto done; 564 } 565 if (c == ' ') { 566 *ap++ = '\0'; 567 while (*sp == ' ') 568 sp++; 569 if (*sp == '\0') 570 goto done; 571 break; 572 } 573 *ap++ = c; 574 } 575 } 576 done: 577 argv[0] = argv[1]; 578 argv[1] = "-"; 579 argv[i+1] = arg; 580 argv[i+2] = 0; 581 envp[0] = 0; 582 execve(argv[0], &argv[1], envp); 583 /* report failure of exec */ 584 syslog(LOG_ERR, "%s: %m", argv[0]); 585 closelog(); 586 sleep(10); /* prevent failures from eating machine */ 587 } 588