Commit | Line | Data |
---|---|---|
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 | 8 | static 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 | ||
28 | char shell[] = "/bin/sh"; | |
7c8ab0e6 BJ |
29 | char minus[] = "-"; |
30 | char runc[] = "/etc/rc"; | |
25efc242 | 31 | char utmpf[] = "/etc/utmp"; |
7c8ab0e6 | 32 | char ctty[] = "/dev/console"; |
7c8ab0e6 | 33 | |
7c8ab0e6 BJ |
34 | struct 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 | |
49 | int fi; | |
50 | int mergflag; | |
51 | char tty[20]; | |
abf0db3c | 52 | jmp_buf sjbuf, shutpass; |
7c8ab0e6 BJ |
53 | |
54 | int reset(); | |
f570e1ff | 55 | int idle(); |
7c8ab0e6 BJ |
56 | char *strcpy(), *strcat(); |
57 | long lseek(); | |
58 | ||
068e4187 | 59 | struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; |
d0ca48ff | 60 | |
25efc242 | 61 | |
e618cb0b | 62 | #if defined(vax) || defined(tahoe) |
7c8ab0e6 BJ |
63 | main() |
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 |
70 | main(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 |
117 | int shutreset(); |
118 | ||
7c8ab0e6 BJ |
119 | shutdown() |
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 | 145 | char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n"; |
abf0db3c BJ |
146 | |
147 | shutreset() | |
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 | ||
162 | shutend() | |
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 | ||
173 | single() | |
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 |
199 | runcom(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 | 224 | int merge(); |
068e4187 | 225 | struct 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 |
231 | multiple() |
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 | |
268 | merge() | |
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 | 351 | term(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 | 365 | dfork(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 | 398 | cleanutmp(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 | ||
412 | reset() | |
413 | { | |
d0ca48ff | 414 | |
7c8ab0e6 BJ |
415 | longjmp(sjbuf, 1); |
416 | } | |
f570e1ff | 417 | |
d0ca48ff SL |
418 | jmp_buf idlebuf; |
419 | ||
420 | idlehup() | |
421 | { | |
422 | ||
423 | longjmp(idlebuf, 1); | |
424 | } | |
425 | ||
f570e1ff BJ |
426 | idle() |
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 | ||
452 | wterm(p) | |
453 | register struct tab *p; | |
454 | { | |
455 | if (p->wpid != 0) { | |
456 | kill(p->wpid, SIGKILL); | |
457 | } | |
458 | p->wpid = 0; | |
459 | } | |
460 | ||
461 | wstart(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 | ||
499 | execit(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 |
531 | done: |
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 | } |