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