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