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