[alt.sources] Init - SCO Xenix System V replacement

jfh@rpp386.Dallas.TX.US (John F. Haugh II) (03/22/89)

This is the beta test release of the init I've been munging on.
It is currently being used on this site with some results.  It
is not complete and does not contain a telinit.  You have to
send it various signals to get things to happen ...

So far it seems to work.

Caveats -
	- no telinit yet
	- still flaky as a pie crust
	- only tested on Xenix/386 2.2.1
	- syscon and systty aren't implemented yet

Debugging an init is EXTREMELY troublesome.  If you are unable
to reboot frequently and from a floppy, I would not suggest
getting involved just yet.  This init is easier to debug in a
production setting than the real McCoy as this version can be
restarted without rebooting the system.  Nice trick.

How to use this beasty -

Create your /etc/inittab just like normal.  You need to have
some experience with inittabs.  Here is mine as a starter:
--
id:S:initdefault:
rc:Ss2:wait:/etc/rc < /dev/console > /dev/console 2>&1
co:Ss:wait:/bin/su - root < /dev/console > /dev/console 2>&1
01:2:respawn:/etc/getty tty01 m	# Screen 1
02:2:respawn:/etc/getty tty02 m	# Screen 2
03:2:respawn:/etc/getty tty03 m	# Screen 3
d1:2:respawn:/etc/getty tty1A v	# Anchor Automation Modem
d2:2:respawn:/etc/getty tty2A v	# Everex Modem
--

Create a new /etc/rc file.  The old one is probably kinda
useless if you are running SCO Xenix.  It doesn't know about
being called in single user mode.

Save your old init someplace handy and make and install
this version.

Reboot.  You will now be in single user mode.

To change run levels, signal init with SIGUSR1 [ signal
16 ] and you will be prompted on the console for a new
run level.  Enter the new runlevel at the prompt.

To restart init, signal init with SIGUSR2 [ signal 17 ]
and init will kill all active processes and re-exec
itself.  This is very useful for replacing init without
rebooting.

To re-read the inittab, send init a signal 1, 2, or 3.

You might want to read the config.h file.  There are only
a few options at this stage of the game.

If you aren't completely frightened, or REALLY DESPARATELY
need a real init, complete with source code, unwrap this
sucker and get on with the show ...

WARNING - SCREWING WITH INIT CAN GET YOUR MACHINE REAL
UNUSABLE REAL FAST.  ALWAYS ALWAYS ALWAYS make plenty of
backups and sacrifice virgins to the computer gods before
screwing with this.  Don't say I didn't warn you.

THIS POSTING COPYRIGHT, 1989, JOHN F. HAUGH II
ALL RIGHTS RESERVED.

Use and redistribution in a USENET-like manner permitted,
all other uses prohibited.
--
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	error.c
#	getlevel.c
#	main.c
#	process.c
#	startup.c
#	inittab.c
#	spawn.c
#	config.h
#	inittab.h
#	patchlevel.h
# This archive created: Wed Mar 22 08:07:05 1989
# By:	John F. Haugh II (River Parishes Programming, Dallas TX)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
#	%Z%Init - System V compatible init
#
#	%W%	%U%	%G%
#
SHELL = /bin/sh

CFLAGS = -O -M3 -g

SRCS = error.c getlevel.c main.c process.c startup.c inittab.c spawn.c

HDRS = config.h inittab.h patchlevel.h

OBJS = error.o getlevel.o main.o process.o startup.o inittab.o spawn.o

FILES = Makefile $(SRCS) $(HDRS)

init: $(OBJS)
	cc -o init -g $(OBJS)

error.o: config.h

getlevel.o: inittab.h config.h

inittab.o: inittab.h config.h

main.o: inittab.h config.h

process.o: inittab.h config.h

spawn.o: inittab.h

startup.o: inittab.h config.h

shar:	$(FILES)
	shar $(FILES) > init.shar

clean:
	rm -f *.o core

clobber: clean
	rm -f init
SHAR_EOF
fi
if test -f 'error.c'
then
	echo shar: "will not over-write existing file 'error.c'"
