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