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