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