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