|
|
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.