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