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