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