|
|
1.1 ! root 1: /* Initialization program for the user level of the OS--this is the ! 2: * first thing that gets run: pid 1. ! 3: * ! 4: * Runs /etc/brc. If it fails spawns a /bin/sh on the console (this is ! 5: * single user mode.) If /etc/brc exits cleanly it starts multi user ! 6: * mode by running /etc/rc, then it spawns gettys on those terminals in ! 7: * /etc/ttys. ! 8: * ! 9: * In multi user mode it respawns gettys as needed, removes tty locks ! 10: * when a getty dies, and wait()s for orphans. ! 11: * ! 12: * Accepts two signals: SIG_HUP and SIG_QUIT. ! 13: * SIG_HUP causes init to kill (SIG_KILL) all processes and go to single ! 14: * user mode. SIG_QUIT causes /etc/ttys to be reread. ! 15: * All other signals are ignored. ! 16: */ ! 17: #define NEWTTYS 1 ! 18: #define NOSWAPPER ! 19: #define NODRIVERS ! 20: #define DEBUG 0 ! 21: ! 22: /* ! 23: * Init ! 24: * ! 25: * Compile -s -n -i on machines other than pdp11. ! 26: */ ! 27: ! 28: #include <sys/dir.h> ! 29: #include <signal.h> ! 30: #include <utmp.h> ! 31: #include <sgtty.h> ! 32: #include <errno.h> ! 33: #include <sys/malloc.h> ! 34: #include <access.h> ! 35: ! 36: /* ! 37: * Miscellaneous constants. ! 38: */ ! 39: #define NULL ((char *)0) ! 40: #define BRCFILE "/etc/brc" ! 41: ! 42: #if DEBUG ! 43: #define dbmsg(arglist) msg arglist ! 44: int debug_fd = -1; ! 45: #else ! 46: #define dbmsg(arglist) ! 47: #endif ! 48: ! 49: /* ! 50: * Structure containing information about each terminal. ! 51: */ ! 52: typedef struct tty { ! 53: struct tty *t_next; /* Pointer to next entry */ ! 54: int t_pid; /* Process id */ ! 55: char t_flag; /* 0 == no getty, 1 == want getty */ ! 56: char t_linetype; /* Line type (local, remote, etc.) */ ! 57: char t_baud[2]; /* Baud descriptor */ ! 58: char t_tty[5+DIRSIZ+1]; /* tty name */ ! 59: } TTY; ! 60: ! 61: /* Console tty for simplified spawn */ ! 62: TTY contty = { ! 63: NULL, 0, 0, 'l', "P", "/dev/console" ! 64: }; ! 65: ! 66: /* Null tty for simplified spawn */ ! 67: TTY nultty = { ! 68: NULL, 0, 0, 'l', "P", "/dev/null" ! 69: }; ! 70: ! 71: /* ! 72: * Default environment list for shell. ! 73: */ ! 74: char *defenv0[] = { /* Default environment for super user */ ! 75: "USER=root", ! 76: "HOME=/etc", ! 77: "PATH=/bin:/usr/bin:/etc:", ! 78: "PS1=# ", ! 79: NULL ! 80: }; ! 81: ! 82: /* ! 83: * Variables. ! 84: */ ! 85: static char _version[]="init version 4.0"; ! 86: struct tty *ttyp; /* Terminal list */ ! 87: int hangflag; /* Go to single user */ ! 88: int quitflag; /* Scan tty file */ ! 89: ! 90: /* ! 91: * Functions. ! 92: */ ! 93: extern int sighang(); ! 94: extern int sigquit(); ! 95: extern int sigalrm(); ! 96: extern struct tty *findtty(); ! 97: ! 98: ! 99: main(argc, argv) register int argc; char *argv[]; ! 100: { ! 101: register TTY *tp; ! 102: register int i, n, multi; ! 103: unsigned status; ! 104: ! 105: dbmsg(("Entering init ", NULL)); ! 106: ! 107: multi = 0; /* do not go to multiuser */ ! 108: /* Make sure that every flag has a usable initial value. */ ! 109: quitflag = 0; /* Do not rescan /etc/ttys. */ ! 110: hangflag = 0; /* Do not shut down. */ ! 111: ! 112: if (getpid() != 1) ! 113: exit(1); ! 114: umask(022); ! 115: dbmsg(("About to fakearg ", NULL)); ! 116: fakearg(0, argv); ! 117: if ((n = creat("/etc/boottime", 0644)) >= 0) ! 118: close(n); ! 119: dbmsg(("CREATED boottime ", NULL)); ! 120: #ifndef NOSWAPPER ! 121: if (argc >= 2) ! 122: loadswp(argv[1]); ! 123: #endif ! 124: #ifndef NODRIVERS ! 125: for (n=2; n<argc; n++) ! 126: loaddrv(argv[n]); ! 127: #endif ! 128: dbmsg(("About to putwtmp ", NULL)); ! 129: putwtmp("~", ""); ! 130: ! 131: /* ! 132: * Ignore all possible signals. We do not want to be able to ! 133: * accidentally kill init. ! 134: */ ! 135: for (i=1; i<=NSIG; i++) ! 136: signal(i, SIG_IGN); ! 137: ! 138: /* ! 139: * We MUST NOT ignore SIGCHLD--we care deeply about our children. ! 140: */ ! 141: ! 142: #if _I386 ! 143: dbmsg(("About to default for SIGCHLD ", NULL)); ! 144: signal(SIGCHLD, SIG_DFL); ! 145: #endif ! 146: ! 147: dbmsg(("About to trap for SIGHUP ", NULL)); ! 148: signal(SIGHUP, sighang); ! 149: ! 150: dbmsg(("About to fork() ", NULL)); ! 151: if (fork() == 0) { /* paranoid sync */ ! 152: sync(); ! 153: exit(0); ! 154: } ! 155: dbmsg(("About to access brc file ", NULL)); ! 156: if (access(BRCFILE, AEXISTS) == 0) { ! 157: dbmsg(("executing /etc/brc", NULL)); ! 158: n = spawn(&contty, "/bin/sh", "sh", BRCFILE, NULL); ! 159: while (wait(&status) != n) ! 160: ; ! 161: if (status == 0) ! 162: multi = 1; ! 163: } ! 164: ! 165: for (;;) { ! 166: while (inittys() == 0) { ! 167: if (!multi) { ! 168: /* Single user - no multi-user ttys active */ ! 169: /* No rescan signals accepted */ ! 170: signal(SIGQUIT, SIG_IGN); ! 171: /* Wait for things to quiet down */ ! 172: /* Necessitated by system shared segment bug */ ! 173: /* But don't wait for hung processes */ ! 174: signal(SIGALRM, sigalrm); ! 175: alarm(2); ! 176: while (wait(NULL) >= 0) ! 177: ; ! 178: alarm(0); ! 179: ! 180: dbmsg(("sync()ing", NULL)); ! 181: sync(); /* Obviates need for user sync. */ ! 182: /* Initiate single user state */ ! 183: dbmsg(("spawn single user shell", NULL)); ! 184: n = spawn(&contty, "/bin/sh", "-sh", NULL); ! 185: /* Wait for shell to exit */ ! 186: if (waitc(n) < 0) { ! 187: hangflag = 0; ! 188: kill9(-1); ! 189: continue; ! 190: } ! 191: } ! 192: /* Start multi-user state */ ! 193: dbmsg(("executing /etc/rc", NULL)); ! 194: n = spawn(&nultty, "/bin/sh", "sh", "/etc/rc", NULL); ! 195: if (waitc(n) < 0) { ! 196: hangflag = 0; ! 197: kill9(-1); ! 198: continue; ! 199: } ! 200: /* Scan the ttys file */ ! 201: scantty(); /* scantty() may reset quitflag */ ! 202: /* Prepare for rescan ttys signal */ ! 203: quitflag = 0; ! 204: signal(SIGQUIT, sigquit); ! 205: } ! 206: /* Wait for orphaned processes */ ! 207: n = wait(&status); ! 208: if (hangflag) { ! 209: /* Return to single user */ ! 210: dbmsg(("going single user", NULL)); ! 211: hangflag = 0; ! 212: kill9(-1); ! 213: for (tp=ttyp; tp!=NULL; tp=tp->t_next) { ! 214: tp->t_pid = 0; ! 215: tp->t_flag = 0; ! 216: } ! 217: if (fork() == 0) { /* paranoid sync */ ! 218: sync(); ! 219: exit(0); ! 220: } ! 221: multi = 0; ! 222: continue; ! 223: } ! 224: if (quitflag) { ! 225: /* Scan for ttys with changes in status */ ! 226: dbmsg(("quit signal, rescan ttys", NULL)); ! 227: quitflag = 0; ! 228: scantty(); ! 229: continue; ! 230: } ! 231: if (n > 0) { ! 232: /* Logout process n. */ ! 233: for (tp=ttyp; tp; tp=tp->t_next) { ! 234: if (n != tp->t_pid) ! 235: continue; ! 236: tp->t_pid = 0; ! 237: dbmsg(("logout process on tty ", tp->t_tty, NULL)); ! 238: putwtmp(&tp->t_tty[5], ""); ! 239: clrutmp(&tp->t_tty[5]); ! 240: chmod(tp->t_tty, 0700); ! 241: chown(tp->t_tty, 0, 0); ! 242: ! 243: /* ! 244: * Unlock the tty; it was locked by ! 245: * process n: originally login. ! 246: * ! 247: * We don't care about the return value; ! 248: * if it was locked by somebody else, ! 249: * locknrm() won't remove the lock. ! 250: */ ! 251: unlockntty(strrchr(tp->t_tty, '/')+1, n); ! 252: /* See if we panicked */ ! 253: if ((status>>8) == 0377) ! 254: tp->t_flag = 0; ! 255: } ! 256: } ! 257: } ! 258: } ! 259: /* ! 260: * Called when we get a hangup. ! 261: */ ! 262: sighang() ! 263: { ! 264: signal(SIGHUP, sighang); ! 265: hangflag = 1; ! 266: } ! 267: ! 268: /* ! 269: * Called when a quit is received. ! 270: */ ! 271: sigquit() ! 272: { ! 273: signal(SIGQUIT, sigquit); ! 274: quitflag = 1; ! 275: } ! 276: ! 277: /* ! 278: * Called when an alarm is received in single user mode. ! 279: */ ! 280: sigalrm() ! 281: { ! 282: } ! 283: ! 284: /* ! 285: * Called when an alarm is received in multi user mode. ! 286: */ ! 287: mulsigalrm() ! 288: { ! 289: kill(1, SIGQUIT); /* Cause a rescan of /etc/ttys. */ ! 290: } ! 291: ! 292: #ifndef NOSWAPPER ! 293: /* ! 294: * Load the swapper. ! 295: */ ! 296: loadswp(np) ! 297: char *np; ! 298: { ! 299: if (np[0] == '\0') ! 300: return; ! 301: if (fork() != 0) ! 302: return; ! 303: execve(np, NULL, NULL); ! 304: panic("cannot load ", np); ! 305: } ! 306: #endif ! 307: ! 308: #ifndef NODRIVERS ! 309: /* ! 310: * Load the given driver. ! 311: */ ! 312: loaddrv(np) ! 313: char *np; ! 314: { ! 315: register int pid; ! 316: int status; ! 317: ! 318: pid = spawn(&nultty, "/etc/load", "load", np, NULL); ! 319: while (wait(&status) != pid) ! 320: ; ! 321: if (status != 0) ! 322: exit(status); ! 323: } ! 324: #endif ! 325: ! 326: /* ! 327: * If there are any terminals which need to be serviced, service them. ! 328: * Return the number of active terminals. ! 329: */ ! 330: inittys() ! 331: { ! 332: register TTY *tp; ! 333: register int n; ! 334: ! 335: n = 0; ! 336: for (tp=ttyp; tp!=NULL; tp=tp->t_next) { ! 337: if (tp->t_pid == 0 && tp->t_flag != 0) ! 338: login(tp); ! 339: n += tp->t_flag; ! 340: } ! 341: return (n); ! 342: } ! 343: ! 344: /* ! 345: * Wait for the given process to complete. ! 346: */ ! 347: waitc(p1) ! 348: register int p1; ! 349: { ! 350: register int p2; ! 351: ! 352: while ((p2=wait(NULL))>=0 && p2!=p1) ! 353: ; ! 354: return (p2); ! 355: } ! 356: ! 357: /* ! 358: * Scan the tty file. ! 359: */ ! 360: scantty() ! 361: { ! 362: register TTY *tp; /* Used to pick entries from ttyp. */ ! 363: register int fd; /* File descriptor for /etc/ttys. */ ! 364: TTY tty; /* Used to hold entries from /etc/ttys. */ ! 365: ! 366: extern char *sbrk(); ! 367: ! 368: dbmsg(("Rescan", NULL)); ! 369: ! 370: unlockntty("console", 0); /* Wipe out locks on the console. */ ! 371: ! 372: if ((fd=open("/etc/ttys", 0)) < 0) ! 373: return; ! 374: while (readtty(&tty, fd) != 0) { ! 375: /* If there is no record of this tty, create one. */ ! 376: if ((tp=findtty(&tty)) == NULL) { ! 377: if ((tp = sbrk(sizeof(*tp))) == BADSBRK) ! 378: panic("too many ttys"); ! 379: *tp = tty; ! 380: tp->t_next = ttyp; ! 381: ttyp = tp; ! 382: continue; ! 383: } ! 384: ! 385: /* ! 386: * If /etc/ttys has changed for this tty, ! 387: * adjust the in-memory version to the desired state. ! 388: */ ! 389: if (tp->t_flag != tty.t_flag ! 390: || tp->t_baud[0] != tty.t_baud[0] ! 391: || tp->t_linetype != tty.t_linetype) { ! 392: /* ! 393: * If this tty is locked, and we want to start a ! 394: * getty, do not do it until the lock goes away. ! 395: * ! 396: * Ignore locks on the console. ! 397: */ ! 398: if ((0 != strcmp(tty.t_tty, "/dev/console")) && ! 399: lockttyexist(strrchr(tty.t_tty, '/')+1) && ! 400: 0 != tty.t_flag) { ! 401: dbmsg(("Setting an alarm", NULL)); ! 402: /* Check again in a few seconds. */ ! 403: signal(SIGALRM, mulsigalrm); ! 404: alarm(10); ! 405: } else { ! 406: dbmsg(("Starting getty", NULL)); ! 407: tp->t_flag = tty.t_flag; ! 408: tp->t_baud[0] = tty.t_baud[0]; ! 409: tp->t_linetype = tty.t_linetype; ! 410: /* Kill off any process lingering on this tty. */ ! 411: if (tp->t_pid != 0) ! 412: kill9(tp->t_pid); ! 413: } ! 414: } ! 415: } ! 416: close(fd); ! 417: } ! 418: ! 419: /* ! 420: * Read a line from the terminal file and save the appropriate fields in ! 421: * the terminal structure. ! 422: */ ! 423: readtty(tp, fd) ! 424: register TTY *tp; ! 425: { ! 426: register char *lp; ! 427: char c[1]; ! 428: char line[3+DIRSIZ+1]; ! 429: ! 430: lp = line; ! 431: for (;;) { ! 432: if (read(fd, c, sizeof(c)) != sizeof(c)) ! 433: return (0); ! 434: if (c[0] == '\n') ! 435: break; ! 436: if (lp < &line[3+DIRSIZ]) ! 437: *lp++ = c[0]; ! 438: } ! 439: *lp++ = '\0'; ! 440: if (lp < &line[5]) ! 441: return (0); ! 442: lp = line; ! 443: tp->t_flag = (*lp++) != '0'; ! 444: #if NEWTTYS ! 445: tp->t_linetype = *lp++; ! 446: #else ! 447: tp->t_linetype = 'l'; ! 448: #endif ! 449: tp->t_pid = 0; ! 450: tp->t_baud[0] = *lp++; ! 451: tp->t_baud[1] = '\0'; ! 452: strcpy(tp->t_tty, "/dev/"); ! 453: strncpy(&tp->t_tty[5], lp, DIRSIZ); ! 454: tp->t_tty[5+DIRSIZ] = '\0'; ! 455: dbmsg(("readtty: ", tp->t_tty, NULL)); ! 456: return (1); ! 457: } ! 458: ! 459: /* ! 460: * Given a terminal structure containing the name of a terminal, ! 461: * find the entry in the terminal list. ! 462: */ ! 463: TTY * ! 464: findtty(tp1) ! 465: register TTY *tp1; ! 466: { ! 467: register TTY *tp2; ! 468: ! 469: for (tp2=ttyp; tp2!=NULL; tp2=tp2->t_next) ! 470: if (strcmp(tp1->t_tty, tp2->t_tty) == 0) ! 471: return (tp2); ! 472: return (NULL); ! 473: } ! 474: ! 475: /* ! 476: * Given a terminal structure, spawn off a login (getty). ! 477: */ ! 478: login(tp) ! 479: register TTY *tp; ! 480: { ! 481: register int pid; ! 482: ! 483: pid = spawn(tp, ! 484: "/etc/getty", ! 485: (tp->t_linetype == 'l') ? "-" : "-r", ! 486: tp->t_baud, ! 487: NULL); ! 488: if (pid < 0) { ! 489: tp->t_flag = 0; ! 490: dbmsg(("spawn failed tty ", tp->t_tty, NULL)); ! 491: } else ! 492: tp->t_pid = pid; ! 493: } ! 494: ! 495: /* ! 496: * Spawn off a command. ! 497: */ ! 498: spawn(tp, np, ap) ! 499: TTY *tp; ! 500: char *np, *ap; ! 501: { ! 502: register int pid; ! 503: register int fd; ! 504: int i; ! 505: ! 506: if ((pid=fork()) != 0) ! 507: return (pid); ! 508: #if DEBUG ! 509: close(debug_fd); ! 510: #endif ! 511: setpgrp(); ! 512: fakearg(1, tp->t_tty); ! 513: while ((fd=open(tp->t_tty, 2)) < 0 && errno==EDBUSY) ! 514: sleep(1); ! 515: if (fd < 0) ! 516: panic("cannot open ", tp->t_tty, NULL); ! 517: ioctl(fd, TIOCSETG); ! 518: #if NEWTTYS ! 519: if (tp->t_linetype == 'r') /* remote line? */ ! 520: ioctl(fd, TIOCHPCL); /* "hangup" on last close */ ! 521: #endif ! 522: dup2(0, 1); ! 523: dup2(0, 2); ! 524: ! 525: /* Restore all signals for any child process. */ ! 526: for (i=1; i<=NSIG; i++) ! 527: signal(i, SIG_DFL); ! 528: ! 529: execve(np, &ap, defenv0); ! 530: panic("cannot execute ", np, NULL); ! 531: return (pid); ! 532: } ! 533: ! 534: /* ! 535: * Write an entry onto the wtmp file. ! 536: */ ! 537: putwtmp(lp, np) char *lp, *np; ! 538: { ! 539: register int fd; ! 540: struct utmp utmp; ! 541: extern time_t time(); ! 542: ! 543: if ((fd=open("/usr/adm/wtmp", 1)) < 0) ! 544: return; ! 545: strncpy(utmp.ut_line, lp, 8); ! 546: strncpy(utmp.ut_name, np, DIRSIZ); ! 547: utmp.ut_time = time(NULL); ! 548: lseek(fd, 0L, 2); ! 549: write(fd, (char *)&utmp, sizeof(utmp)); ! 550: close(fd); ! 551: } ! 552: ! 553: /* ! 554: * Clear out a utmp entry. ! 555: */ ! 556: clrutmp(tty) ! 557: char *tty; ! 558: { ! 559: register int fd; ! 560: struct utmp utmp; ! 561: static struct utmp ctmp; ! 562: ! 563: if ((fd=open("/etc/utmp", 2)) < 0) ! 564: return; ! 565: while (read(fd, &utmp, sizeof(utmp)) == sizeof(utmp)) ! 566: { if (strncmp(utmp.ut_line, tty, 8)) /* no match? */ ! 567: continue; /* yes, go for next record */ ! 568: lseek(fd, (long)-sizeof(utmp), 1); ! 569: write(fd, &ctmp, sizeof(ctmp)); /* clear utmp record */ ! 570: break; ! 571: } ! 572: close(fd); ! 573: } ! 574: ! 575: /* ! 576: * Print out a list of error messages and exit. ! 577: */ ! 578: panic(cp) ! 579: char *cp; ! 580: { ! 581: register char **cpp; ! 582: ! 583: close(0); ! 584: open("/dev/console", 2); ! 585: write(0, "/etc/init: ", 11); ! 586: for (cpp=&cp; *cpp!=NULL; cpp++) ! 587: write(0, *cpp, strlen(*cpp)); ! 588: write(0, "\n", 1); ! 589: exit(0377); ! 590: } ! 591: ! 592: /* ! 593: * Make the arg listing of ps come out right. ! 594: * f == 0, first entry, determine buffer limits. ! 595: * In this case, name the forks of init -tty until the ! 596: * tty opens. ! 597: * f != 0, later entry, fill buffer with lies. ! 598: */ ! 599: fakearg(f, argv) ! 600: int f; ! 601: char **argv; ! 602: { ! 603: static char *fbuf; ! 604: static int nbuf; ! 605: register int n; ! 606: register char *p; ! 607: ! 608: if (f == 0) { ! 609: fbuf = argv[0]; ! 610: nbuf = 0; ! 611: while (argv[1] != NULL) ! 612: argv += 1; ! 613: nbuf = argv[0] - fbuf + strlen(argv[0]) - 1; ! 614: } else { ! 615: if (fbuf == NULL || nbuf == 0) ! 616: return; ! 617: p = (char *)argv; ! 618: p += 5; /* tty part of /dev/tty* */ ! 619: n = 1; ! 620: *fbuf++ = '-'; ! 621: do ! 622: *fbuf++ = *p; ! 623: while (++n < nbuf && *p++ != 0); ! 624: *fbuf = 01; /* non-ascii terminator */ ! 625: } ! 626: } ! 627: ! 628: /* ! 629: * Send SIGKILL to process, delaying and sending twice to ensure death. ! 630: */ ! 631: kill9(pid) register int pid; ! 632: { ! 633: kill(pid, SIGKILL); ! 634: sleep(1); ! 635: kill(pid, SIGKILL); ! 636: } ! 637: ! 638: #if DEBUG ! 639: #define SCREEN_ADDR 0xb0000L /* Physical address of screen. ! 640: * Use 0xb8000 for color screen. ! 641: */ ! 642: #define SCREEN_SIZE (80*25*2) /* Size of screen in bytes. */ ! 643: ! 644: /* ! 645: * Write a debug message to the console. ! 646: * The args should be a NULL-terminated list of strings. ! 647: */ ! 648: msg(cp) char *cp; ! 649: { ! 650: register char **cpp; ! 651: #if 0 ! 652: /* Old init couldn't write to console because it messed up process groups. */ ! 653: int fd; ! 654: static long mp = SCREEN_ADDR; ! 655: int i; ! 656: ! 657: if (mp >= SCREEN_ADDR + SCREEN_SIZE) ! 658: mp = SCREEN_ADDR; ! 659: fd = open("/dev/mem", 2); ! 660: lseek(fd, mp, 0); ! 661: write(fd, ":", 1); ! 662: lseek(fd, 1L, 1); ! 663: mp += 2; ! 664: for (cpp=&cp; *cpp!=NULL; cpp++) { ! 665: for (i = 0; i < strlen(*cpp); i++) { ! 666: write(fd, (*cpp)+i, 1); ! 667: lseek(fd, 1L, 1); ! 668: mp += 2; ! 669: } ! 670: write(fd, " ", 1); ! 671: lseek(fd, 1L, 1); ! 672: mp += 2; ! 673: } ! 674: close(fd); ! 675: #else ! 676: if (debug_fd == -1) ! 677: debug_fd = open("/dev/console", 2); ! 678: write(debug_fd, ":", 1); ! 679: for (cpp=&cp; *cpp!=NULL; cpp++) { ! 680: write(debug_fd, *cpp, strlen(cp)); ! 681: write(debug_fd, " ", 1); ! 682: } ! 683: #endif ! 684: } ! 685: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.