else
cat << \SHAR_EOF > 'error.c'
#include <fcntl.h>
#include <stdio.h>
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)error.c	1.1	07:58:04	3/22/89";
#endif

extern	int	proc1;
extern	int	consolefd;

error (s)
char	*s;
{
	char	buf[BUFSIZ];
	
	sprintf (buf, "ERROR: %s\r\n", s);
#ifdef	DEBUG
	fputs (buf, stderr);
#else
	if (proc1) {
		if (fork () == 0) {
			proc1 = 0;
			consolefd = open (CONSOLE, O_RDWR|O_NDELAY);
			write (consolefd, buf, strlen (buf));
			_exit (0);
		}
	} else {
		write (consolefd, buf, strlen (buf));
		_exit (0);
	}
#endif
}

msg (s)
char	*s;
{
	char	buf[BUFSIZ];
	
	sprintf (buf, "%s\r\n", s);
#ifdef	DEBUG
	fputs (buf, stderr);
#else
	if (proc1) {
		if (fork () == 0) {
			proc1 = 0;
			consolefd = open (CONSOLE, O_RDWR|O_NDELAY);
			write (consolefd, buf, strlen (buf));
			_exit (0);
		}
	} else {
		write (consolefd, buf, strlen (buf));
		_exit (0);
	}
#endif
}
SHAR_EOF
fi
if test -f 'getlevel.c'
then
	echo shar: "will not over-write existing file 'getlevel.c'"
else
cat << \SHAR_EOF > 'getlevel.c'
#include <stdio.h>
#include <fcntl.h>
#include <termio.h>
#include <signal.h>
#include "inittab.h"
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)getlevel.c	1.1	07:58:04	3/22/89";
#endif

extern	int	proc1;
extern	int	consolefd;
extern	int	nproc;
extern	struct	inittab	*proc;

/*
 * getlevel - return new run level
 */

int	getlevel ()
{
	char	buf[16];
	int	fd;
	int	status;
	int	pid;
	int	child;
	int	i;
	struct	termio	termio;

	for (i = 0;i < nproc;i++) {
		if (proc[i].ini_pid > 1) {
			kill (- proc[i].ini_pid, SIGKILL);
			waitfor (&proc[i]);
		}
	}
	kill (0, SIGKILL);
	switch (child = fork ()) {
		default:	/* still proc1 ... */
			while ((pid = wait (&status)) != child
					&& pid != -1)
				;
			if ((status & 0377) != 0) {
				error ("Can't get run-level, using S");
				return ('S');
			}
			break;
		case -1:	/* couldn't fork */
			error ("Can't get run-level, using S");
			return ('S');
		case 0:		/* child process */
			proc1 = 0;
			if ((fd = open (CONSOLE, O_RDWR|O_NDELAY)) < 0)
				_exit (0); /* assume 'S' ... */

#ifndef	DEBUG
			ioctl (fd, TCGETA, &termio);
			termio.c_iflag = (ISTRIP|ICRNL|IXON);
			termio.c_oflag = (OPOST|ONLCR);
			termio.c_cflag &= CBAUD;
			termio.c_cflag |= (CREAD|HUPCL);
			termio.c_lflag = (ISIG|ICANON|ECHO|ECHOE|ECHOK);
			ioctl (fd, TCSETA, &termio);
#endif
			fcntl (fd, F_SETFL,
				fcntl (fd, F_GETFL, 0) & ~O_NDELAY);
			consolefd = fd;
			do {
				write (fd, "Enter run-level [Ss0123456]: ", 29);
				i = read (fd, buf, sizeof buf);
				if (i >= 0)
					buf[i] = '\0';
			} while (! (buf[0] == 's' || buf[0] == 'S'
				|| (buf[0] >= '0' && buf[0] <= '6')));

			if (buf[0] == 'S' || buf[0] == '0')
				_exit (0);
			else if (buf[0] == 's')
				_exit (1);
			else
				_exit (buf[0] - '0' + 1);
	}
	status = (status >> 8) & 07;
	return ("Ss123456"[status]);
}
SHAR_EOF
fi
if test -f 'main.c'
then
	echo shar: "will not over-write existing file 'main.c'"
