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