1: /* 2: * init.c 3: */ 4: #include "whoami.h" 5: #include <signal.h> 6: #include <sys/types.h> 7: #include <utmp.h> 8: #include <setjmp.h> 9: #ifdef UCB_AUTOBOOT 10: #include <sys/reboot.h> 11: #endif 12: #include <errno.h> 13: #include <sys/autoconfig.h> 14: 15: #define VHANGUP /* undefine if you don't have vhangup */ 16: #define CONFIGOPTS "-vc" 17: 18: #define LINSIZ sizeof(wtmp.ut_line) 19: #define TABSIZ 100 20: #define ALL p = &itab[0]; p < &itab[TABSIZ]; p++ 21: #define EVER ;; 22: #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 23: #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 24: 25: char shell[] = "/bin/sh"; 26: char getty[] = "/etc/getty"; 27: char minus[] = "-"; 28: char plus[] = "+"; /* this tells getty we are in sp. sess. */ 29: char runc[] = "/etc/rc"; 30: char ifile[] = "/etc/ttys"; 31: char utmp[] = "/etc/utmp"; 32: char wtmpf[] = "/usr/adm/wtmp"; 33: char ctty[] = "/dev/console"; 34: char dev[] = "/dev/"; 35: char config[]= "/etc/autoconfig"; 36: 37: struct utmp wtmp; 38: struct 39: { 40: char line[LINSIZ]; 41: char comn; 42: char flag; 43: } line; 44: struct tab 45: { 46: char line[LINSIZ]; 47: char comn; 48: char xflag; 49: int pid; 50: } itab[TABSIZ]; 51: 52: extern errno; 53: 54: int fi; 55: int mergflag; 56: int multiuser; 57: /* 58: * Modes: bits in first char of /etc/ttys line 59: */ 60: #define NORMAL 1 /* anyone can login */ 61: #define SP_SESS 2 /* only root can login */ 62: int mode = NORMAL; 63: 64: char tty[20]; 65: jmp_buf sjbuf, shutpass; 66: time_t time0; 67: 68: time_t time(); 69: int reset(); 70: int idle(), sp_ss(), setmerge(); 71: char *strcpy(), *strcat(); 72: long lseek(); 73: 74: #ifdef UCB_AUTOBOOT 75: main(ac, av) 76: char **av; 77: #else 78: main () 79: #endif 80: { 81: int howto, oldhowto; 82: 83: time0 = time((time_t *) 0); 84: #ifdef UCB_AUTOBOOT 85: signal(SIGQUIT, idle); 86: 87: if (ac > 1) { 88: howto = * ((int *) av[1]); 89: * ((int *) av[1]) = 0; /* don't confuse ps with binary args */ 90: } else 91: howto = RB_SINGLE; 92: if (autoconfig() == 0) 93: howto = RB_SINGLE; 94: #else 95: autoconfig(); 96: #endif 97: setjmp(sjbuf); 98: signal(SIGTERM, reset); 99: signal(SIGINT, sp_ss); 100: signal(SIGHUP, setmerge); 101: for(EVER) { 102: shutdown(); 103: #ifdef UCB_AUTOBOOT 104: oldhowto = howto; 105: howto = RB_SINGLE; 106: if (oldhowto & RB_SINGLE) 107: single(); 108: if (runcom(oldhowto) == 0) 109: mode = SP_SESS; 110: #else 111: single(); 112: runcom(); 113: #endif 114: merge(); 115: multiple(); 116: } 117: } 118: 119: int shutreset(); 120: 121: shutdown() 122: { 123: register i, f; 124: register struct tab *p; 125: 126: multiuser = 0; 127: for(ALL) { 128: term(p); 129: p->line[0] = 0; 130: } 131: close(creat(utmp, 0644)); 132: signal(SIGALRM, shutreset); 133: if (setjmp(shutpass) == 0) { 134: alarm(30); 135: for(i=0; i<5; i++) 136: kill(-1, SIGKILL); 137: while(wait((int *)0) != -1) 138: ; 139: alarm(0); 140: } 141: acct(0); 142: signal(SIGALRM, SIG_DFL); 143: for(i=0; i<10; i++) 144: close(i); 145: f = open(wtmpf, 1); 146: if (f >= 0) { 147: lseek(f, 0L, 2); 148: SCPYN(wtmp.ut_line, "~"); 149: SCPYN(wtmp.ut_name, "shutdown"); 150: time(&wtmp.ut_time); 151: write(f, (char *)&wtmp, sizeof(wtmp)); 152: close(f); 153: } 154: } 155: 156: shutreset() 157: { 158: cmesg("WARNING: Something is hung (won't die); ps axl advised\n", 0, 0); 159: longjmp(shutpass, 1); 160: } 161: 162: single() 163: { 164: register pid; 165: register xpid; 166: extern errno; 167: 168: multiuser = 0; 169: do { 170: pid = fork(); 171: if(pid == 0) { 172: /* 173: alarm(300); 174: */ 175: signal(SIGTERM, SIG_DFL); 176: signal(SIGHUP, SIG_DFL); 177: signal(SIGALRM, SIG_DFL); 178: open(ctty, 2); 179: dup(0); 180: dup(0); 181: execl(shell, minus, (char *)0); 182: cmesg("Init: can't exec ", shell, "\r\n"); 183: exit(0); 184: } 185: while((xpid = wait((int *)0)) != pid) 186: if (xpid == -1 && errno == ECHILD) 187: break; 188: } while (xpid == -1); 189: } 190: 191: #ifdef UCB_AUTOBOOT 192: runcom(howto) 193: int howto; 194: #else 195: runcom() 196: #endif 197: { 198: register pid, f; 199: int status; 200: char *arg1, *arg2; 201: 202: pid = fork(); 203: if(pid == 0) { 204: open("/", 0); 205: dup(0); 206: dup(0); 207: #ifdef UCB_AUTOBOOT 208: if ((howto & RB_SINGLE) || (howto & RB_NOFSCK)) 209: arg1 = "fastboot"; 210: else 211: arg1 = "autoboot"; 212: if (howto & RB_POWRFAIL) 213: arg2 = "powerfail"; 214: else 215: arg2 = (char *)0; 216: execl(shell, shell, runc, arg1, arg2, (char *)0); 217: exit(1); 218: #else 219: execl(shell, shell, runc, (char *)0); 220: exit(1); 221: #endif 222: } 223: while(wait(&status) != pid) 224: ; 225: #ifdef UCB_AUTOBOOT 226: if(status) 227: return(0); 228: #endif 229: f = open(wtmpf, 1); 230: if (f >= 0) { 231: lseek(f, 0L, 2); 232: SCPYN(wtmp.ut_line, "~"); 233: SCPYN(wtmp.ut_name, "reboot"); 234: if (time0) { 235: wtmp.ut_time = time0; 236: time0 = 0; 237: } else 238: time(&wtmp.ut_time); 239: write(f, (char *)&wtmp, sizeof(wtmp)); 240: close(f); 241: } 242: return(1); 243: } 244: 245: setmerge() 246: { 247: signal(SIGHUP, SIG_IGN); 248: mergflag = 1; 249: } 250: 251: multiple() 252: { 253: register struct tab *p; 254: register pid; 255: 256: loop: 257: multiuser = 1; 258: mergflag = 0; 259: signal(SIGHUP, setmerge); 260: for(EVER) { 261: pid = wait((int *)0); 262: if(mergflag) { 263: merge(); 264: goto loop; 265: } 266: if(pid == -1) { 267: if (errno == ECHILD) { 268: cmesg("Init: ", "no children left", "\r\n"); 269: return; 270: } 271: goto loop; 272: } 273: for(ALL) 274: if(p->pid == pid || p->pid == -1) { 275: #ifdef UCB_SUBMIT 276: if (p->pid != -1) 277: killbkg(p->pid, SIGKILL); 278: #endif 279: rmut(p); 280: dfork(p); 281: } 282: } 283: } 284: 285: term(p) 286: register struct tab *p; 287: { 288: 289: if(p->pid != 0 && p->pid != -1) { 290: rmut(p); 291: kill(p->pid, SIGKILL); 292: #ifdef UCB_SUBMIT 293: killbkg(p->pid, SIGKILL); 294: #endif 295: } 296: p->pid = 0; 297: } 298: 299: rline() 300: { 301: register c, i; 302: 303: loop: 304: c = get(); 305: if(c < 0) 306: return(0); 307: if(c == 0) 308: goto loop; 309: line.flag = c; 310: c = get(); 311: if(c <= 0) 312: goto loop; 313: line.comn = c; 314: SCPYN(line.line, ""); 315: for (i=0; i<LINSIZ; i++) { 316: c = get(); 317: /* 318: * If a blank, newline, or end of file, or tab, 319: * cease accumulating line name 320: */ 321: if(c <= 0 || c == ' ' || c == '\t') 322: break; 323: line.line[i] = c; 324: } 325: while(c > 0) 326: c = get(); 327: if(line.line[0] == 0) 328: goto loop; 329: if(line.flag == '0') 330: goto loop; 331: strcpy(tty, dev); 332: strncat(tty, line.line, LINSIZ); 333: if(access(tty, 06) < 0) 334: goto loop; 335: return(1); 336: } 337: 338: get() 339: { 340: char b; 341: 342: if(read(fi, &b, 1) != 1) 343: return(-1); 344: if(b == '\n') 345: return(0); 346: return(b); 347: } 348: 349: #define FOUND 1 350: #define CHANGE 2 351: 352: merge() 353: { 354: register struct tab *p; 355: 356: fi = open(ifile, 0); 357: if(fi < 0) 358: return; 359: for(ALL) 360: p->xflag = 0; 361: while(rline()) { 362: if ((line.flag < '1') || (line.flag > '9')) 363: continue; 364: if (((line.flag-'0') & mode) == 0) 365: continue; 366: for(ALL) { 367: if (SCMPN(p->line, line.line)) 368: continue; 369: p->xflag |= FOUND; 370: if(line.comn != p->comn) { 371: p->xflag |= CHANGE; 372: p->comn = line.comn; 373: } 374: goto contin1; 375: } 376: for(ALL) { 377: if(p->line[0] != 0) 378: continue; 379: SCPYN(p->line, line.line); 380: p->xflag |= FOUND|CHANGE; 381: p->comn = line.comn; 382: goto contin1; 383: } 384: contin1: 385: ; 386: } 387: close(fi); 388: for(ALL) { 389: if((p->xflag&FOUND) == 0) { 390: term(p); 391: p->line[0] = 0; 392: } 393: if((p->xflag&CHANGE) != 0) { 394: term(p); 395: dfork(p); 396: } 397: #ifdef UCB_AUTOBOOT 398: /* 399: * If we are resuming after an idle (possibly a failed reboot) 400: * we need to restart the lines that shut down. 401: */ 402: if (p->pid == -1) 403: dfork(p); 404: #endif 405: } 406: } 407: 408: dfork(p) 409: struct tab *p; 410: { 411: register pid; 412: 413: pid = fork(); 414: if(pid == 0) { 415: signal(SIGTERM, SIG_DFL); 416: signal(SIGHUP, SIG_IGN); 417: strcpy(tty, dev); 418: strncat(tty, p->line, LINSIZ); 419: chown(tty, 0, 0); 420: chmod(tty, 0622); 421: if (open(tty, 2) < 0) { 422: int repcnt = 0; 423: do { 424: if (repcnt % 10 == 0) 425: cmesg("init: ",tty,": cannot open\n\r"); 426: repcnt++; 427: sleep(60); 428: } while (open(tty, 2) < 0); 429: } 430: #ifdef VHANGUP 431: vhangup(); 432: #endif 433: signal(SIGHUP, SIG_DFL); 434: open(tty, 2); 435: close(0); 436: dup(1); 437: dup(0); 438: tty[0] = p->comn; 439: tty[1] = 0; 440: if(mode == SP_SESS) 441: execl(getty, plus, tty, (char *)0); 442: else 443: execl(getty, minus, tty, (char *)0); 444: exit(0); 445: } 446: p->pid = pid; 447: } 448: 449: rmut(p) 450: register struct tab *p; 451: { 452: register f; 453: int found = 0; 454: 455: f = open(utmp, 2); 456: if(f >= 0) { 457: while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 458: if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0) 459: continue; 460: lseek(f, -(long)sizeof(wtmp), 1); 461: SCPYN(wtmp.ut_name, ""); 462: time(&wtmp.ut_time); 463: write(f, (char *)&wtmp, sizeof(wtmp)); 464: found++; 465: } 466: close(f); 467: } 468: if (found) { 469: f = open(wtmpf, 1); 470: if (f >= 0) { 471: SCPYN(wtmp.ut_line, p->line); 472: SCPYN(wtmp.ut_name, ""); 473: time(&wtmp.ut_time); 474: lseek(f, (long)0, 2); 475: write(f, (char *)&wtmp, sizeof(wtmp)); 476: close(f); 477: } 478: } 479: } 480: 481: reset() 482: { 483: longjmp(sjbuf, 1); 484: } 485: 486: /* 487: * Toggle special-session mode. 488: * Do a shutdown() so that getty's are reissued in the new mode. 489: */ 490: sp_ss() 491: { 492: signal(SIGINT, SIG_IGN); 493: mergflag++; 494: shutdown(); 495: if (mode == NORMAL) 496: mode = SP_SESS; 497: else { 498: /* 499: * Returning to normal operation. 500: * Run the rc file; either it hasn't been finished 501: * since we failed a filesystem check, or we shut down. 502: */ 503: #ifdef UCB_AUTOBOOT 504: (void) runcom(RB_NOFSCK); 505: #else 506: (void) runcom(); 507: #endif 508: mode = NORMAL; 509: } 510: signal(SIGINT, sp_ss); 511: } 512: 513: #ifdef UCB_AUTOBOOT 514: idle() 515: { 516: register struct tab *p; 517: register pid; 518: 519: signal(SIGQUIT,idle); 520: for (;;) { 521: pid = wait((int *) 0); 522: if (mergflag) { 523: if (!multiuser) 524: reset(); 525: else 526: return; 527: } 528: if (pid == -1) 529: pause(); 530: else { 531: for (ALL) 532: if (p->pid == pid) { 533: rmut(p); 534: p->pid = -1; 535: } 536: } 537: } 538: } 539: #endif 540: 541: cmesg(s1, s2, s3) 542: char *s1, *s2, *s3; 543: { 544: register int pid; 545: 546: pid = fork(); 547: if (pid == 0) { 548: int fd = open(ctty, 2); 549: write(fd, s1, strlen(s1)); 550: if (s2) 551: write(fd, s2, strlen(s2)); 552: if (s3) 553: write(fd, s3, strlen(s3)); 554: close(fd); 555: exit(0); 556: } 557: while (wait((int *)0) != pid) 558: ; 559: } 560: 561: autoconfig() 562: { 563: int pid, status; 564: 565: cmesg("\r\nCONFIGURE SYSTEM:\n", 0, 0); 566: if ((pid = fork()) == 0) { 567: open(ctty, 2); 568: dup(0); 569: dup(0); 570: execl(config, "autoconfig", CONFIGOPTS, 0); 571: printf("Couldn't exec %s\n", config); 572: exit(AC_SETUP); 573: } 574: while (wait(&status) != pid) 575: ; 576: if ((status & 0377) == 0) 577: status >>= 8; 578: else 579: status = AC_SINGLE; 580: switch (status) { 581: case AC_SETUP: 582: cmesg("Configuration setup error\n", 0, 0); 583: return 0; 584: case AC_SINGLE: 585: cmesg("SERIOUS CONFIGURATION ERROR\n", 0, 0); 586: return 0; 587: case AC_OK: 588: return 1; 589: default: 590: cmesg("Unrecognized return from configure\n", 0, 0); 591: return 0; 592: } 593: }