else
cat << \SHAR_EOF > 'main.c'
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <utmp.h>
#include <string.h>
#include "config.h"
#include "inittab.h"

#ifndef lint
static	char	_sccsid[] = "@(#)main.c	1.1	07:58:07	3/22/89";
#endif

char	intrflag;
int	proc1;
int	runlevel;
int	prevlevel;
int	runcnt[8];
int	consolefd;
int	wtmpfd;
int	nproc;

struct	inittab	*proc;

reinit ()
{
	int	i;

	msg ("Reloading INIT");
#ifndef	DEBUG
	kill (-1, SIGKILL);
#endif
#ifdef	DEBUG
	execl ("./init", "init", "proc1", (char *) 0);
#else
	execl ("/etc/init", "/etc/init", (char *) 0);
#endif
}

main (argc, argv)
int	argc;
char	**argv;
{
	int	newlevel;
	char	buf[BUFSIZ];

#ifdef	DEBUG
	if (proc1 = (argc > 1 && strcmp (argv[1], "proc1") == 0)) {
		argv[1] = argv[0];
		argc--;
		argv++;
	}
#else
 	proc1 = getpid () == 1;
#endif
	if (proc1)
		startup ();

	while (1) {
		process (runlevel);

		newlevel = getlevel ();

		if (newlevel != runlevel)
			sprintf (buf, "INIT: New run-level: %c", newlevel);
		else
			sprintf (buf, "INIT: Run-level: %c", newlevel);

		msg (buf);
		runlevel = newlevel;
	}
}
SHAR_EOF
fi
if test -f 'process.c'
then
	echo shar: "will not over-write existing file 'process.c'"
else
cat << \SHAR_EOF > 'process.c'
#include <signal.h>
#include <sys/types.h>
#include <utmp.h>
#include <fcntl.h>
#include "config.h"
#include "inittab.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)process.c	1.1	07:58:08	3/22/89";
#endif

extern	char	intrflag;
extern	int	nproc;
extern	int	prevlevel;
extern	int	runlevel;
extern	int	runcnt[];
extern	int	wtmpfd;
extern	struct	inittab	*proc;

/* 
 * process - perform entries specified in inittab
 *
 *	perform respawn, wait, and once commands.
 */

process ()
{
	int	i;
	int	utmpfd;
	int	count;
	struct	inittab	*ip;
	struct	utmp	utmp;
	struct	utmp	utent;

	if (runlevel == 'S')
		i = runcnt[0]++;
	else if (runlevel == 's')
		i = runcnt[1]++;
	else
		i = runcnt[runlevel - '0' + 1]++;

#ifdef	DEBUG
	utmpfd = -1;
#else
	utmpfd = open ("/etc/utmp", O_RDWR|O_CREAT, 0644);
#endif
	memset ((char *) &utmp, 0, sizeof utmp);
	sprintf (utmp.ut_line, RUNLVL_MSG, runlevel);
	utmp.ut_type = RUN_LVL;
	utmp.ut_pid = i;
	utmp.ut_exit.e_termination = runlevel;
	utmp.ut_exit.e_exit = prevlevel;
	utmp.ut_time = time ((time_t *) 0);

	prevlevel = runlevel;
	intrflag = 0;

	if (utmpfd >= 0) {
		while (read (utmpfd, &utent, sizeof utent) == sizeof utent)
			if (utent.ut_type == RUN_LVL)
				break;

		if (utent.ut_type == RUN_LVL)
			lseek (utmpfd, (off_t) - sizeof utent, 1);

		write (utmpfd, &utmp, sizeof utmp);
		close (utmpfd);
		utmpfd = -1;
	}
	if (wtmpfd >= 0)
		write (wtmpfd, &utmp, sizeof utmp);
again:
	inittab (runlevel);
#ifdef	DEBUG
	prtab ();
#endif
	for (count = 0, ip = proc;ip != &proc[nproc];ip++) {
		if (ip->ini_pid && kill (ip->ini_pid, 0) != 0)
			waitfor (ip);

		if (! (ip->ini_pid && kill (ip->ini_pid, 0) == 0)) {
			switch (ip->ini_action) {
				case INIT_RESPAWN:
					spawn (ip);
					count++;
					break;
				case INIT_WAIT:
					if (intrflag == 0)
						spawn (ip);
					count++;
					break;
				case INIT_ONCE:
					if (ip->ini_count == 0)
						spawn (ip);
					count++;
					break;
			}
		}
	}
	intrflag = 0;
	if (count)
		waitfor ((struct inittab *) 0);

	if (intrflag && intrflag != SIGUSR1)
		goto again;
}
SHAR_EOF
fi
if test -f 'startup.c'
then
	echo shar: "will not over-write existing file 'startup.c'"
