xref: /original-bsd/sbin/init/init.c (revision f0fd5f8a)
1 static	char *sccsid = "@(#)init.c	4.9 (Berkeley) 12/07/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 	extern char *sys_errlist[];
349 
350 	time(&t);
351 	p->gettycnt++;
352 	if ((t - p->gettytime) >= 60) {
353 		p->gettytime = t;
354 		p->gettycnt = 1;
355 	} else {
356 		if (p->gettycnt >= 5) {
357 			dowait = 1;
358 			p->gettytime = t;
359 			p->gettycnt = 1;
360 		}
361 	}
362 	pid = fork();
363 	if(pid == 0) {
364 		int oerrno, f;
365 		extern int errno;
366 
367 		signal(SIGTERM, SIG_DFL);
368 		signal(SIGHUP, SIG_IGN);
369 		strcpy(tty, dev);
370 		strncat(tty, p->line, LINSIZ);
371 		if (dowait) {
372 			f = open("/dev/console", 1);
373 			write(f, "init: ", 6);
374 			write(f, tty, strlen(tty));
375 			write(f, ": getty failing, sleeping\n\r", 27);
376 			close(f);
377 			sleep(30);
378 			if ((f = open("/dev/tty", 2)) >= 0) {
379 				ioctl(f, TIOCNOTTY, 0);
380 				close(f);
381 			}
382 		}
383 		chown(tty, 0, 0);
384 		chmod(tty, 0622);
385 		if (open(tty, 2) < 0) {
386 			int repcnt = 0;
387 			do {
388 				oerrno = errno;
389 				if (repcnt % 10 == 0) {
390 					f = open("/dev/console", 1);
391 					write(f, "init: ", 6);
392 					write(f, tty, strlen(tty));
393 					write(f, ": ", 2);
394 					write(f, sys_errlist[oerrno],
395 						strlen(sys_errlist[oerrno]));
396 					write(f, "\n", 1);
397 					close(f);
398 					if ((f = open("/dev/tty", 2)) >= 0) {
399 						ioctl(f, TIOCNOTTY, 0);
400 						close(f);
401 					}
402 				}
403 				repcnt++;
404 				sleep(60);
405 			} while (open(tty, 2) < 0);
406 			exit(0);	/* have wrong control tty, start over */
407 		}
408 		vhangup();
409 		signal(SIGHUP, SIG_DFL);
410 		open(tty, 2);
411 		close(0);
412 		dup(1);
413 		dup(0);
414 		tty[0] = p->comn;
415 		tty[1] = 0;
416 		execl(getty, minus, tty, (char *)0);
417 		exit(0);
418 	}
419 	p->pid = pid;
420 }
421 
422 rmut(p)
423 register struct tab *p;
424 {
425 	register f;
426 	int found = 0;
427 
428 	f = open(utmp, 2);
429 	if(f >= 0) {
430 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
431 			if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
432 				continue;
433 			lseek(f, -(long)sizeof(wtmp), 1);
434 			SCPYN(wtmp.ut_name, "");
435 			time(&wtmp.ut_time);
436 			write(f, (char *)&wtmp, sizeof(wtmp));
437 			found++;
438 		}
439 		close(f);
440 	}
441 	if (found) {
442 		f = open(wtmpf, 1);
443 		if (f >= 0) {
444 			SCPYN(wtmp.ut_line, p->line);
445 			SCPYN(wtmp.ut_name, "");
446 			time(&wtmp.ut_time);
447 			lseek(f, (long)0, 2);
448 			write(f, (char *)&wtmp, sizeof(wtmp));
449 			close(f);
450 		}
451 	}
452 }
453 
454 reset()
455 {
456 	longjmp(sjbuf, 1);
457 }
458 
459 idle()
460 {
461 	register struct tab *p;
462 	register pid;
463 
464 	signal(SIGTSTP, idle);
465 	for (;;) {
466 		pid = wait((int *) 0);
467 		if (mergflag)
468 			return;
469 		if (pid == -1)
470 			pause();
471 		else {
472 			for (ALL)
473 				if (p->pid == pid) {
474 					rmut(p);
475 					p->pid = -1;
476 				}
477 		}
478 	}
479 }
480