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.17 (Berkeley) 06/24/90"; 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 #if defined(tahoe) 65 register int r12; /* make sure r11 gets bootflags */ 66 #endif 67 #if defined(vax) || defined(tahoe) || defined(hp300) 68 register int r11; /* passed thru from boot */ 69 #endif 70 #ifdef __GNUC__ 71 /* insure proper semantics for setjmp/longjmp */ 72 static 73 #endif 74 int howto, oldhowto, started = 0; 75 76 #if defined(vax) || defined(tahoe) || defined(hp300) 77 /* howto passed in high-order register XXX */ 78 #ifdef __GNUC__ 79 #ifdef hp300 80 asm("movl d7,%0" : "=rm" (howto)); 81 #else 82 asm("movl r11,%0" : "=rm" (howto)); 83 #endif 84 #else 85 howto = r11; 86 #endif /* __GNUC__ */ 87 #else /* defined(vax) || defined(tahoe) || defined(hp300) */ 88 /* howto passed as argument */ 89 if (argc > 1 && argv[1][0] == '-') { 90 char *cp; 91 92 howto = 0; 93 cp = &argv[1][1]; 94 while (*cp) switch (*cp++) { 95 case 'a': 96 howto |= RB_ASKNAME; 97 break; 98 case 's': 99 howto |= RB_SINGLE; 100 break; 101 } 102 } else 103 howto = RB_SINGLE; 104 #endif 105 if (getuid() != 0) 106 exit(1); 107 openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 108 if (setsid() < 0) 109 syslog(LOG_ERR, "setsid failed (initial) %m"); 110 sigvec(SIGTERM, &rvec, (struct sigvec *)0); 111 signal(SIGTSTP, idle); 112 signal(SIGSTOP, SIG_IGN); 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 status; 230 231 pid = fork(); 232 if (pid == 0) { 233 (void) open(ctty, O_RDONLY); 234 dup2(0, 1); 235 dup2(0, 2); 236 if (setsid() < 0) 237 syslog(LOG_ERR, "setsid failed (runcom) %m"); 238 if (ioctl(0, TIOCSCTTY, 0) < 0) 239 syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m"); 240 if (oldhowto & RB_SINGLE) 241 execl(shell, shell, runc, (char *)0); 242 else 243 execl(shell, shell, runc, "autoboot", (char *)0); 244 exit(1); 245 } 246 while (wait(&status) != pid) 247 ; 248 if (status) 249 return (0); 250 logwtmp("~", "reboot", ""); 251 return (1); 252 } 253 254 struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 255 /* 256 * Multi-user. Listen for users leaving, SIGHUP's 257 * which indicate ttys has changed, and SIGTERM's which 258 * are used to shutdown the system. 259 */ 260 multiple() 261 { 262 extern int errno; 263 register struct tab *p; 264 register pid; 265 int omask; 266 267 sigvec(SIGHUP, &mvec, (struct sigvec *)0); 268 for (EVER) { 269 pid = wait((int *)0); 270 /* SHOULD FIX THIS IN THE KERNEL */ 271 if (pid == -1 && errno != EINTR) 272 return; 273 omask = sigblock(sigmask(SIGHUP)); 274 for (ALL) { 275 /* must restart window system BEFORE emulator */ 276 if (p->wpid == pid || p->wpid == -1) 277 wstart(p); 278 if (p->pid == pid || p->pid == -1) { 279 /* disown the window system */ 280 if (p->wpid) 281 kill(p->wpid, SIGHUP); 282 cleanutmp(p); 283 dfork(p); 284 } 285 } 286 sigsetmask(omask); 287 } 288 } 289 290 /* 291 * Merge current contents of ttys file 292 * into in-core table of configured tty lines. 293 * Entered as signal handler for SIGHUP. 294 */ 295 #define FOUND 1 296 #define CHANGE 2 297 #define WCHANGE 4 298 299 void 300 merge() 301 { 302 register struct tab *p; 303 register struct ttyent *t; 304 register struct tab *p1; 305 306 for (ALL) 307 p->xflag = 0; 308 setttyent(); 309 while (t = getttyent()) { 310 if ((t->ty_status & TTY_ON) == 0) 311 continue; 312 for (ALL) { 313 if (SCMPN(p->line, t->ty_name)) 314 continue; 315 p->xflag |= FOUND; 316 if (SCMPN(p->comn, t->ty_getty)) { 317 p->xflag |= CHANGE; 318 SCPYN(p->comn, t->ty_getty); 319 } 320 if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 321 p->xflag |= WCHANGE|CHANGE; 322 SCPYN(p->wcmd, t->ty_window); 323 } 324 goto contin1; 325 } 326 327 /* 328 * Make space for a new one 329 */ 330 p1 = (struct tab *)calloc(1, sizeof(*p1)); 331 if (!p1) { 332 syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 333 goto contin1; 334 } 335 /* 336 * Put new terminal at the end of the linked list. 337 */ 338 if (itab) { 339 for (p = itab; p->next ; p = p->next) 340 ; 341 p->next = p1; 342 } else 343 itab = p1; 344 345 p = p1; 346 SCPYN(p->line, t->ty_name); 347 p->xflag |= FOUND|CHANGE; 348 SCPYN(p->comn, t->ty_getty); 349 if (t->ty_window && strcmp(t->ty_window, "") != 0) { 350 p->xflag |= WCHANGE; 351 SCPYN(p->wcmd, t->ty_window); 352 } 353 contin1: 354 ; 355 } 356 endttyent(); 357 p1 = (struct tab *)0; 358 for (ALL) { 359 if ((p->xflag&FOUND) == 0) { 360 term(p); 361 wterm(p); 362 if (p1) 363 p1->next = p->next; 364 else 365 itab = p->next; 366 free(p); 367 p = p1 ? p1 : itab; 368 } else { 369 /* window system should be started first */ 370 if (p->xflag&WCHANGE) { 371 wterm(p); 372 wstart(p); 373 } 374 if (p->xflag&CHANGE) { 375 term(p); 376 dfork(p); 377 } 378 } 379 p1 = p; 380 } 381 } 382 383 term(p) 384 register struct tab *p; 385 { 386 387 if (p->pid != 0) { 388 cleanutmp(p); 389 kill(p->pid, SIGKILL); 390 } 391 p->pid = 0; 392 /* send SIGHUP to get rid of connections */ 393 if (p->wpid > 0) 394 kill(p->wpid, SIGHUP); 395 } 396 397 dfork(p) 398 struct tab *p; 399 { 400 register pid; 401 time_t t; 402 int dowait = 0; 403 404 time(&t); 405 p->gettycnt++; 406 if ((t - p->gettytime) >= 60) { 407 p->gettytime = t; 408 p->gettycnt = 1; 409 } else if (p->gettycnt >= 5) { 410 dowait = 1; 411 p->gettytime = t; 412 p->gettycnt = 1; 413 } 414 pid = fork(); 415 if (pid == 0) { 416 signal(SIGTERM, SIG_DFL); 417 signal(SIGHUP, SIG_IGN); 418 sigsetmask(0); /* since can be called from masked code */ 419 if (dowait) { 420 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 421 closelog(); 422 sleep(30); 423 } 424 if (setsid() < 0) 425 syslog(LOG_ERR, "setsid failed(dfork) %m"); 426 execit(p->comn, p->line); 427 exit(0); 428 } 429 p->pid = pid; 430 } 431 432 cleanutmp(p) 433 register struct tab *p; 434 { 435 if (logout(p->line)) { 436 logwtmp(p->line, "", ""); 437 /* 438 * After a proper login force reset 439 * of error detection code in dfork. 440 */ 441 p->gettytime = 0; 442 p->windtime = 0; 443 } 444 } 445 446 void 447 reset() 448 { 449 longjmp(sjbuf, 1); 450 } 451 452 jmp_buf idlebuf; 453 454 void 455 idlehup() 456 { 457 longjmp(idlebuf, 1); 458 } 459 460 void 461 idle() 462 { 463 register struct tab *p; 464 register pid; 465 466 signal(SIGHUP, idlehup); 467 for (EVER) { 468 if (setjmp(idlebuf)) 469 return; 470 pid = wait((int *) 0); 471 if (pid == -1) { 472 sigpause(0); 473 continue; 474 } 475 for (ALL) { 476 /* if window system dies, mark it for restart */ 477 if (p->wpid == pid) 478 p->wpid = -1; 479 if (p->pid == pid) { 480 cleanutmp(p); 481 p->pid = -1; 482 } 483 } 484 } 485 } 486 487 wterm(p) 488 register struct tab *p; 489 { 490 if (p->wpid != 0) { 491 kill(p->wpid, SIGKILL); 492 } 493 p->wpid = 0; 494 } 495 496 wstart(p) 497 register struct tab *p; 498 { 499 register pid; 500 time_t t; 501 int dowait = 0; 502 503 time(&t); 504 p->windcnt++; 505 if ((t - p->windtime) >= 60) { 506 p->windtime = t; 507 p->windcnt = 1; 508 } else if (p->windcnt >= 5) { 509 dowait = 1; 510 p->windtime = t; 511 p->windcnt = 1; 512 } 513 514 pid = fork(); 515 516 if (pid == 0) { 517 signal(SIGTERM, SIG_DFL); 518 signal(SIGHUP, SIG_IGN); 519 sigsetmask(0); /* since can be called from masked code */ 520 if (dowait) { 521 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 522 closelog(); 523 sleep(30); 524 } 525 if (setsid() < 0) 526 syslog(LOG_ERR, "setsid failed (window) %m"); 527 execit(p->wcmd, p->line); 528 exit(0); 529 } 530 p->wpid = pid; 531 } 532 533 #define NARGS 20 /* must be at least 4 */ 534 #define ARGLEN 512 /* total size for all the argument strings */ 535 536 execit(s, arg) 537 char *s; 538 char *arg; /* last argument on line */ 539 { 540 char *argv[NARGS], args[ARGLEN], *envp[1]; 541 register char *sp = s; 542 register char *ap = args; 543 register char c; 544 register int i; 545 546 /* 547 * First we have to set up the argument vector. 548 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 549 */ 550 for (i = 1; i < NARGS - 2; i++) { 551 argv[i] = ap; 552 for (EVER) { 553 if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 554 *ap = '\0'; 555 goto done; 556 } 557 if (c == ' ') { 558 *ap++ = '\0'; 559 while (*sp == ' ') 560 sp++; 561 if (*sp == '\0') 562 goto done; 563 break; 564 } 565 *ap++ = c; 566 } 567 } 568 done: 569 argv[0] = argv[1]; 570 argv[1] = "-"; 571 argv[i+1] = arg; 572 argv[i+2] = 0; 573 envp[0] = 0; 574 execve(argv[0], &argv[1], envp); 575 /* report failure of exec */ 576 syslog(LOG_ERR, "%s: %m", argv[0]); 577 closelog(); 578 sleep(10); /* prevent failures from eating machine */ 579 } 580