else
cat << \SHAR_EOF > 'startup.c'
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <utmp.h>
#include "config.h"
#include "inittab.h"

extern	void	reread ();
extern	void	reinit ();
extern	char	intrflag;
extern	int	runlevel;
extern	int	prevlevel;
extern	int	nproc;
extern	int	wtmpfd;
extern	struct	inittab	*proc;

#ifndef	lint
static	char	_sccsid[] = "@(#)startup.c	1.1	07:58:09	3/22/89";
#endif

/*
 * startup - set up the initial state
 */

void	startup ()
{
	int	i;
	int	fd;
	int	utmpfd;
	struct	utmp	utent;
	struct	utmp	utmp;

	wtmpfd = open ("/etc/wtmp", O_RDWR|O_APPEND|O_CREAT, 0644);
#ifdef	DEBUG
	utmpfd = -1;
#else
	utmpfd = open ("/etc/utmp", O_RDWR|O_CREAT|O_TRUNC, 0644);
#endif

	memset (utmp, sizeof utmp, 0);
	strcpy (utmp.ut_line, BOOT_MSG);
	utmp.ut_type = BOOT_TIME;
	utmp.ut_time = time ((time_t *) 0);

	if (utmpfd >= 0) {
		while (read (utmpfd, &utent, sizeof utent) == sizeof utent)
			if (utent.ut_type == BOOT_TIME)
				break;

		if (utent.ut_type == BOOT_TIME)
			lseek (utmpfd, (off_t) - sizeof utent, 1);

		write (utmpfd, &utmp, sizeof utmp);
	}
	if (wtmpfd >= 0)
		write (wtmpfd, &utmp, sizeof utmp);
#ifndef	DEBUG
	for (i = 1;i < NSIG;i++)
		signal (i, SIG_IGN);
#endif
	signal (SIGHUP, reread);
	signal (SIGINT, reread);
	signal (SIGQUIT, reread);
	signal (SIGUSR1, reread);
	signal (SIGUSR2, reinit);
	signal (SIGCLD, SIG_DFL);

	inittab (-1);
#ifdef	DEBUG
	printf ("INIT: BOOT\n");
	prtab ();
#endif
	/*
	 * certain entries must be executed first.  initdefault is
	 * the first one of them.  if there is no initdefault entry,
	 * we assume 'S' for the initial run level.
	 */

	for (i = 0;i < nproc && ! runlevel;i++) /* scan for initdefault */
		if (proc[i].ini_action == INIT_INITDEFAULT)
			runlevel = proc[i].ini_levels[0];

	if (! runlevel)
		runlevel = 'S';

	prevlevel = runlevel;
	memset (utmp, sizeof utmp, 0);
	sprintf (utmp.ut_line, RUNLVL_MSG, runlevel);
	utmp.ut_type = RUN_LVL;
	utmp.ut_pid = 0;
	utmp.ut_exit.e_termination = utmp.ut_exit.e_exit = runlevel;
	utmp.ut_time = time ((time_t *) 0);

	if (utmpfd >= 0) {
		while (read (utmpfd, &utent, sizeof utent) == sizeof utent)
			if (utent.ut_type == RUN_LVL)
				break;

		if (utent.ut_type == RUN_LVL)
			lseek (utmpfd, (off_t) - sizeof utent, 1);

		write (utmpfd, &utmp, sizeof utmp);
	}
	if (wtmpfd >= 0)
		write (wtmpfd, &utmp, sizeof utmp);

	/*
	 * next we must exec all `sysinit' commands ...
	 */

	for (i = 0;i < nproc;i++)	/* scan for sysinit */
		if (proc[i].ini_action == INIT_SYSINIT)
			spawn (&proc[i]);

	/*
	 * now we execute the `boot time only' commands ...
	 */

	for (i = 0;i < nproc;i++)
		if (proc[i].ini_action == INIT_BOOT
				|| proc[i].ini_action == INIT_BOOTWAIT)
			spawn (&proc[i]);

	close (utmpfd);
}
SHAR_EOF
fi
if test -f 'inittab.c'
then
	echo shar: "will not over-write existing file 'inittab.c'"
