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