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