else
cat << \SHAR_EOF > 'inittab.c'
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "inittab.h"
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)inittab.c	1.1	07:58:06	3/22/89";
#endif

char	*actions[] = {
	"respawn",
	"wait",
	"once",
	"boot",
	"bootwait",
	"powerfail",
	"powerwait",
	"off",
	"ondemand",
	"initdefault",
	"sysinit"
};

struct	inittab	initdefault = {
	"default",
	"Ss123456",
	INIT_ONCE,
	"/etc/sulogin",
	0
};

extern	struct	inittab	*proc;
extern	int	nproc;
extern	char	intrflag;
extern	char	*malloc ();
extern	char	*realloc ();

struct	inittab	*getinit (fp, entry)
FILE	*fp;
struct	inittab	*entry;
{
	char	*cp;
	char	buf[BUFSIZ];
	char	id[16];
	char	levels[16];
	char	actions[16];
	char	command[BUFSIZ];

	while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
		if (buf[0] == '#')
			continue;

		if (cp = strtok (buf, ":"))
			strcpy (id, cp);
		else
			continue;

		if (cp = strtok ((char *) 0, ":"))
			strcpy (levels, cp);
		else
			continue;

		if (cp = strtok ((char *) 0, ":"))
			strcpy (actions, cp);
		else
			continue;

		if (cp = strtok ((char *) 0, ":"))
			strcpy (command, cp);
		else
			continue;

		if (cp = strchr (command, '\n'))
			*cp = '\0';

		if (strcmp (actions, "respawn") == 0)
			entry->ini_action = INIT_RESPAWN;
		else if (strcmp (actions, "wait") == 0)
			entry->ini_action = INIT_WAIT;
		else if (strcmp (actions, "once") == 0)
			entry->ini_action = INIT_ONCE;
		else if (strcmp (actions, "boot") == 0)
			entry->ini_action = INIT_BOOT;
		else if (strcmp (actions, "bootwait") == 0)
			entry->ini_action = INIT_BOOTWAIT;
		else if (strcmp (actions, "off") == 0)
			entry->ini_action = INIT_OFF;
		else if (strcmp (actions, "ondemand") == 0)
			entry->ini_action = INIT_ONDEMAND;
		else if (strcmp (actions, "initdefault") == 0)
			entry->ini_action = INIT_INITDEFAULT;
		else if (strcmp (actions, "sysinit") == 0)
			entry->ini_action = INIT_SYSINIT;
		else
			continue;

		entry->ini_id = strdup (id);
		entry->ini_levels = strdup (levels);
		entry->ini_command = strdup (command);

		return (entry);
	}
	return ((struct inittab *) 0);
}

freeinit (entry)
struct	inittab	*entry;
{
	free (entry->ini_id);
	free (entry->ini_levels);
	free (entry->ini_command);
}

struct	inittab	*findinit (id, table, entries)
char	*id;
struct	inittab	*table;
int	entries;
{
	while (--entries >= 0) {
		if (strcmp (id, table->ini_id) == 0)
			return (table);
		else
			table++;
	}
	return ((struct inittab *) 0);
}

