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