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