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