1 /*
2 * Copyright (c) 1980,1986 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
7 #ifndef lint
8 static char sccsid[] = "@(#)init.c 5.19 (Berkeley) 03/25/91";
9 #endif not lint
10
11 #include <sys/types.h>
12 #include <sys/file.h>
13 #include <sys/signal.h>
14 #include <sys/reboot.h>
15 #include <sys/syslog.h>
16 #include <sys/stat.h>
17 #include <sys/ioctl.h>
18 #include <setjmp.h>
19 #include <utmp.h>
20 #include <errno.h>
21 #include <ttyent.h>
22 #include "pathnames.h"
23
24 #define CMDSIZ 200 /* max string length for getty or window command*/
25 #define ALL p = itab; p ; p = p->next
26 #define EVER ;;
27 #define SCPYN(a, b) strncpy(a, b, sizeof(a))
28 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
29
30 char shell[] = _PATH_BSHELL;
31 char minus[] = "-";
32 char runc[] = _PATH_RC;
33 char ctty[] = _PATH_CONSOLE;
34
35 struct tab
36 {
37 char line[UT_LINESIZE];
38 char comn[CMDSIZ];
39 char xflag;
40 int pid;
41 int wpid; /* window system pid for SIGHUP */
42 char wcmd[CMDSIZ]; /* command to start window system process */
43 time_t gettytime;
44 int gettycnt;
45 time_t windtime;
46 int windcnt;
47 struct tab *next;
48 } *itab;
49
50 int fi;
51 int mergflag;
52 char tty[20];
53 jmp_buf sjbuf, shutpass;
54
55 char *strcpy(), *strcat();
56 long lseek();
57 void idle(), merge(), reset();
58
59 struct sigvec rvec = { reset, sigmask(SIGHUP), 0 };
60
main(argc,argv)61 main(argc, argv)
62 char **argv;
63 {
64 /* insure proper semantics for setjmp/longjmp */
65 static int howto, oldhowto, started = 0;
66 #if defined(tahoe)
67 register int r12; /* make sure r11 gets bootflags */
68 #endif
69 #if defined(vax) || defined(tahoe) || defined(hp300)
70 /* howto passed in high-order register XXX */
71 register int r11; /* passed thru from boot */
72 #ifdef __GNUC__
73 #ifdef hp300
74 asm("movl d7,%0" : "=rm" (howto));
75 #else
76 asm("movl r11,%0" : "=rm" (howto));
77 #endif
78 #else
79 howto = r11;
80 #endif /* __GNUC__ */
81 #else /* vax || tahoe || hp300 */
82 /* howto passed as argument */
83 howto = 0;
84 #endif /* ! (vax || tahoe || hp300) */
85
86 /*
87 * We expect a single options argument from the kernel.
88 * If it is present, we ignore anything in registers from above.
89 */
90 if (argc > 1 && argv[1][0] == '-') {
91 char *cp;
92
93 howto = 0;
94 cp = &argv[1][1];
95 while (*cp) switch (*cp++) {
96 #ifdef notyet
97 case 'f':
98 howto |= RB_FASTBOOT;
99 break;
100 #endif
101 case 's':
102 howto |= RB_SINGLE;
103 break;
104 }
105 }
106 if (getuid() != 0)
107 exit(1);
108 openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
109 if (setsid() < 0)
110 syslog(LOG_ERR, "setsid failed (initial) %m");
111 sigvec(SIGTERM, &rvec, (struct sigvec *)0);
112 signal(SIGTSTP, idle);
113 signal(SIGTTIN, SIG_IGN);
114 signal(SIGTTOU, SIG_IGN);
115 (void) setjmp(sjbuf);
116 for (; ; ) {
117 oldhowto = howto;
118 howto = RB_SINGLE;
119 if (started && setjmp(shutpass) == 0)
120 shutdown();
121 started = 1;
122 if (oldhowto & RB_SINGLE)
123 single();
124 if (runcom(oldhowto) == 0)
125 continue;
126 merge();
127 multiple();
128 }
129 }
130
131 void shutreset();
132
shutdown()133 shutdown()
134 {
135 register i;
136 register struct tab *p, *p1;
137
138 signal(SIGHUP, SIG_IGN);
139 for (p = itab; p ; ) {
140 term(p);
141 p1 = p->next;
142 free(p);
143 p = p1;
144 }
145 itab = (struct tab *)0;
146 signal(SIGALRM, shutreset);
147 (void) kill(-1, SIGTERM); /* one chance to catch it */
148 sleep(5);
149 alarm(30);
150 for (i = 0; i < 5; i++)
151 kill(-1, SIGKILL);
152 while (wait((int *)0) != -1)
153 ;
154 alarm(0);
155 shutend();
156 }
157
158 char shutfailm[] = "init: WARNING: something is hung (won't die); ps axl advised\n";
159
160 void
shutreset()161 shutreset()
162 {
163 int status;
164
165 if (fork() == 0) {
166 int ct = open(ctty, 1);
167 write(ct, shutfailm, sizeof (shutfailm));
168 sleep(5);
169 exit(1);
170 }
171 sleep(5);
172 shutend();
173 longjmp(shutpass, 1);
174 }
175
shutend()176 shutend()
177 {
178 register i;
179
180 acct(0);
181 signal(SIGALRM, SIG_DFL);
182 for (i = 0; i < 10; i++)
183 close(i);
184 logwtmp("~", "shutdown", "");
185 }
186
single()187 single()
188 {
189 register pid;
190 register xpid;
191 int fd;
192 extern int errno;
193
194 do {
195 pid = fork();
196 if (pid == 0) {
197 signal(SIGTERM, SIG_DFL);
198 signal(SIGHUP, SIG_DFL);
199 signal(SIGALRM, SIG_DFL);
200 signal(SIGTSTP, SIG_IGN);
201 if (setsid() < 0)
202 syslog(LOG_ERR, "setsid failed (single): %m");
203 (void) revoke(ctty);
204 if ((fd = open(ctty, O_RDWR)) < 0) {
205 syslog(LOG_ERR, "open %s: %m", ctty);
206 exit(1);
207 }
208 if (ioctl(fd, TIOCSCTTY, 0) < 0)
209 syslog(LOG_ERR, "TIOCSCTTY failed: %m");
210 dup2(fd, 0);
211 dup2(fd, 1);
212 dup2(fd, 2);
213 if (fd > 2)
214 close(fd);
215 execl(shell, minus, (char *)0);
216 perror(shell);
217 exit(0);
218 }
219 while ((xpid = wait((int *)0)) != pid)
220 if (xpid == -1 && errno == ECHILD)
221 break;
222 } while (xpid == -1);
223 }
224
runcom(oldhowto)225 runcom(oldhowto)
226 int oldhowto;
227 {
228 register pid;
229 int fd, status;
230
231 pid = fork();
232 if (pid == 0) {
233 signal(SIGTSTP, SIG_IGN);
234 signal(SIGHUP, SIG_IGN);
235 if ((fd = open(ctty, O_RDWR)) < 0)
236 syslog(LOG_ERR, "open %s: %m", ctty);
237 else {
238 dup2(fd, 0);
239 dup2(fd, 1);
240 dup2(fd, 2);
241 if (fd > 2)
242 close(fd);
243 }
244 if (setsid() < 0)
245 syslog(LOG_ERR, "setsid failed (runcom) %m");
246 if (ioctl(0, TIOCSCTTY, 0) < 0)
247 syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m");
248 if (oldhowto & RB_SINGLE)
249 execl(shell, shell, runc, (char *)0);
250 else
251 execl(shell, shell, runc, "autoboot", (char *)0);
252 exit(1);
253 }
254 while (wait(&status) != pid)
255 ;
256 if (status)
257 return (0);
258 logwtmp("~", "reboot", "");
259 return (1);
260 }
261
262 struct sigvec mvec = { merge, sigmask(SIGTERM), 0 };
263 /*
264 * Multi-user. Listen for users leaving, SIGHUP's
265 * which indicate ttys has changed, and SIGTERM's which
266 * are used to shutdown the system.
267 */
multiple()268 multiple()
269 {
270 extern int errno;
271 register struct tab *p;
272 register pid;
273 int omask;
274
275 sigvec(SIGHUP, &mvec, (struct sigvec *)0);
276 for (EVER) {
277 pid = wait((int *)0);
278 /* SHOULD FIX THIS IN THE KERNEL */
279 if (pid == -1 && errno != EINTR)
280 return;
281 omask = sigblock(sigmask(SIGHUP));
282 for (ALL) {
283 /* must restart window system BEFORE emulator */
284 if (p->wpid == pid || p->wpid == -1)
285 wstart(p);
286 if (p->pid == pid || p->pid == -1) {
287 /* disown the window system */
288 if (p->wpid)
289 kill(p->wpid, SIGHUP);
290 cleanutmp(p);
291 dfork(p);
292 }
293 }
294 sigsetmask(omask);
295 }
296 }
297
298 /*
299 * Merge current contents of ttys file
300 * into in-core table of configured tty lines.
301 * Entered as signal handler for SIGHUP.
302 */
303 #define FOUND 1
304 #define CHANGE 2
305 #define WCHANGE 4
306
307 void
merge()308 merge()
309 {
310 register struct tab *p;
311 register struct ttyent *t;
312 register struct tab *p1;
313
314 for (ALL)
315 p->xflag = 0;
316 setttyent();
317 while (t = getttyent()) {
318 if ((t->ty_status & TTY_ON) == 0)
319 continue;
320 for (ALL) {
321 if (SCMPN(p->line, t->ty_name))
322 continue;
323 p->xflag |= FOUND;
324 if (SCMPN(p->comn, t->ty_getty)) {
325 p->xflag |= CHANGE;
326 SCPYN(p->comn, t->ty_getty);
327 }
328 if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) {
329 p->xflag |= WCHANGE|CHANGE;
330 SCPYN(p->wcmd, t->ty_window);
331 }
332 goto contin1;
333 }
334
335 /*
336 * Make space for a new one
337 */
338 p1 = (struct tab *)calloc(1, sizeof(*p1));
339 if (!p1) {
340 syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
341 goto contin1;
342 }
343 /*
344 * Put new terminal at the end of the linked list.
345 */
346 if (itab) {
347 for (p = itab; p->next ; p = p->next)
348 ;
349 p->next = p1;
350 } else
351 itab = p1;
352
353 p = p1;
354 SCPYN(p->line, t->ty_name);
355 p->xflag |= FOUND|CHANGE;
356 SCPYN(p->comn, t->ty_getty);
357 if (t->ty_window && strcmp(t->ty_window, "") != 0) {
358 p->xflag |= WCHANGE;
359 SCPYN(p->wcmd, t->ty_window);
360 }
361 contin1:
362 ;
363 }
364 endttyent();
365 p1 = (struct tab *)0;
366 for (ALL) {
367 if ((p->xflag&FOUND) == 0) {
368 term(p);
369 wterm(p);
370 if (p1)
371 p1->next = p->next;
372 else
373 itab = p->next;
374 free(p);
375 p = p1 ? p1 : itab;
376 } else {
377 /* window system should be started first */
378 if (p->xflag&WCHANGE) {
379 wterm(p);
380 wstart(p);
381 }
382 if (p->xflag&CHANGE) {
383 term(p);
384 dfork(p);
385 }
386 }
387 p1 = p;
388 }
389 }
390
term(p)391 term(p)
392 register struct tab *p;
393 {
394
395 if (p->pid != 0) {
396 cleanutmp(p);
397 kill(p->pid, SIGKILL);
398 }
399 p->pid = 0;
400 /* send SIGHUP to get rid of connections */
401 if (p->wpid > 0)
402 kill(p->wpid, SIGHUP);
403 }
404
405 dfork(p)
406 struct tab *p;
407 {
408 register pid;
409 time_t t;
410 int dowait = 0;
411
412 time(&t);
413 p->gettycnt++;
414 if ((t - p->gettytime) >= 60) {
415 p->gettytime = t;
416 p->gettycnt = 1;
417 } else if (p->gettycnt >= 5) {
418 dowait = 1;
419 p->gettytime = t;
420 p->gettycnt = 1;
421 }
422 pid = fork();
423 if (pid == 0) {
424 signal(SIGTERM, SIG_DFL);
425 signal(SIGHUP, SIG_IGN);
426 sigsetmask(0); /* since can be called from masked code */
427 if (dowait) {
428 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
429 closelog();
430 sleep(30);
431 }
432 if (setsid() < 0)
433 syslog(LOG_ERR, "setsid failed(dfork) %m");
434 execit(p->comn, p->line);
435 exit(0);
436 }
437 p->pid = pid;
438 }
439
cleanutmp(p)440 cleanutmp(p)
441 register struct tab *p;
442 {
443 if (logout(p->line)) {
444 logwtmp(p->line, "", "");
445 /*
446 * After a proper login force reset
447 * of error detection code in dfork.
448 */
449 p->gettytime = 0;
450 p->windtime = 0;
451 }
452 }
453
454 void
reset()455 reset()
456 {
457 longjmp(sjbuf, 1);
458 }
459
460 jmp_buf idlebuf;
461
462 void
idlehup()463 idlehup()
464 {
465 longjmp(idlebuf, 1);
466 }
467
468 void
idle()469 idle()
470 {
471 register struct tab *p;
472 register pid;
473
474 signal(SIGHUP, idlehup);
475 for (EVER) {
476 if (setjmp(idlebuf))
477 return;
478 pid = wait((int *) 0);
479 if (pid == -1) {
480 sigpause(0);
481 continue;
482 }
483 for (ALL) {
484 /* if window system dies, mark it for restart */
485 if (p->wpid == pid)
486 p->wpid = -1;
487 if (p->pid == pid) {
488 cleanutmp(p);
489 p->pid = -1;
490 }
491 }
492 }
493 }
494
wterm(p)495 wterm(p)
496 register struct tab *p;
497 {
498 if (p->wpid != 0) {
499 kill(p->wpid, SIGKILL);
500 }
501 p->wpid = 0;
502 }
503
wstart(p)504 wstart(p)
505 register struct tab *p;
506 {
507 register pid;
508 time_t t;
509 int dowait = 0;
510
511 time(&t);
512 p->windcnt++;
513 if ((t - p->windtime) >= 60) {
514 p->windtime = t;
515 p->windcnt = 1;
516 } else if (p->windcnt >= 5) {
517 dowait = 1;
518 p->windtime = t;
519 p->windcnt = 1;
520 }
521
522 pid = fork();
523
524 if (pid == 0) {
525 signal(SIGTERM, SIG_DFL);
526 signal(SIGHUP, SIG_IGN);
527 sigsetmask(0); /* since can be called from masked code */
528 if (dowait) {
529 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
530 closelog();
531 sleep(30);
532 }
533 if (setsid() < 0)
534 syslog(LOG_ERR, "setsid failed (window) %m");
535 execit(p->wcmd, p->line);
536 exit(0);
537 }
538 p->wpid = pid;
539 }
540
541 #define NARGS 20 /* must be at least 4 */
542 #define ARGLEN 512 /* total size for all the argument strings */
543
execit(s,arg)544 execit(s, arg)
545 char *s;
546 char *arg; /* last argument on line */
547 {
548 char *argv[NARGS], args[ARGLEN], *envp[1];
549 register char *sp = s;
550 register char *ap = args;
551 register char c;
552 register int i;
553
554 /*
555 * First we have to set up the argument vector.
556 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
557 */
558 for (i = 1; i < NARGS - 2; i++) {
559 argv[i] = ap;
560 for (EVER) {
561 if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
562 *ap = '\0';
563 goto done;
564 }
565 if (c == ' ') {
566 *ap++ = '\0';
567 while (*sp == ' ')
568 sp++;
569 if (*sp == '\0')
570 goto done;
571 break;
572 }
573 *ap++ = c;
574 }
575 }
576 done:
577 argv[0] = argv[1];
578 argv[1] = "-";
579 argv[i+1] = arg;
580 argv[i+2] = 0;
581 envp[0] = 0;
582 execve(argv[0], &argv[1], envp);
583 /* report failure of exec */
584 syslog(LOG_ERR, "%s: %m", argv[0]);
585 closelog();
586 sleep(10); /* prevent failures from eating machine */
587 }
588