unblock signals before fork, window mgr changes from jg
[unix-history] / usr / src / old / init / init.c
CommitLineData
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 8static 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
29char shell[] = "/bin/sh";
7c8ab0e6
BJ
30char minus[] = "-";
31char runc[] = "/etc/rc";
7c8ab0e6
BJ
32char utmp[] = "/etc/utmp";
33char wtmpf[] = "/usr/adm/wtmp";
34char ctty[] = "/dev/console";
7c8ab0e6
BJ
35
36struct utmp wtmp;
7c8ab0e6
BJ
37struct 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
51int fi;
52int mergflag;
53char tty[20];
abf0db3c 54jmp_buf sjbuf, shutpass;
f570e1ff 55time_t time0;
7c8ab0e6
BJ
56
57int reset();
f570e1ff 58int idle();
7c8ab0e6
BJ
59char *strcpy(), *strcat();
60long lseek();
61
068e4187 62struct sigvec rvec = { reset, sigmask(SIGHUP), 0 };
d0ca48ff
SL
63
64#ifdef vax
7c8ab0e6
BJ
65main()
66{
215943cc 67 register int r11; /* passed thru from boot */
d0ca48ff 68#else
8d3a6b89
TL
69main(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
117int shutreset();
118
7c8ab0e6
BJ
119shutdown()
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
140char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
141
142shutreset()
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
157shutend()
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
177single()
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
202runcom(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 239struct 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
245multiple()
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
279merge()
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 339term(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 355dfork(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 391rmut(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
430reset()
431{
d0ca48ff 432
7c8ab0e6
BJ
433 longjmp(sjbuf, 1);
434}
f570e1ff 435
d0ca48ff
SL
436jmp_buf idlebuf;
437
438idlehup()
439{
440
441 longjmp(idlebuf, 1);
442}
443
f570e1ff
BJ
444idle()
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
470wterm(p)
471 register struct tab *p;
472{
473 if (p->wpid != 0) {
474 kill(p->wpid, SIGKILL);
475 }
476 p->wpid = 0;
477}
478
479wstart(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
517execit(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
549done:
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}