SysIII/usr/src/cmd/init.c

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

#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <utmp.h>

#define TTYS	"/etc/inittab"
#define RC	"/etc/rc"
#define SH	"/bin/sh"
#define DIAG	"/dev/console"
#define ERRACT	"/bin/sh < /dev/console > /dev/console 2>&1"

#define INIT 1
#define NOPROC	0
#define NOCMD	-1
#define NOIND	-1
#define CHILD	0
#define FORKERR	-1

#define ASIZE	256
#define TABSIZ	100
#define RCLIM	300

#define STx	1
#define ST1	4
#define ST2	5
#define ST3	6
#define ST4	7
#define ST5	8
#define ST6	10
#define ST7	11
#define ST8	12
#define ST9	13

struct initbl {
	int in_proc;
	char in_id[2];
	int in_cmd;
};
struct initbl itab[TABSIZ];

char state = '1';
char a0[] = "INIT     ";
char lstate = '0';
int statecnt [10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int ST [10] = {0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST8, ST9};
int chst(), rckill();
int sigs [4] = {SIGINT, SIGQUIT, SIGALRM, SIGTERM};
int rdstate = 1;
int xstate = 0;
int idlim = 0;
int rcid;
unsigned csize = ASIZE;
char *start, *malloc(), *realloc();
unsigned nextcmd = 0;	/* offset from start */

main(argc, argv)
int argc;
char **argv;
{
	int i;

	if(argc > 1) {
		if((*argv[1] > '9') || (*argv[1] < '1')) {
			fputs("init: invalid state\n", stderr);
			exit(2);
		}

		if(kill(INIT, ST[*argv[1]-'0'])) {
			fputs("init: permission denied\n", stderr);
			exit(2);
		}
		exit(0);
	}

	if(getpid() != INIT) {
		fputs("usage: init state\n", stderr);
		exit(2);
	}

	signal(STx, chst);
	signal(SIGPWR, chst);
	ignsigs();

	for(i=0;i<=10;i++)
		close(i);

	while ((start=malloc(csize)) == NULL) err(2, "no memory, malloc failed", "");

	for(;;) {
		a0[5] = state;
		strcpy(*argv, a0);
		xstate = 0;
		while(rdstate) {
			rdstate = 0;
			readttys();
			statecnt[state-'0']++;
			runrc();
			xstate = 0;
		}

		invttys();
		waitttys();
	}
}

fit(str)
char *str;
{
/* returns offset from start where string stored. */
	int len, rstr;
	char *ostart;

	len = strlen(str) + 1;
	if((len+nextcmd) > csize) {
		csize += ASIZE;
		ostart = start;
		if ((start=realloc(start, csize)) == NULL) {
			start = ostart;
			csize -= ASIZE;
			err(0, "no memory, malloc failed", "");
			return(NOCMD);
		}
	}

	strcpy(start+nextcmd, str);
	rstr = nextcmd;
	nextcmd += len;
	return(rstr);
}

invttys()
{
	int i;

	for(i=0;i<idlim;i++)
		if((itab[i].in_proc == NOPROC) && (itab[i].in_cmd != NOCMD)) {
			if(*((itab[i].in_cmd)+start) == ':') {

				itab[i].in_proc = iexec(start+(itab[i].in_cmd)+2);
				itab[i].in_cmd = NOCMD;
			}
			else itab[i].in_proc = iexec(start+(itab[i].in_cmd));
		}
}

iexec(s)
char *s;
{
	int pid, i;
	char rs[256];

	strcpy(rs, "exec ");
	strcat(rs, s);
	switch(pid=fork()) {
	case FORKERR:
		err(0, "fork failed for:", s);
		return(NOPROC);
	case CHILD:
		for(i=0;i<=10;i++)
			close(i);
		open("/", 0);
		dup(0);
		dup(0);
		rsetsigs();
		setpgrp();
		execl(SH, "sh", "-c", rs, 0);
		err(1, "exec failed for:", s);
	default:
		return(pid);
	}
}

waitttys()
{
	int status;
	int pnum;
	int deadind;

	while(((pnum=wait(&status))==-1) && (rdstate==0) && (xstate==0))
		err(2, "no processes running", "");

	deadind=lookproc(pnum);
	if(deadind!=NOIND)
		itab[deadind].in_proc=NOPROC;
	return(pnum);
}

runrc()
{
	char rcstring[100], iabuf[5];
	int i;
	char blank = ' ', eos = '\0';

	strcpy(rcstring, "exec ");
	strcat(rcstring, RC);
	i=strlen(rcstring);
	rcstring[i++] = blank;
	rcstring[i++] = state;
	if(xstate==1)
		rcstring[i++] = 'x';
	rcstring[i++] = blank;
	rcstring[i++] = eos;
	itoa(statecnt[state-'0']-1, iabuf);
	strcat(rcstring, iabuf);
	i = strlen(rcstring);
	rcstring[i++] = blank;
	rcstring[i++] = lstate;
	rcstring[i++] = eos;

	while((rcid=fork())==FORKERR) {
		err(0, "fork failed for: RC", "");
		sleep(2);
	}

	if(rcid==CHILD) {
		for(i=0;i<=10;i++)
			close(i);

		open("/", 0);
		dup(0);
		dup(0);

		rsetsigs();
		setpgrp();
		execl(SH, "RC", "-c", rcstring, 0);
		err(1, "exec failed for: RC", "");
	}

	setsigs();
	if(xstate==0) {
		signal(SIGALRM, rckill);
		alarm(RCLIM);
	}
	while((waitttys()!=rcid) && (rdstate==0));
	if(xstate==0) {
		alarm(0);
		signal(SIGALRM, SIG_IGN);
	}
}

readttys()
{
	FILE *tfile;
	char ocmd[258], icmd[256], iflags[5], *ifp;
	int itp, i, tset, istate, holdc;
	char *fp;
	char id[2];

	for(i=0;i<idlim;i++)
		itab[i].in_cmd = NOCMD;

	nextcmd=0;

	while((tfile = fopen(TTYS, "r"))==NULL)
		err(2, "inittab open failed", "");
	rdstate = 0;
	for(;;) {
		if((istate=getc(tfile))==EOF)
			break;
		else if(istate=='\n')
			continue;
		else if((istate != state) || (getc(tfile)!=':')) {
			while(((holdc=getc(tfile))!=EOF) && (holdc!='\n'))
				;
			if(holdc==EOF)
				break;
			else continue;
		}

		if((int)(id[0]=getc(tfile))==EOF)
			break;
		else if(id[0]=='\n')
			continue;
		if((int)(id[1]=getc(tfile))==EOF)
			break;
		else if(id[1]=='\n')
			continue;

		if(getc(tfile)!=':') {
			while(((holdc=getc(tfile))!=EOF) && (holdc!='\n'))
				;
			if(holdc==EOF)
				break;
			else continue;
		}

		ifp=iflags;
		while(((*ifp=getc(tfile))!=':') && ((int)*ifp!=EOF) && (*ifp!='\n'))
			ifp++;
		if((int)*ifp==EOF)
			break;
		else if(*ifp=='\n')
			continue;
		else *ifp = '\0';

		ifp=icmd;
		while(((int)(*ifp=getc(tfile))!=EOF) && (*ifp!='\n'))
			ifp++;
		*ifp = '\0';

		itp = lookid(id);
		if(strchr(iflags, 'o') || (*icmd == '\0'))
			;
		else if(strchr(iflags, 'c'))
			itab[itp].in_cmd = fit(icmd);
		else {
			ocmd[0] = ':';
			ocmd[1] = ' ';
			ocmd[2] = '\0';
			strcat(ocmd, icmd);
			itab[itp].in_cmd = fit(ocmd);
		}

		tset=0;
		for(fp=iflags;*fp;fp++) switch(*fp) {
		case 't':
			if((itab[itp].in_proc) > NOPROC) {
				/* killpgrp */
				kill(-(itab[itp].in_proc), 15);
				tset=1;
			}
			break;
		case 'k':
			if(itab[itp].in_proc > NOPROC) {
				/* killpgrp */
				if(tset) sleep(1);
				kill(-(itab[itp].in_proc), 9);
			}
			break;
		}
	}
	fclose(tfile);
}

lookproc(proc)
int proc;
{
	int i;

	for(i=0;i<idlim;i++)
		if(itab[i].in_proc==proc) return(i);
	return(NOIND);
}

lookid(id)
char id[2];
{
	int i;

	for(i=0;i<idlim;i++)
		if((itab[i].in_id[0]==id[0]) && (itab[i].in_id[1]==id[1])) return(i);

	itab[idlim].in_id[0]=id[0];
	itab[idlim].in_id[1]=id[1];
	itab[idlim].in_proc=NOPROC;
	itab[idlim].in_cmd = NOCMD;

	return(idlim++);
}

chst(sno)
{
	int i;

	ignsigs();
	if (sno == STx || sno == SIGPWR) {
		signal(STx, chst);
		signal(SIGPWR, chst);
		xstate = 1;
		runrc();
		return;
	}

	lstate = state;
	for(i=1;ST[i] != sno;i++) ;
	state = i + '0';
	rdstate = 1;
}

rckill()
{
	char itoabuf[6];

	itoa(RCLIM, itoabuf);
	err(0, "RC over time limit of:", itoabuf);
	kill(-rcid, 9);
	xstate = 1;
}

ignsigs()
{
	int i;

	for(i=0;i<=3;i++)
		signal(sigs[i], SIG_IGN);

	for(i=1;i<=9;i++)
		signal(ST[i], SIG_IGN);
}

setsigs()
{
	int i;

	for(i=0;i<=3;i++)
		signal(sigs[i], SIG_IGN);

	for(i=1;i<=9;i++)
		signal(ST[i], chst);
}

rsetsigs()
{
	int i;

	for(i=0;i<=3;i++)
		signal(sigs[i], SIG_DFL);

	for(i=1;i<=9;i++)
		signal(ST[i], SIG_DFL);
}

err(act, msg1, msg2)
int act;
char *msg1, *msg2;
{
	FILE *errfile;
	int i;

	if((errfile=fopen(DIAG, "a")) != NULL) {
		setbuf(errfile, (char *)NULL);
		fputs("init: ", errfile);
		fputs(msg1, errfile);
		fputs(msg2, errfile);
		putc('\n', errfile);
	}

	switch(act) {
	case 0:
		fclose(errfile);
		return;
	case 1:
		exit(2);
	case 2:
		if(errfile != NULL) {
			fputs("trying default shell\n", errfile);
			fputs(ERRACT, errfile);
			fputs("\n", errfile);
		}

		if((i=iexec(ERRACT))==NOPROC)
			err(1, "exec failed for: final default shell", "");
		rdstate = 0;
		setsigs();
		while((waitttys()!=i) && (rdstate==0))
			;
		if(rdstate && (errfile != NULL))
			fputs("WARNING: default shell not terminated\n", errfile);
		fclose(errfile);
		return;
	}
}

itoa(n, s)
char *s;
int n;
{
	int i=0, c, j, sign;

	if((sign=n) < 0)
		n = -n;

	do {
		s[i++] = n % 10 + '0';
	} while((n /= 10) > 0);

	if(sign < 0)
		s[i++] = '-';
	s[i] = '\0';

	for(i=0, j=strlen(s)-1;i<j;i++, j--) {
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}