/*
 * inittab - read the inittab
 */

inittab (runlevel)
int	runlevel;
{
	FILE	*fp;
	int	i, j;
	struct	inittab	it;
	struct	inittab	*ip;
	struct	inittab	*newproc;
	int	newprocs;
	int	kills;

	if ((fp = fopen (INITTAB, "r")) == (FILE *) 0) {
		nproc = 1;
		proc = (struct inittab *) malloc (sizeof it);
		proc[0] = initdefault;
		return;
	}
	newprocs = 0;

	if (runlevel != -1) {
		for (kills = i = 0;i < nproc;i++) {
			if (proc[i].ini_pid == 0)
				continue;

			if (strchr (proc[i].ini_levels, runlevel))
				continue;

			kill (proc[i].ini_pid, SIGTERM);
			kills++;
		}
		if (kills)
			sleep (10);

		for (i = 0;i < nproc;i++) {
			if (proc[i].ini_pid == 0)
				continue;

			if (strchr (proc[i].ini_levels, runlevel))
				continue;

			kill (proc[i].ini_pid, SIGKILL);
			waitfor (&proc[i]);
		}
	}
	while (getinit (fp, &it)) {
		if (runlevel != -1
			&& (it.ini_action == INIT_BOOT
				|| it.ini_action == INIT_BOOTWAIT
				|| it.ini_action == INIT_INITDEFAULT
				|| it.ini_action == INIT_SYSINIT
				|| ! strchr (it.ini_levels, runlevel))) {
			freeinit (&it);
			continue;
		}
		if (newprocs == 0)
			newproc = (struct inittab *) malloc (sizeof it);
		else
			newproc = (struct inittab *) realloc (newproc, sizeof it * (newprocs + 1));

		newproc[newprocs++] = it;
	}
	fclose (fp);

	for (kills = i = 0;i < newprocs;i++) {
		if (ip = findinit (newproc[i].ini_id, proc, nproc)) {
			newproc[i].ini_pid = ip->ini_pid;
			newproc[i].ini_count = ip->ini_count;
			newproc[i].ini_status = ip->ini_status;
			if (newproc[i].ini_action == ip->ini_action
				&& strcmp (newproc[i].ini_levels, ip->ini_levels) == 0
				&& strcmp (newproc[i].ini_command, ip->ini_command) == 0)
				continue;
		} else {
			newproc[i].ini_pid = 0;
			newproc[i].ini_count = 0;
			newproc[i].ini_status = 0;
		}
		if (newproc[i].ini_pid == 0)
			continue;

		if (newproc[i].ini_action == INIT_OFF) {
			kill (newproc[i].ini_pid, SIGTERM);
			kills++;
		}
	}
	if (kills)
		sleep (10);

	for (i = 0;i < newprocs;i++) {
		if (ip = findinit (newproc[i].ini_id, proc, nproc)) {
			if (newproc[i].ini_action == ip->ini_action
				&& strcmp (newproc[i].ini_levels, ip->ini_levels) == 0
				&& strcmp (newproc[i].ini_command, ip->ini_command) == 0)
				continue;
		}
		if (newproc[i].ini_pid == 0)
			continue;

		if (newproc[i].ini_action == INIT_OFF) {
			kill (newproc[i].ini_pid, SIGKILL);
			waitfor (&newproc[i]);
		}
	}
	for (i = 0;i < nproc;i++)
		freeinit (&proc[i]);

	proc = newproc;
	nproc = newprocs;
}

void	reread (sig)
int	sig;
{
	char	buf[BUFSIZ];

	signal (sig, reread);
	intrflag = sig;
}

prtab ()
{
	int	i;
	char	buf[BUFSIZ];

	for (i = 0;i < nproc;i++) {
		sprintf (buf, "%s:%s:%s:%s",
			proc[i].ini_id, proc[i].ini_levels,
			actions[proc[i].ini_action], proc[i].ini_command);
		msg (buf);
	}
}
SHAR_EOF
fi
if test -f 'spawn.c'
then
	echo shar: "will not over-write existing file 'spawn.c'"
