2.9BSD/usr/src/cmd/init.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	init.c
 */
#include "whoami.h"
#include <signal.h>
#include <sys/types.h>
#include <utmp.h>
#include <setjmp.h>
#ifdef	UCB_AUTOBOOT
#include <sys/reboot.h>
#endif
#include <errno.h>
#include <sys/autoconfig.h>

#define	VHANGUP			/* undefine if you don't have vhangup */
#define	CONFIGOPTS	"-vc"

#define	LINSIZ	sizeof(wtmp.ut_line)
#define	TABSIZ	100
#define	ALL	p = &itab[0]; p < &itab[TABSIZ]; p++
#define	EVER	;;
#define SCPYN(a, b)	strncpy(a, b, sizeof(a))
#define SCMPN(a, b)	strncmp(a, b, sizeof(a))

char	shell[]	= "/bin/sh";
char	getty[]	 = "/etc/getty";
char	minus[]	= "-";
char	plus[] = "+";		/* this tells getty we are in sp. sess. */
char	runc[]	= "/etc/rc";
char	ifile[]	= "/etc/ttys";
char	utmp[]	= "/etc/utmp";
char	wtmpf[]	= "/usr/adm/wtmp";
char	ctty[]	= "/dev/console";
char	dev[]	= "/dev/";
char	config[]= "/etc/autoconfig";

struct utmp wtmp;
struct
{
	char	line[LINSIZ];
	char	comn;
	char	flag;
} line;
struct	tab
{
	char	line[LINSIZ];
	char	comn;
	char	xflag;
	int	pid;
} itab[TABSIZ];

extern	errno;

int	fi;
int	mergflag;
int	multiuser;
/*
 *  Modes: bits in first char of /etc/ttys line
 */
#define	NORMAL	1		/* anyone can login */
#define	SP_SESS	2		/* only root can login */
int	mode = NORMAL;

char	tty[20];
jmp_buf	sjbuf, shutpass;
time_t	time0;

time_t	time();
int	reset();
int	idle(), sp_ss(), setmerge();
char	*strcpy(), *strcat();
long	lseek();

#ifdef	UCB_AUTOBOOT
main(ac, av)
char	**av;
#else
main ()
#endif
{
	int howto, oldhowto;

	time0 = time((time_t *) 0);
#ifdef	UCB_AUTOBOOT
	signal(SIGQUIT, idle);

	if (ac > 1) {
		howto = * ((int *) av[1]);
		* ((int *) av[1]) = 0;	/* don't confuse ps with binary args */
	 } else
		howto = RB_SINGLE;
	if (autoconfig() == 0)
		howto = RB_SINGLE;
#else
	autoconfig();
#endif
	setjmp(sjbuf);
	signal(SIGTERM, reset);
	signal(SIGINT, sp_ss);
	signal(SIGHUP, setmerge);
	for(EVER) {
		shutdown();
#ifdef	UCB_AUTOBOOT
		oldhowto = howto;
		howto = RB_SINGLE;
		if (oldhowto & RB_SINGLE)
			single();
		if (runcom(oldhowto) == 0) 
			mode = SP_SESS;
#else
		single();
		runcom();
#endif
		merge();
		multiple();
	}
}

int	shutreset();

shutdown()
{
	register i, f;
	register struct tab *p;

	multiuser = 0;
	for(ALL) {
		term(p);
		p->line[0] = 0;
	}
	close(creat(utmp, 0644));
	signal(SIGALRM, shutreset);
	if (setjmp(shutpass) == 0) {
		alarm(30);
		for(i=0; i<5; i++)
			kill(-1, SIGKILL);
		while(wait((int *)0) != -1)
			;
		alarm(0);
	}
	acct(0);
	signal(SIGALRM, SIG_DFL);
	for(i=0; i<10; i++)
		close(i);
	f = open(wtmpf, 1);
	if (f >= 0) {
		lseek(f, 0L, 2);
		SCPYN(wtmp.ut_line, "~");
		SCPYN(wtmp.ut_name, "shutdown");
		time(&wtmp.ut_time);
		write(f, (char *)&wtmp, sizeof(wtmp));
		close(f);
	}
}

shutreset()
{
	cmesg("WARNING: Something is hung (won't die); ps axl advised\n", 0, 0);
	longjmp(shutpass, 1);
}

single()
{
	register pid;
	register xpid;
	extern	errno;

	multiuser = 0;
   do {
	pid = fork();
	if(pid == 0) {
/*
		alarm(300);
*/
		signal(SIGTERM, SIG_DFL);
		signal(SIGHUP, SIG_DFL);
		signal(SIGALRM, SIG_DFL);
		open(ctty, 2);
		dup(0);
		dup(0);
		execl(shell, minus, (char *)0);
		cmesg("Init: can't exec ", shell, "\r\n");
		exit(0);
	}
	while((xpid = wait((int *)0)) != pid)
		if (xpid == -1 && errno == ECHILD)
			break;
   } while (xpid == -1);
}

