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