else
cat << \SHAR_EOF > 'spawn.c'
#include <stdio.h>
#include <sys/types.h>
#include <utmp.h>
#include <signal.h>
#include "inittab.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)spawn.c	1.1	07:58:09	3/22/89";
#endif

extern	int	proc1;
extern	int	errno;
extern	int	nproc;
extern	int	wtmpfd;
extern	struct	inittab	*proc;

struct	utmp	*getutent ();
extern	void	waitfor ();
time_t	time ();

/*
 * spawn - execute an entry
 */

spawn (entry)
struct	inittab	*entry;
{
	int	mustwait = 0;
	int	child;
	int	type;
	int	fd;
	int	sig;
	char	buf[BUFSIZ];

	mustwait = (entry->ini_action == INIT_WAIT ||
			entry->ini_action == INIT_BOOTWAIT ||
			entry->ini_action == INIT_SYSINIT);

	switch (child = fork ()) {
		case 0:
			proc1 = 0;
			strcat (strcpy (buf, "exec "), entry->ini_command);
			for (fd = 0;fd < _NFILE;fd++)
				close (fd);
			setpgrp ();

			if (execl ("/bin/sh", "sh", "-c", buf, (char *) 0)) {
				sprintf (buf, "INIT: Can't exec %s", buf);
				error (buf);
				_exit (errno);
			}
			break;
		case -1:
			return;
		default:
			entry->ini_count++;
			entry->ini_pid = child;
			birth (entry);

			if (mustwait)
				waitfor (entry);

			break;
	}
}

void	waitfor (entry)
struct	inittab	*entry;
{
	struct	inittab	*ip;
	int	pid;
	int	status;
	int	i;
	int	children;

	if (entry && entry->ini_pid == 0)
		return;

	if (! entry) {		/* count the children to wait for */
		for (children = 0, ip = proc;ip != &proc[nproc];ip++)
			if (ip->ini_pid)
				children++;
	} else {		/* only have one to worry about */
		children = 1;
	}
	while (children && (pid = wait (&status)) != -1) {
		if (entry && pid == entry->ini_pid) {
			entry->ini_status = status;
			bury (entry);
			entry->ini_pid = 0;
			return;
		}

		/*
		 * find process in table and lay to rest.  may require
		 * being restarted if action is respawn.  entries not
		 * in the table are silently buried.
		 */

		for (ip = proc;ip != &proc[nproc];ip++) {
			if (ip->ini_pid != pid)
				continue;

			ip->ini_status = status;
			bury (ip);
			children--;
			ip->ini_pid = 0;
			if (ip->ini_action == INIT_RESPAWN) {
				spawn (ip);
				children++;
			}
			break;
		}
	}
}

bury (entry)
struct	inittab	*entry;
{
	struct	utmp	*utmp;

	setutent ();

	while (utmp = getutent ()) {
		if (strcmp (utmp->ut_id, entry->ini_id) == 0)
			break;
	}
	if (utmp) {
		utmp->ut_pid = entry->ini_pid;
		utmp->ut_type = DEAD_PROCESS;
		utmp->ut_exit.e_termination = entry->ini_status & 0377;
		utmp->ut_exit.e_exit = (entry->ini_status >> 8) & 0377;
		pututline (utmp);
		write (wtmpfd, (char *) utmp, sizeof *utmp);
	}
	endutent ();
}

birth (entry)
struct	inittab	*entry;
{
	struct	utmp	*utmp;
	struct	utmp	new;

	setutent ();

	while (utmp = getutent ()) {
		if (strcmp (utmp->ut_id, entry->ini_id) == 0)
			break;
	}
	if (! utmp) {
		utmp = &new;
		memset ((char *) utmp, 0, sizeof *utmp);
	}
	strncpy (utmp->ut_id, entry->ini_id, sizeof (utmp->ut_id));
	if (entry->ini_action == INIT_RESPAWN)
		strcpy (utmp->ut_user, "GETTY");
	else
		memset (utmp->ut_user, '\0', sizeof utmp->ut_user);
	utmp->ut_pid = entry->ini_pid;
	utmp->ut_type = INIT_PROCESS;
	utmp->ut_exit.e_termination = 0;
	utmp->ut_exit.e_exit = 0;
	utmp->ut_time = time ((time_t *) 0);

