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