Add copyright
[unix-history] / usr / src / old / init / init.c
... / ...
CommitLineData
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
8#ifndef lint
9static char sccsid[] = "@(#)init.c 5.1 (Berkeley) %G%";
10#endif not lint
11
12#include <signal.h>
13#include <sys/types.h>
14#include <utmp.h>
15#include <setjmp.h>
16#include <sys/reboot.h>
17#include <errno.h>
18#include <sys/file.h>
19#include <ttyent.h>
20#include <syslog.h>
21
22#define LINSIZ sizeof(wtmp.ut_line)
23#define CMDSIZ 70 /* max string length for getty or window command*/
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";
31char minus[] = "-";
32char runc[] = "/etc/rc";
33char utmp[] = "/etc/utmp";
34char wtmpf[] = "/usr/adm/wtmp";
35char ctty[] = "/dev/console";
36
37struct utmp wtmp;
38struct tab
39{
40 char line[LINSIZ];
41 char comn[CMDSIZ];
42 char xflag;
43 int pid;
44 int wpid; /* window system pid for SIGHUP */
45 char wcmd[CMDSIZ]; /* command to start window system process */
46 time_t gettytime;
47 int gettycnt;
48} itab[TABSIZ];
49
50int fi;
51int mergflag;
52char tty[20];
53jmp_buf sjbuf, shutpass;
54time_t time0;
55
56int reset();
57int idle();
58char *strcpy(), *strcat();
59long lseek();
60
61struct sigvec rvec = { reset, sigmask(SIGHUP), 0 };
62
63#ifdef vax
64main()
65{
66 register int r11; /* passed thru from boot */
67#else
68main(argc, argv)
69 char **argv;
70{
71#endif
72 int howto, oldhowto;
73
74 time0 = time(0);
75#ifdef vax
76 howto = r11;
77#else
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 }
94#endif
95 openlog("init", LOG_CONS|LOG_ODELAY, 0);
96 sigvec(SIGTERM, &rvec, (struct sigvec *)0);
97 signal(SIGTSTP, idle);
98 signal(SIGSTOP, SIG_IGN);
99 signal(SIGTTIN, SIG_IGN);
100 signal(SIGTTOU, SIG_IGN);
101 (void) setjmp(sjbuf);
102 for (EVER) {
103 oldhowto = howto;
104 howto = RB_SINGLE;
105 if (setjmp(shutpass) == 0)
106 shutdown();
107 if (oldhowto & RB_SINGLE)
108 single();
109 if (runcom(oldhowto) == 0)
110 continue;
111 merge();
112 multiple();
113 }
114}
115
116int shutreset();
117
118shutdown()
119{
120 register i;
121 register struct tab *p;
122
123 close(creat(utmp, 0644));
124 signal(SIGHUP, SIG_IGN);
125 for (ALL) {
126 term(p);
127 p->line[0] = 0;
128 }
129 signal(SIGALRM, shutreset);
130 alarm(30);
131 for (i = 0; i < 5; i++)
132 kill(-1, SIGKILL);
133 while (wait((int *)0) != -1)
134 ;
135 alarm(0);
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{
158 register i, f;
159
160 acct(0);
161 signal(SIGALRM, SIG_DFL);
162 for (i = 0; i < 10; i++)
163 close(i);
164 f = open(wtmpf, O_WRONLY|O_APPEND);
165 if (f >= 0) {
166 SCPYN(wtmp.ut_line, "~");
167 SCPYN(wtmp.ut_name, "shutdown");
168 SCPYN(wtmp.ut_host, "");
169 time(&wtmp.ut_time);
170 write(f, (char *)&wtmp, sizeof(wtmp));
171 close(f);
172 }
173 return (1);
174}
175
176single()
177{
178 register pid;
179 register xpid;
180 extern errno;
181
182 do {
183 pid = fork();
184 if (pid == 0) {
185 signal(SIGTERM, SIG_DFL);
186 signal(SIGHUP, SIG_DFL);
187 signal(SIGALRM, SIG_DFL);
188 signal(SIGTSTP, SIG_IGN);
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);
199}
200
201runcom(oldhowto)
202 int oldhowto;
203{
204 register pid, f;
205 int status;
206
207 pid = fork();
208 if (pid == 0) {
209 (void) open("/", O_RDONLY);
210 dup2(0, 1);
211 dup2(0, 2);
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);
217 }
218 while (wait(&status) != pid)
219 ;
220 if (status)
221 return (0);
222 f = open(wtmpf, O_WRONLY|O_APPEND);
223 if (f >= 0) {
224 SCPYN(wtmp.ut_line, "~");
225 SCPYN(wtmp.ut_name, "reboot");
226 SCPYN(wtmp.ut_host, "");
227 if (time0) {
228 wtmp.ut_time = time0;
229 time0 = 0;
230 } else
231 time(&wtmp.ut_time);
232 write(f, (char *)&wtmp, sizeof(wtmp));
233 close(f);
234 }
235 return (1);
236}
237
238struct sigvec mvec = { merge, sigmask(SIGTERM), 0 };
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 */
244multiple()
245{
246 register struct tab *p;
247 register pid;
248
249 sigvec(SIGHUP, &mvec, (struct sigvec *)0);
250 for (EVER) {
251 pid = wait((int *)0);
252 if (pid == -1)
253 return;
254 for (ALL) {
255 /* must restart window system BEFORE emulator */
256 if (p->wpid == pid || p->wpid == -1)
257 wstart(p);
258 if (p->pid == pid || p->pid == -1) {
259 /* disown the window system */
260 if (p->wpid)
261 kill(p->wpid, SIGHUP);
262 rmut(p);
263 dfork(p);
264 }
265 }
266 }
267}
268
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
276#define WCHANGE 4
277
278merge()
279{
280 register struct tab *p;
281 register struct ttyent *t;
282
283 for (ALL)
284 p->xflag = 0;
285 setttyent();
286 while (t = getttyent()) {
287 if ((t->ty_status & TTY_ON) == 0)
288 continue;
289 for (ALL) {
290 if (SCMPN(p->line, t->ty_name))
291 continue;
292 p->xflag |= FOUND;
293 if (SCMPN(p->comn, t->ty_getty)) {
294 p->xflag |= CHANGE;
295 SCPYN(p->comn, t->ty_getty);
296 }
297 if (SCMPN(p->wcmd, t->ty_window)) {
298 p->xflag |= WCHANGE|CHANGE;
299 SCPYN(p->wcmd, t->ty_window);
300 }
301 goto contin1;
302 }
303
304 for (ALL) {
305 if (p->line[0] != 0)
306 continue;
307 SCPYN(p->line, t->ty_name);
308 p->xflag |= FOUND|CHANGE;
309 SCPYN(p->comn, t->ty_getty);
310 if (strcmp(t->ty_window, "") != 0) {
311 p->xflag |= WCHANGE;
312 SCPYN(p->wcmd, t->ty_window);
313 }
314 goto contin1;
315 }
316 contin1:
317 ;
318 }
319 endttyent();
320 for (ALL) {
321 if ((p->xflag&FOUND) == 0) {
322 term(p);
323 p->line[0] = 0;
324 wterm(p);
325 }
326 /* window system should be started first */
327 if (p->xflag&WCHANGE) {
328 wterm(p);
329 wstart(p);
330 }
331 if (p->xflag&CHANGE) {
332 term(p);
333 dfork(p);
334 }
335 }
336}
337
338term(p)
339 register struct tab *p;
340{
341
342 if (p->pid != 0) {
343 rmut(p);
344 kill(p->pid, SIGKILL);
345 }
346 p->pid = 0;
347 /* send SIGHUP to get rid of connections */
348 if (p->wpid > 0)
349 kill(p->wpid, SIGHUP);
350}
351
352#include <sys/ioctl.h>
353
354dfork(p)
355 struct tab *p;
356{
357 register pid;
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;
366 } else if (p->gettycnt >= 5) {
367 dowait = 1;
368 p->gettytime = t;
369 p->gettycnt = 1;
370 }
371 pid = fork();
372 if (pid == 0) {
373 signal(SIGTERM, SIG_DFL);
374 signal(SIGHUP, SIG_IGN);
375 if (dowait) {
376 syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
377 closelog();
378 sleep(30);
379 }
380 execit(p->comn, p->line);
381 exit(0);
382 }
383 p->pid = pid;
384}
385
386/*
387 * Remove utmp entry.
388 */
389rmut(p)
390 register struct tab *p;
391{
392 register f;
393 int found = 0;
394
395 f = open(utmp, O_RDWR);
396 if (f >= 0) {
397 while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
398 if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
399 continue;
400 lseek(f, -(long)sizeof(wtmp), 1);
401 SCPYN(wtmp.ut_name, "");
402 SCPYN(wtmp.ut_host, "");
403 time(&wtmp.ut_time);
404 write(f, (char *)&wtmp, sizeof(wtmp));
405 found++;
406 }
407 close(f);
408 }
409 if (found) {
410 f = open(wtmpf, O_WRONLY|O_APPEND);
411 if (f >= 0) {
412 SCPYN(wtmp.ut_line, p->line);
413 SCPYN(wtmp.ut_name, "");
414 SCPYN(wtmp.ut_host, "");
415 time(&wtmp.ut_time);
416 write(f, (char *)&wtmp, sizeof(wtmp));
417 close(f);
418 }
419 /*
420 * After a proper login force reset
421 * of error detection code in dfork.
422 */
423 p->gettytime = 0;
424 }
425}
426
427reset()
428{
429
430 longjmp(sjbuf, 1);
431}
432
433jmp_buf idlebuf;
434
435idlehup()
436{
437
438 longjmp(idlebuf, 1);
439}
440
441idle()
442{
443 register struct tab *p;
444 register pid;
445
446 signal(SIGHUP, idlehup);
447 for (EVER) {
448 if (setjmp(idlebuf))
449 return;
450 pid = wait((int *) 0);
451 if (pid == -1) {
452 sigpause(0);
453 continue;
454 }
455 for (ALL) {
456 /* if window system dies, mark it for restart */
457 if (p->wpid == pid)
458 p->wpid = -1;
459 if (p->pid == pid) {
460 rmut(p);
461 p->pid = -1;
462 }
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 }
528 }
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 */
540}