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