	pututline (utmp);
	write (wtmpfd, (char *) utmp, sizeof *utmp);

	endutent ();
}
SHAR_EOF
fi
if test -f 'config.h'
then
	echo shar: "will not over-write existing file 'config.h'"
else
cat << \SHAR_EOF > 'config.h'
/*
 * config.h - init configuration file
 *
 *	@(#)config.h	1.1	07:58:03	3/22/89
 */

#ifndef	DEBUG
#define	CONSOLE	"/dev/console"
#define	NPROC	100
#define	INITTAB	"/etc/inittab"
#else
#define	CONSOLE	"/dev/tty"
#define	NPROC	20
#define	INITTAB	"inittab"
#endif
SHAR_EOF
fi
if test -f 'inittab.h'
then
	echo shar: "will not over-write existing file 'inittab.h'"
else
cat << \SHAR_EOF > 'inittab.h'
#include <stdio.h>
#include "config.h"

/*
 * inittab - structure of the inittab file
 *
 *	@(#)inittab.h	1.1	07:58:06	3/22/89
 */

struct	inittab	{
	char	*ini_id;
	char	*ini_levels;
	int	ini_action;
	char	*ini_command;
	long	ini_count;
	int	ini_pid;
	int	ini_status;
};

#define	INIT_RESPAWN	0
#define	INIT_WAIT	1
#define	INIT_ONCE	2
#define	INIT_BOOT	3
#define	INIT_BOOTWAIT	4
#define	INIT_POWERFAIL	5
#define	INIT_POWERWAIT	6
#define	INIT_OFF	7
#define	INIT_ONDEMAND	8
#define	INIT_INITDEFAULT 9
#define	INIT_SYSINIT	10
SHAR_EOF
fi
if test -f 'patchlevel.h'
then
	echo shar: "will not over-write existing file 'patchlevel.h'"
else
cat << \SHAR_EOF > 'patchlevel.h'
/*
 * patchlevel.h - current patch level
 *
 *	@(#)patchlevel.h	1.1	07:58:07	3/22/89
 */

#define	PATCHLEVEL	1
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II                        +-Quote of the Week:-------------------
VoiceNet: (214) 250-3311   Data: -6272  | "Do not drink and bake"
InterNet: jfh@rpp386.Dallas.TX.US       |         -- Arnold Swartzenegger
UucpNet : <backbone>!killer!rpp386!jfh  +--------------------------------------

jfh@rpp386.Dallas.TX.US (John F. Haugh II) (03/23/89)

In article <13858@rpp386.Dallas.TX.US> jfh@rpp386.Dallas.TX.US (John F. Haugh II) writes:
>This is the beta test release of the init I've been munging on.
>It is currently being used on this site with some results.  It
>is not complete and does not contain a telinit.  You have to
>send it various signals to get things to happen ...

That paragraph should have been a clue.  Judging from the
mail I've received, some people don't associate `not done
yet' with `isn't from AT&T'.

This code IS NOT derived from AT&T source code.  I DO NOT
have a source code license and have not used AT&T code to
write this.  It is 100 PERCENT free of licensing hassles.

On the other hand, the init being distributed by Sandy
Zelkovitz IS derived from AT&T source code and is being
distributed in binary form ONLY.  If you need more info,
you may contact him at sandy@alphacm.UUCP.

DO NOT confuse my init with the init Sandy is handing
out.  PLEASE.  I don't need any more AT&T hate mail.  I
had my share of that last year with that damned yacc ...
-- 
John F. Haugh II                        +-Quote of the Week:-------------------
VoiceNet: (214) 250-3311   Data: -6272  | "Do not drink and bake"
InterNet: jfh@rpp386.Dallas.TX.US       |         -- Arnold Swartzenegger
UucpNet : <backbone>!killer!rpp386!jfh  +--------------------------------------