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