#ifdef	UCB_AUTOBOOT
runcom(howto)
int howto;
#else
runcom()
#endif
{
	register pid, f;
	int status;
	char *arg1, *arg2;

	pid = fork();
	if(pid == 0) {
		open("/", 0);
		dup(0);
		dup(0);
#ifdef	UCB_AUTOBOOT
		if ((howto & RB_SINGLE) || (howto & RB_NOFSCK))
			arg1 = "fastboot";
		else
			arg1 = "autoboot";
		if (howto & RB_POWRFAIL)
			arg2 = "powerfail";
		else
			arg2 = (char *)0;
		execl(shell, shell, runc, arg1, arg2, (char *)0);
		exit(1);
#else
		execl(shell, shell, runc, (char *)0);
		exit(1);
#endif
	}
	while(wait(&status) != pid)
		;
#ifdef	UCB_AUTOBOOT
	if(status)
		return(0);
#endif
	f = open(wtmpf, 1);
	if (f >= 0) {
		lseek(f, 0L, 2);
		SCPYN(wtmp.ut_line, "~");
		SCPYN(wtmp.ut_name, "reboot");
		if (time0) {
			wtmp.ut_time = time0;
			time0 = 0;
		} else
			time(&wtmp.ut_time);
		write(f, (char *)&wtmp, sizeof(wtmp));
		close(f);
	}
	return(1);
}

setmerge()
{
	signal(SIGHUP, SIG_IGN);
	mergflag = 1;
}

multiple()
{
	register struct tab *p;
	register pid;

loop:
	multiuser = 1;
	mergflag = 0;
	signal(SIGHUP, setmerge);
	for(EVER) {
		pid = wait((int *)0);
		if(mergflag) {
			merge();
			goto loop;
		}
		if(pid == -1) {
			if (errno == ECHILD) {
				cmesg("Init: ", "no children left", "\r\n");
				return;
			}
			goto loop;
		}
		for(ALL)
			if(p->pid == pid || p->pid == -1) {
#ifdef	UCB_SUBMIT
				if (p->pid != -1)
					killbkg(p->pid, SIGKILL);
#endif
				rmut(p);
				dfork(p);
			}
	}
}

term(p)
register struct tab *p;
{

	if(p->pid != 0 && p->pid != -1) {
		rmut(p);
		kill(p->pid, SIGKILL);
#ifdef	UCB_SUBMIT
		killbkg(p->pid, SIGKILL);
#endif
	}
	p->pid = 0;
}

rline()
{
	register c, i;

loop:
	c = get();
	if(c < 0)
		return(0);
	if(c == 0)
		goto loop;
	line.flag = c;
	c = get();
	if(c <= 0)
		goto loop;
	line.comn = c;
	SCPYN(line.line, "");
	for (i=0; i<LINSIZ; i++) {
		c = get();
		/*
		 * If a blank, newline, or end of file, or tab,
		 * cease accumulating line name
		 */
		if(c <= 0 || c == ' ' || c == '\t')
			break;
		line.line[i] = c;
	}
	while(c > 0)
		c = get();
	if(line.line[0] == 0)
		goto loop;
	if(line.flag == '0')
		goto loop;
	strcpy(tty, dev);
	strncat(tty, line.line, LINSIZ);
	if(access(tty, 06) < 0)
		goto loop;
	return(1);
}

get()
{
	char b;

	if(read(fi, &b, 1) != 1)
		return(-1);
	if(b == '\n')
		return(0);
	return(b);
}

#define	FOUND	1
#define	CHANGE	2

merge()
{
	register struct tab *p;

	fi = open(ifile, 0);
	if(fi < 0)
		return;
	for(ALL)
		p->xflag = 0;
	while(rline()) {
		if ((line.flag < '1') || (line.flag > '9'))
			continue;
		if (((line.flag-'0') & mode) == 0)
			continue;
		for(ALL) {
			if (SCMPN(p->line, line.line))
				continue;
			p->xflag |= FOUND;
			if(line.comn != p->comn) {
				p->xflag |= CHANGE;
				p->comn = line.comn;
			}
			goto contin1;
		}
		for(ALL) {
			if(p->line[0] != 0)
				continue;
			SCPYN(p->line, line.line);
			p->xflag |= FOUND|CHANGE;
			p->comn = line.comn;
			goto contin1;
		}
	contin1:
		;
	}
	close(fi);
	for(ALL) {
		if((p->xflag&FOUND) == 0) {
			term(p);
			p->line[0] = 0;
		}
		if((p->xflag&CHANGE) != 0) {
			term(p);
			dfork(p);
		}
#ifdef	UCB_AUTOBOOT
		/*
		 * If we are resuming after an idle (possibly a failed reboot)
		 * we need to restart the lines that shut down.
		 */
		if (p->pid == -1)
			dfork(p);
#endif
	}
}

