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