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