dfork(p)
struct tab *p;
{
	register pid;

	pid = fork();
	if(pid == 0) {
		signal(SIGTERM, SIG_DFL);
		signal(SIGHUP, SIG_IGN);
		strcpy(tty, dev);
		strncat(tty, p->line, LINSIZ);
		chown(tty, 0, 0);
		chmod(tty, 0622);
		if (open(tty, 2) < 0) {
			int repcnt = 0;
			do {
				if (repcnt % 10 == 0)
					cmesg("init: ",tty,": cannot open\n\r");
				repcnt++;
				sleep(60);
			} while (open(tty, 2) < 0);
		}
#ifdef	VHANGUP
		vhangup();
#endif
		signal(SIGHUP, SIG_DFL);
		open(tty, 2);
		close(0);
		dup(1);
		dup(0);
		tty[0] = p->comn;
		tty[1] = 0;
		if(mode == SP_SESS)
			execl(getty, plus, tty, (char *)0);
		else
			execl(getty, minus, tty, (char *)0);
		exit(0);
	}
	p->pid = pid;
}

rmut(p)
register struct tab *p;
{
	register f;
	int found = 0;

	f = open(utmp, 2);
	if(f >= 0) {
		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
			if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
				continue;
			lseek(f, -(long)sizeof(wtmp), 1);
			SCPYN(wtmp.ut_name, "");
			time(&wtmp.ut_time);
			write(f, (char *)&wtmp, sizeof(wtmp));
			found++;
		}
		close(f);
	}
	if (found) {
		f = open(wtmpf, 1);
		if (f >= 0) {
			SCPYN(wtmp.ut_line, p->line);
			SCPYN(wtmp.ut_name, "");
			time(&wtmp.ut_time);
			lseek(f, (long)0, 2);
			write(f, (char *)&wtmp, sizeof(wtmp));
			close(f);
		}
	}
}

reset()
{
	longjmp(sjbuf, 1);
}

/*
 *  Toggle special-session mode.
 *  Do a shutdown() so that getty's are reissued in the new mode.
 */
sp_ss()
{
	signal(SIGINT, SIG_IGN);
	mergflag++;
	shutdown();
	if (mode == NORMAL) 
		mode = SP_SESS;
	else {
		/*
		 * Returning to normal operation.
		 * Run the rc file; either it hasn't been finished
		 * since we failed a filesystem check, or we shut down.
		 */
#ifdef	UCB_AUTOBOOT
		(void) runcom(RB_NOFSCK);
#else
		(void) runcom();
#endif
		mode = NORMAL;
	}
	signal(SIGINT, sp_ss);
}

#ifdef	UCB_AUTOBOOT
idle()
{
	register struct tab *p;
	register pid;

	signal(SIGQUIT,idle);
	for (;;) {
		pid = wait((int *) 0);
		if (mergflag) {
			if (!multiuser)
				reset();
			else
				return;
		}
		if (pid == -1)
			pause();
		else {
			for (ALL)
				if (p->pid == pid) {
					rmut(p);
					p->pid = -1;
				}
		}
	}
}
#endif

cmesg(s1, s2, s3)
char *s1, *s2, *s3;
{
	register int pid;

	pid = fork();
	if (pid == 0) {
		int fd = open(ctty, 2);
		write(fd, s1, strlen(s1));
		if (s2)
			write(fd, s2, strlen(s2));
		if (s3)
			write(fd, s3, strlen(s3));
		close(fd);
		exit(0);
	}
	while (wait((int *)0) != pid)
		;
}

autoconfig()
{
	int pid, status;

	cmesg("\r\nCONFIGURE SYSTEM:\n", 0, 0);
	if ((pid = fork()) == 0) {
		open(ctty, 2);
		dup(0);
		dup(0);
		execl(config, "autoconfig", CONFIGOPTS, 0);
		printf("Couldn't exec %s\n", config);
		exit(AC_SETUP);
	}
	while (wait(&status) != pid)
		;
	if ((status & 0377) == 0)
		status >>= 8;
	else
		status = AC_SINGLE;
	switch (status) {
		case AC_SETUP:
			cmesg("Configuration setup error\n", 0, 0);
			return 0;
		case AC_SINGLE:
			cmesg("SERIOUS CONFIGURATION ERROR\n", 0, 0);
			return 0;
		case AC_OK:
			return 1;
		default:
			cmesg("Unrecognized return from configure\n", 0, 0);
			return 0;
	}
}