Annotation of src/sbin/init/init.c, Revision 1.6
1.1 cgd 1: /*
2: * Copyright (c) 1986, 1987, 1992 Daniel D. Lanciani.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by
16: * Daniel D. Lanciani.
17: * 4. The name of the author may not
18: * be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY Daniel D. Lanciani ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL Daniel D. Lanciani BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
1.3 cgd 33:
1.6 ! cgd 34: /* $Header: /b/source/CVS/src/sbin/init/init.c,v 1.5 1993/04/06 19:33:33 cgd Exp $ */
1.1 cgd 35:
36:
37: #include <sys/types.h>
38: #include <sys/errno.h>
39: #include <sys/signal.h>
40: #include <sys/wait.h>
41: #include <setjmp.h>
42: #include <ttyent.h>
43: #include <unistd.h>
44:
1.5 cgd 45: #ifdef SECURE_CONSOLE
46: #include <pwd.h>
47: #endif
48:
1.1 cgd 49: #define NTTY 32 /* max ttys */
50: #define NARG 16 /* max args to login/getty */
51:
52: /* internal flags */
53: #define TTY_SEEN 0x8000
54: #define TTY_DIFF 0x4000
55: #define TTY_LOGIN 0x2000
56:
57: /* non-standard tty_logout: rerun login/getty with -o switch to clean line */
58: #ifndef TTY_LOGOUT
59: #define TTY_LOGOUT 0x1000
60: #endif
61:
62: /* non-standard tty_open: open device for login/getty */
63: #ifndef TTY_OPEN
64: #define TTY_OPEN 0x0800
65: #endif
66:
67: #define isspace(c) ((c) == ' ' || (c) == '\t')
68:
69: struct ttytab {
70: char *tt_name;
71: char *tt_getty;
72: char *tt_type;
73: int tt_status;
74: int tt_pid;
75: } ttytab[NTTY], *ttytabend = ttytab;
76: int drain, sflag;
77: char arg[128], nam[64], term[64], *env[] = { term, 0 };
78: jmp_buf single, reread;
79: char *Reboot = "autoboot";
80:
81: char *newstring(), *malloc();
82: extern int errno;
83:
84: /* signal state of child process */
85: #define SIGNALSFORCHILD \
86: signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); \
87: signal(SIGTERM, SIG_DFL); signal(SIGALRM, SIG_DFL); \
88: signal(SIGTSTP, SIG_DFL); signal(SIGCHLD, SIG_DFL); \
1.2 cgd 89: signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); \
90: sigsetmask( 0); /* 04 Sep 92*/
1.1 cgd 91:
92: /* SIGHUP: reread /etc/ttys */
93: void
94: shup(sig)
95: {
96: longjmp(reread, 1);
97: }
98:
99: /* SIGALRM: abort wait and go single user */
100: void
101: salrm(sig)
102: {
103: signal(SIGALRM, SIG_DFL);
104: warn("process hung");
105: longjmp(single, 1);
106: }
107:
108: /* SIGTERM: go single user */
109: void
110: sterm(sig)
111: {
112: register struct ttytab *tt;
113:
114: if (!Reboot) {
115: for(tt = ttytab; tt < ttytabend; tt++) {
116: free(tt->tt_name);
117: free(tt->tt_getty);
118: free(tt->tt_type);
119: }
120: ttytabend = ttytab;
1.2 cgd 121: /* give processes time to exit cleanly */ /* 15 Aug 92*/
122: kill(-1, SIGTERM);
123: sleep(10);
124: /* Now murder them */
1.1 cgd 125: kill(-1, SIGKILL);
126: kill(-1, SIGCONT);
127: signal(SIGALRM, salrm);
128: alarm(30);
129: while(wait((int *)0) > 0);
130: alarm(0);
131: signal(SIGALRM, SIG_DFL);
132: longjmp(single, 1);
133: }
134: }
135:
136: /* SIGTSTP: drain system */
137: void
138: ststp(sig)
139: {
140: drain = 1;
141: }
142:
143: /* init [-s] [-f] */
144:
145: main(argc, argv)
146: char **argv;
147: {
148: register int pid;
149: register struct ttytab *tt;
150: struct ttyent *ty;
151: int status;
152: long mask = sigblock(sigmask(SIGHUP) | sigmask(SIGTERM));
153:
154: /* did some idiot try to run us? */
155: if(getpid() != 1) {
156: writes(2,"init: sorry, system daemon, runnable only by system\n");
157: exit(0xff);
158: }
159:
160: /* allocate a session for init */
161: (void) setsid();
162:
163: /* protect against signals, listen for outside requests */
164: signal(SIGHUP, shup);
165: signal(SIGTSTP, ststp);
166:
167: signal (SIGTTIN, SIG_IGN);
168: signal (SIGTTOU, SIG_IGN);
169: signal (SIGCHLD, SIG_IGN);
170: signal (SIGINT, SIG_IGN);
171:
172: /* handle arguments, if any */
173: if(argc > 1)
174: if(!strcmp(argv[1], "-s"))
175: sflag++;
176: else if(!strcmp(argv[1], "-f"))
177: Reboot = 0;
178: top:
179: /* Single user mode? */
180: if(sflag) {
181: sflag = 0;
182: status = 1;
183: } else {
184: /* otherwise, execute /etc/rc */
185: if (access("/etc/rc", F_OK) == 0) {
186:
187: signal(SIGTERM, SIG_IGN); /* XXX */
188: if((pid = fork()) < 0)
189: fatal("fork");
190: else if(!pid) {
191: /* signals, to default state */
192: SIGNALSFORCHILD;
193:
194: /* clean off console */
195: revoke("/dev/console");
196:
197: /* create a shell */
198: login_tty(open("/dev/console", 2));
199: execl("/bin/sh", "sh", "/etc/rc", Reboot, (char *)0);
200: _exit(127);
201: }
1.2 cgd 202: Reboot = 0; /* 31 Jul 92*/
1.1 cgd 203: while(wait(&status) != pid);
204:
205: /* if we are about to be rebooted, then wait for it */
206: if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)
207: pause();
208: } else { status = 1; sflag = 1; goto top; }
209: }
210: signal(SIGTERM, sterm);
211: Reboot = 0;
212:
213: /* do single user shell on console */
214: if (setjmp(single) || status) {
1.5 cgd 215: #ifdef SECURE_CONSOLE
216: struct ttyent *ttyp;
217: struct passwd *passp;
218: char *pass;
219: static const char banner[] =
220: "Enter root password, or Control-D to go multi-user\n";
221: #endif
222:
1.1 cgd 223: if((pid = fork()) < 0)
224: fatal("fork");
225: else if(!pid) {
226: /* signals, to default state */
227: SIGNALSFORCHILD;
228:
229: /* clean off console */
230: revoke("/dev/console");
231:
232: /* do open and configuration of console */
233: login_tty(open("/dev/console", 2));
1.5 cgd 234: #ifdef SECURE_CONSOLE
235: /* if the console isn't secure, check the root PW */
236: ttyp = getttynam("console");
237: if (!ttyp) {
238: /* don't have an entry for "console", probably
239: * have one for /dev/vga
240: */
241: ttyp = getttynam("vga");
242: }
243: passp = getpwnam("root");
244: if (ttyp && ((ttyp->ty_status & TTY_SECURE) == 0) &&
245: passp) {
246: write(2, banner, sizeof(banner) - 1);
247: do {
248: pass = getpass("Password:");
249: if ((pass == 0) || (*pass == '\0'))
250: _exit(0); /* got control-d */
251: pass = crypt(pass, passp->pw_passwd);
252: } while (strcmp(pass, passp->pw_passwd) != 0);
253: }
254: #endif
1.1 cgd 255: execl("/bin/sh", "-", (char *)0);
256: _exit(127);
257: }
1.2 cgd 258: while(wait(&status) != pid);
259: while(drain) /* 31 Jul 92*/
260: pause();
1.1 cgd 261: goto top;
262: }
263:
264: /* multiuser mode, traipse through table */
265: setttyent();
266: for(tt = ttytab; (ty = getttyent()) && tt < &ttytab[NTTY]; tt++) {
267: tt->tt_name = newstring(ty->ty_name);
268: tt->tt_getty = newstring(ty->ty_getty);
269: tt->tt_type = newstring(ty->ty_type);
270: tt->tt_status = ty->ty_status;
271: }
272: ttytabend = tt;
273: endttyent();
274: for(tt = ttytab; tt < ttytabend; getty(tt++));
275:
276: /* if we receive a request to reread the table, come here */
277: if(setjmp(reread)) {
278:
279: /* first pass. find and clean the entries that have changed */
280: setttyent();
281: while(ty = getttyent()) {
282: for(tt = ttytab; tt < ttytabend; tt++)
283: if(!strcmp(tt->tt_name, ty->ty_name)) {
284: /* if a process present, mark */
285: if((tt->tt_status & ~TTY_LOGIN) !=ty->ty_status)
286: tt->tt_status = ty->ty_status |TTY_DIFF;
287: if(strcmp(tt->tt_getty, ty->ty_getty)) {
288: free(tt->tt_getty);
289: tt->tt_getty = newstring(ty->ty_getty);
290: tt->tt_status |= TTY_DIFF;
291: }
292: if(strcmp(tt->tt_type, ty->ty_type)) {
293: free(tt->tt_type);
294: tt->tt_type = newstring(ty->ty_type);
295: tt->tt_status |= TTY_DIFF;
296: }
297: if(((tt->tt_status |= TTY_SEEN) & TTY_DIFF)
298: && tt->tt_pid > 1)
299: kill(tt->tt_pid, 9);
300: break;
301: }
302: if(tt == ttytabend && tt < &ttytab[NTTY]) {
303: tt->tt_name = newstring(ty->ty_name);
304: tt->tt_getty = newstring(ty->ty_getty);
305: tt->tt_type = newstring(ty->ty_type);
306: tt->tt_status = ty->ty_status |
307: TTY_SEEN | TTY_DIFF;
308: ttytabend++;
309: }
310: }
311: endttyent();
312: /* second pass. offer gettys on previously cleaned entries,
313: and garbage collect "dead" entries */
314: for(tt = ttytab; tt < ttytabend; tt++)
315: if(tt->tt_status & TTY_SEEN) {
316: tt->tt_status &= ~TTY_SEEN;
317: if(tt->tt_status & TTY_DIFF) {
318: tt->tt_status &= ~TTY_DIFF;
319: getty(tt);
320: }
321: }
322: else {
323: if(tt->tt_pid > 1)
324: kill(tt->tt_pid, 9);
325: free(tt->tt_name);
326: free(tt->tt_getty);
327: free(tt->tt_type);
328: pid = tt - ttytab;
329: for(tt++; tt < ttytabend; tt++)
330: tt[-1] = *tt;
331: ttytabend--;
332: tt = &ttytab[pid];
333: }
334: }
335: drain = 0;
336:
337: /* listen for terminating gettys and sessions, and process them */
338: while(1) {
339: sigsetmask(mask);
340: pid = wait(&status);
341: sigblock(sigmask(SIGHUP) | sigmask(SIGTERM));
342: if(pid < 0) {
343: sleep(5);
344: continue;
345: }
346: for(tt = ttytab; tt < ttytabend; tt++)
347: if(pid == tt->tt_pid) {
1.2 cgd 348: /* 24 Jul 92*/ if (logout(tt->tt_name)) logwtmp(tt->tt_name,"","");
1.1 cgd 349: if(drain && !(tt->tt_status & TTY_LOGIN)) {
350: free(tt->tt_name);
351: free(tt->tt_getty);
352: free(tt->tt_type);
353: for(tt++; tt < ttytabend; tt++)
354: tt[-1] = *tt;
355: ttytabend--;
356: }
357: else
358: getty(tt);
359: break;
360: }
361: }
362: }
363:
364: /* process a getty for a "line". N.B. by having getty do open, init
365: is not limited by filedescriptors for number of possible users */
366: getty(tt)
367: struct ttytab *tt;
368: {
369: char *sargv[NARG];
370: register char *p = arg, **sp = sargv;
371:
372: if(!(tt->tt_status & TTY_ON)) {
373: tt->tt_pid = -1;
374: return;
375: }
376: if((tt->tt_pid = fork()) < 0)
377: fatal("getty fork");
378: else if(tt->tt_pid) {
379: if(tt->tt_status & TTY_LOGOUT)
380: tt->tt_status ^= TTY_LOGIN;
381: return;
382: }
383: signal(SIGHUP, SIG_DFL);
384: signal(SIGTERM, SIG_DFL);
385: signal(SIGTSTP, SIG_DFL);
386: sigsetmask(0);
387: strcpy(p, tt->tt_getty);
388: while(sp < &sargv[NARG - 2]) {
389: while(isspace(*p))
390: p++;
391: if(!*p)
392: break;
393: *sp++ = p;
394: while(!isspace(*p) && *p)
395: p++;
396: if(!*p)
397: break;
398: *p++ = 0;
399: }
400: strcpy(nam, tt->tt_name);
401: *sp++ = nam;
402: *sp = 0;
403: p = *sargv;
404: strcpy(term, "TERM=");
405: strcat(term, tt->tt_type);
406: execve(p, sargv, env);
407: bad:
408: sleep(30);
409: fatal(tt->tt_name);
410: }
411:
412: char *
413: newstring(s)
414: register char *s;
415: {
416: register char *n;
417:
418: if(!(n = malloc(strlen(s) + 1)))
419: fatal("out of memory");
420: strcpy(n, s);
421: return(n);
422: }
423:
424: warn(s)
425: char *s;
426: {
427: register int pid;
428: int fd;
429:
430: fd = open("/dev/console", 2);
431: writes(fd, "init WARNING: ");
432: writes(fd, s);
433: write(fd, "\n", 1);
434: close(fd);
435: }
436:
437: fatal(s)
438: char *s;
439: {
440: login_tty(open("/dev/console", 2));
441: writes(2, "init FATAL error: ");
442: perror(s);
1.2 cgd 443: _exit(1); /* 04 Sep 92*/
1.1 cgd 444: /* panic: init died */
445: }
446:
447: writes(n, s)
448: char *s;
449: {
450: write(n, s, strlen(s));
451: }
CVSweb <webmaster@jp.NetBSD.org>