|
|
1.1 root 1: /*
2: * Copyright (c) 1980,1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)init.c 5.18 (Berkeley) 6/26/90";
9: #endif not lint
10:
11: #include <sys/types.h>
12: #include <sys/file.h>
13: #include <sys/signal.h>
14: #include <sys/reboot.h>
15: #include <sys/syslog.h>
16: #include <sys/stat.h>
17: #include <sys/ioctl.h>
18: #include <setjmp.h>
19: #include <utmp.h>
20: #include <errno.h>
21: #include <ttyent.h>
22: #include "pathnames.h"
23:
24: #define CMDSIZ 200 /* max string length for getty or window command*/
25: #define ALL p = itab; p ; p = p->next
26: #define EVER ;;
27: #define SCPYN(a, b) strncpy(a, b, sizeof(a))
28: #define SCMPN(a, b) strncmp(a, b, sizeof(a))
29:
30: char shell[] = _PATH_BSHELL;
31: char minus[] = "-";
32: char runc[] = _PATH_RC;
33: char ctty[] = _PATH_CONSOLE;
34:
35: struct tab
36: {
37: char line[UT_LINESIZE];
38: char comn[CMDSIZ];
39: char xflag;
40: int pid;
41: int wpid; /* window system pid for SIGHUP */
42: char wcmd[CMDSIZ]; /* command to start window system process */
43: time_t gettytime;
44: int gettycnt;
45: time_t windtime;
46: int windcnt;
47: struct tab *next;
48: } *itab;
49:
50: int fi;
51: int mergflag;
52: char tty[20];
53: jmp_buf sjbuf, shutpass;
54:
55: char *strcpy(), *strcat();
56: long lseek();
57: void idle(), merge(), reset();
58:
59: struct sigvec rvec = { reset, sigmask(SIGHUP), 0 };
60:
61: main(argc, argv)
62: char **argv;
63: {
64: #if defined(tahoe)
65: register int r12; /* make sure r11 gets bootflags */
66: #endif
67: #if defined(vax) || defined(tahoe) || defined(hp300)
68: register int r11; /* passed thru from boot */
69: #endif
70: #ifdef __GNUC__
71: /* insure proper semantics for setjmp/longjmp */
72: static
73: #endif
74: int howto, oldhowto, started = 0;
75:
76: #if defined(vax) || defined(tahoe) || defined(hp300)
77: /* howto passed in high-order register XXX */
78: #ifdef __GNUC__
79: #ifdef hp300
80: asm("movl d7,%0" : "=rm" (howto));
81: #else
82: asm("movl r11,%0" : "=rm" (howto));
83: #endif
84: #else
85: howto = r11;
86: #endif /* __GNUC__ */
87: #else /* defined(vax) || defined(tahoe) || defined(hp300) */
88: /* howto passed as argument */
89: if (argc > 1 && argv[1][0] == '-') {
90: char *cp;
91:
92: howto = 0;
93: cp = &argv[1][1];
94: while (*cp) switch (*cp++) {
95: case 'a':
96: howto |= RB_ASKNAME;
97: break;
98: case 's':
99: howto |= RB_SINGLE;
100: break;
101: }
102: } else
103: howto = RB_SINGLE;
104: #endif
105: if (getuid() != 0)
106: exit(1);
107: openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
108: if (setsid() < 0)
109: syslog(LOG_ERR, "setsid failed (initial) %m");
110: sigvec(SIGTERM, &rvec, (struct sigvec *)0);
111: signal(SIGTSTP, idle);
112: signal(SIGTTIN, SIG_IGN);
113: signal(SIGTTOU, SIG_IGN);
114: (void) setjmp(sjbuf);
115: for (; ; ) {
116: oldhowto = howto;
117: howto = RB_SINGLE;
118: if (started && setjmp(shutpass) == 0)
119: shutdown();
120: started = 1;
121: if (oldhowto & RB_SINGLE)
122: single();
123: if (runcom(oldhowto) == 0)
124: continue;
125: merge();
126: multiple();
127: }
128: }
129:
130: void shutreset();
131:
132: shutdown()
133: {
134: register i;
135: register struct tab *p, *p1;
136:
137: signal(SIGHUP, SIG_IGN);
138: for (p = itab; p ; ) {
139: term(p);
140: p1 = p->next;
141: free(p);
142: p = p1;
143: }
144: itab = (struct tab *)0;
145: signal(SIGALRM, shutreset);
146: (void) kill(-1, SIGTERM); /* one chance to catch it */
147: sleep(5);
148: alarm(30);
149: for (i = 0; i < 5; i++)
150: kill(-1, SIGKILL);
151: while (wait((int *)0) != -1)
152: ;
153: alarm(0);
154: shutend();
155: }
156:
157: char shutfailm[] = "init: WARNING: something is hung (won't die); ps axl advised\n";
158:
159: void
160: shutreset()
161: {
162: int status;
163:
164: if (fork() == 0) {
165: int ct = open(ctty, 1);
166: write(ct, shutfailm, sizeof (shutfailm));
167: sleep(5);
168: exit(1);
169: }
170: sleep(5);
171: shutend();
172: longjmp(shutpass, 1);
173: }
174:
175: shutend()
176: {
177: register i;
178:
179: acct(0);
180: signal(SIGALRM, SIG_DFL);
181: for (i = 0; i < 10; i++)
182: close(i);
183: logwtmp("~", "shutdown", "");
184: }
185:
186: single()
187: {
188: register pid;
189: register xpid;
190: int fd;
191: extern int errno;
192:
193: do {
194: pid = fork();
195: if (pid == 0) {
196: signal(SIGTERM, SIG_DFL);
197: signal(SIGHUP, SIG_DFL);
198: signal(SIGALRM, SIG_DFL);
199: signal(SIGTSTP, SIG_IGN);
200: if (setsid() < 0)
201: syslog(LOG_ERR, "setsid failed (single): %m");
202: (void) revoke(ctty);
203: if ((fd = open(ctty, O_RDWR)) < 0) {
204: syslog(LOG_ERR, "open %s: %m", ctty);
205: exit(1);
206: }
207: if (ioctl(fd, TIOCSCTTY, 0) < 0)
208: syslog(LOG_ERR, "TIOCSCTTY failed: %m");
209: dup2(fd, 0);
210: dup2(fd, 1);
211: dup2(fd, 2);
212: if (fd > 2)
213: close(fd);
214: execl(shell, minus, (char *)0);
215: perror(shell);
216: exit(0);
217: }
218: while ((xpid = wait((int *)0)) != pid)
219: if (xpid == -1 && errno == ECHILD)
220: break;
221: } while (xpid == -1);
222: }
223:
224: runcom(oldhowto)
225: int oldhowto;
226: {
227: register pid;
228: int fd, status;
229:
230: pid = fork();
231: if (pid == 0) {
232: signal(SIGTSTP, SIG_IGN);
233: signal(SIGHUP, SIG_IGN);
234: if ((fd = open(ctty, O_RDWR)) < 0)
235: syslog(LOG_ERR, "open %s: %m", ctty);
236: else {
237: dup2(fd, 0);
238: dup2(fd, 1);
239: dup2(fd, 2);
240: if (fd > 2)
241: close(fd);
242: }
243: if (setsid() < 0)
244: syslog(LOG_ERR, "setsid failed (runcom) %m");
245: if (ioctl(0, TIOCSCTTY, 0) < 0)
246: syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m");
247: if (oldhowto & RB_SINGLE)
248: execl(shell, shell, runc, (char *)0);
249: else
250: execl(shell, shell, runc, "autoboot", (char *)0);
251: exit(1);
252: }
253: while (wait(&status) != pid)
254: ;
255: if (status)
256: return (0);
257: logwtmp("~", "reboot", "");
258: return (1);
259: }
260:
261: struct sigvec mvec = { merge, sigmask(SIGTERM), 0 };
262: /*
263: * Multi-user. Listen for users leaving, SIGHUP's
264: * which indicate ttys has changed, and SIGTERM's which
265: * are used to shutdown the system.
266: */
267: multiple()
268: {
269: extern int errno;
270: register struct tab *p;
271: register pid;
272: int omask;
273:
274: sigvec(SIGHUP, &mvec, (struct sigvec *)0);
275: for (EVER) {
276: pid = wait((int *)0);
277: /* SHOULD FIX THIS IN THE KERNEL */
278: if (pid == -1 && errno != EINTR)
279: return;
280: omask = sigblock(sigmask(SIGHUP));
281: for (ALL) {
282: /* must restart window system BEFORE emulator */
283: if (p->wpid == pid || p->wpid == -1)
284: wstart(p);
285: if (p->pid == pid || p->pid == -1) {
286: /* disown the window system */
287: if (p->wpid)
288: kill(p->wpid, SIGHUP);
289: cleanutmp(p);
290: dfork(p);
291: }
292: }
293: sigsetmask(omask);
294: }
295: }
296:
297: /*
298: * Merge current contents of ttys file
299: * into in-core table of configured tty lines.
300: * Entered as signal handler for SIGHUP.
301: */
302: #define FOUND 1
303: #define CHANGE 2
304: #define WCHANGE 4
305:
306: void
307: merge()
308: {
309: register struct tab *p;
310: register struct ttyent *t;
311: register struct tab *p1;
312:
313: for (ALL)
314: p->xflag = 0;
315: setttyent();
316: while (t = getttyent()) {
317: if ((t->ty_status & TTY_ON) == 0)
318: continue;
319: for (ALL) {
320: if (SCMPN(p->line, t->ty_name))
321: continue;
322: p->xflag |= FOUND;
323: if (SCMPN(p->comn, t->ty_getty)) {
324: p->xflag |= CHANGE;
325: SCPYN(p->comn, t->ty_getty);
326: }
327: if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) {
328: p->xflag |= WCHANGE|CHANGE;
329: SCPYN(p->wcmd, t->ty_window);
330: }
331: goto contin1;
332: }
333:
334: /*
335: * Make space for a new one
336: */
337: p1 = (struct tab *)calloc(1, sizeof(*p1));
338: if (!p1) {
339: syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
340: goto contin1;
341: }
342: /*
343: * Put new terminal at the end of the linked list.
344: */
345: if (itab) {
346: for (p = itab; p->next ; p = p->next)
347: ;
348: p->next = p1;
349: } else
350: itab = p1;
351:
352: p = p1;
353: SCPYN(p->line, t->ty_name);
354: p->xflag |= FOUND|CHANGE;
355: SCPYN(p->comn, t->ty_getty);
356: if (t->ty_window && strcmp(t->ty_window, "") != 0) {
357: p->xflag |= WCHANGE;
358: SCPYN(p->wcmd, t->ty_window);
359: }
360: contin1:
361: ;
362: }
363: endttyent();
364: p1 = (struct tab *)0;
365: for (ALL) {
366: if ((p->xflag&FOUND) == 0) {
367: term(p);
368: wterm(p);
369: if (p1)
370: p1->next = p->next;
371: else
372: itab = p->next;
373: free(p);
374: p = p1 ? p1 : itab;
375: } else {
376: /* window system should be started first */
377: if (p->xflag&WCHANGE) {
378: wterm(p);
379: wstart(p);
380: }
381: if (p->xflag&CHANGE) {
382: term(p);
383: dfork(p);
384: }
385: }
386: p1 = p;
387: }
388: }
389:
390: term(p)
391: register struct tab *p;
392: {
393:
394: if (p->pid != 0) {
395: cleanutmp(p);
396: kill(p->pid, SIGKILL);
397: }
398: p->pid = 0;
399: /* send SIGHUP to get rid of connections */
400: if (p->wpid > 0)
401: kill(p->wpid, SIGHUP);
402: }
403:
404: dfork(p)
405: struct tab *p;
406: {
407: register pid;
408: time_t t;
409: int dowait = 0;
410:
411: time(&t);
412: p->gettycnt++;
413: if ((t - p->gettytime) >= 60) {
414: p->gettytime = t;
415: p->gettycnt = 1;
416: } else if (p->gettycnt >= 5) {
417: dowait = 1;
418: p->gettytime = t;
419: p->gettycnt = 1;
420: }
421: pid = fork();
422: if (pid == 0) {
423: signal(SIGTERM, SIG_DFL);
424: signal(SIGHUP, SIG_IGN);
425: sigsetmask(0); /* since can be called from masked code */
426: if (dowait) {
427: syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
428: closelog();
429: sleep(30);
430: }
431: if (setsid() < 0)
432: syslog(LOG_ERR, "setsid failed(dfork) %m");
433: execit(p->comn, p->line);
434: exit(0);
435: }
436: p->pid = pid;
437: }
438:
439: cleanutmp(p)
440: register struct tab *p;
441: {
442: if (logout(p->line)) {
443: logwtmp(p->line, "", "");
444: /*
445: * After a proper login force reset
446: * of error detection code in dfork.
447: */
448: p->gettytime = 0;
449: p->windtime = 0;
450: }
451: }
452:
453: void
454: reset()
455: {
456: longjmp(sjbuf, 1);
457: }
458:
459: jmp_buf idlebuf;
460:
461: void
462: idlehup()
463: {
464: longjmp(idlebuf, 1);
465: }
466:
467: void
468: idle()
469: {
470: register struct tab *p;
471: register pid;
472:
473: signal(SIGHUP, idlehup);
474: for (EVER) {
475: if (setjmp(idlebuf))
476: return;
477: pid = wait((int *) 0);
478: if (pid == -1) {
479: sigpause(0);
480: continue;
481: }
482: for (ALL) {
483: /* if window system dies, mark it for restart */
484: if (p->wpid == pid)
485: p->wpid = -1;
486: if (p->pid == pid) {
487: cleanutmp(p);
488: p->pid = -1;
489: }
490: }
491: }
492: }
493:
494: wterm(p)
495: register struct tab *p;
496: {
497: if (p->wpid != 0) {
498: kill(p->wpid, SIGKILL);
499: }
500: p->wpid = 0;
501: }
502:
503: wstart(p)
504: register struct tab *p;
505: {
506: register pid;
507: time_t t;
508: int dowait = 0;
509:
510: time(&t);
511: p->windcnt++;
512: if ((t - p->windtime) >= 60) {
513: p->windtime = t;
514: p->windcnt = 1;
515: } else if (p->windcnt >= 5) {
516: dowait = 1;
517: p->windtime = t;
518: p->windcnt = 1;
519: }
520:
521: pid = fork();
522:
523: if (pid == 0) {
524: signal(SIGTERM, SIG_DFL);
525: signal(SIGHUP, SIG_IGN);
526: sigsetmask(0); /* since can be called from masked code */
527: if (dowait) {
528: syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
529: closelog();
530: sleep(30);
531: }
532: if (setsid() < 0)
533: syslog(LOG_ERR, "setsid failed (window) %m");
534: execit(p->wcmd, p->line);
535: exit(0);
536: }
537: p->wpid = pid;
538: }
539:
540: #define NARGS 20 /* must be at least 4 */
541: #define ARGLEN 512 /* total size for all the argument strings */
542:
543: execit(s, arg)
544: char *s;
545: char *arg; /* last argument on line */
546: {
547: char *argv[NARGS], args[ARGLEN], *envp[1];
548: register char *sp = s;
549: register char *ap = args;
550: register char c;
551: register int i;
552:
553: /*
554: * First we have to set up the argument vector.
555: * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
556: */
557: for (i = 1; i < NARGS - 2; i++) {
558: argv[i] = ap;
559: for (EVER) {
560: if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
561: *ap = '\0';
562: goto done;
563: }
564: if (c == ' ') {
565: *ap++ = '\0';
566: while (*sp == ' ')
567: sp++;
568: if (*sp == '\0')
569: goto done;
570: break;
571: }
572: *ap++ = c;
573: }
574: }
575: done:
576: argv[0] = argv[1];
577: argv[1] = "-";
578: argv[i+1] = arg;
579: argv[i+2] = 0;
580: envp[0] = 0;
581: execve(argv[0], &argv[1], envp);
582: /* report failure of exec */
583: syslog(LOG_ERR, "%s: %m", argv[0]);
584: closelog();
585: sleep(10); /* prevent failures from eating machine */
586: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.