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