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