/*
** Module:	proc1
**
** Purpose:	This module is imbedded in the system image loaded by the
**		bootstrap loader program. proc1's only purpose is to 
**		allow init to reside on the /etc or /bin directory.
**		proc1 exec's /etc/init, which takes over proc1's pid
**		etc.
**
** Version:	1 - 95/01/29 - Initial version
** Release:	0 - 95/01/29 - Initial release
**
** Author:	Lew Pitcher
**
**		Note: Minix 1.5 initialization requires that proc1 
**		immediately swap out, waiting on some system service.
**		If proc1 does *not* do this, fs cannot initialize
**		properly, and a FileSystem Panic is generated.
**		So... the first thing we have to do is sync() so that
**		fs/mm/kernel can synchronize their initializations.
**
**		Note: proc1 makes heavy use of static variables, 'cause
**		it doesn't have a big stack. The normal stack allocation
**		done by mm in conjunction with the binary's header info
**		has not been performed for mm, fs, or proc1. This means
**		that we allocate a static global buffer, and the startup
**		code linked to proc1 uses that static buffer for the stack.
**		In turn, we must be careful that we don't overflow the
**		buffer by excessive use of automatic variables.
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>

#define NONE	((char *) 0)			/* end of arg list	*/
#define STACKSIZE (192 * sizeof(char *))	/* proc1's stack	*/
#define ABEND	199				/* can't exec login	*/

#define WARNING	"\nproc1 Error: Cant exec init - login and repair root fs\n"
#define PANIC	"proc1 Panic: Cant exec /bin/login - reboot new root fs\n" 

char stack[STACKSIZE];				/* as i said before...	*/
char *stackpt = &stack[STACKSIZE];
char **environ;					/* needed by libc fns	*/
extern int errno;

char *tiny_env[] = { (char *) 0};	/* tiny environment for execle	*/

main()
{
	static pid_t child;
	static int status;

	do {
		sync();		/* flush filesystem buffers	*/

		/* try to exec init from one of it's two locations */
		execle("/etc/init", NONE, tiny_env);
		execle("/bin/init", NONE, tiny_env);

		/* cant find init - start login so root can fix /bin */
		if ((child = fork()) == 0)
		{
			dup(dup(open("/dev/tty0",O_RDWR)));
			display(WARNING);
			execle("/bin/login", "login", NONE, tiny_env);
			display(PANIC);
			exit(ABEND);
		}
		else while (wait(&status) != child) sync();
	} while (!WIFEXITED(status) || (WEXITSTATUS(status) != ABEND));

	/* if we get here, we're really up a creek	**
	** so all we can do is sync the buffers and die	*/
	sync();
}

display(msg)	/* display given message on (already open ) stderr	*/
char *msg;
{
	register int len;

	/* count the characters in the message */
	for (len = 0; *(msg+len) != '\0'; ++len);

	/* write the message to stderr */
	write(2,msg,len);
}

/*
** One-off sbrk to allocate memory for execle. The stack and heap are not
** set up right for the library sbrk. This code borrowed from original
** Minix init.
*/
char *sbrk(incr)
int incr;
{
	static void *some_mem[100];	 /* (void *) aligns it */
	register char *new_brk;
	static char *old_brk = (char *) some_mem;
	register char *result;

	/*
	** Overflow of the next expression will be caught by the next test
	** without an explicit check, because sizeof (some_mem) < INT_MAX
	*/
	new_brk = old_brk + incr;
	if (new_brk > (char *) some_mem + sizeof (some_mem) ||
	    new_brk < (char *) some_mem)
		return ((char *) -1);
	result = old_brk;
	old_brk = new_brk;
	return (result);
}

