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