Subject: Re: Where to start...?
To: Rose, Brian <>
From: Erik Anggard <>
List: tech-embed
Date: 08/26/2002 11:15:19
This is a multi-part message in MIME format.
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

The attached mini_init.c works for me. (Note that this is a stripped 
down version of an init that did a bit more stuff that is  specific to 
our system).

Compile with "cc -Wall -Werror -static -o init mini_init.c".


Rose, Brian wrote:

>>From: Erik Anggard <>
>>List: tech-embed
>>Well, if you want to get really minimalistic all you'll need is:
>>- A kernel (comment out all options and devices you don't need, in the 
>>config file before compiling it to reduce the size of the kernel).
>>- A root device: if you don't have a hardrive you can use a memory disk 
>>beded in the kernel (like in the installation-kernel) or NFS.
>>- Your own statically linked /sbin/init on the root device. This is the 
>>only userland process started by the kernel so if your system only need 
>>to run one program call it init and place it in /sbin. (Your program 
>>might have to do some of the things that the original init does, e.g. if 
>>your program wants do console io you will need a /dev/console and your 
>>init will have to open that device and dup2 fd's 0, 1 and 2 to that fd). 
>>You can of course use the standard init and instead creat your own
>Has anyone created a minimal init that just sets up the console? I've tried
>looking through the init code, but I'm not seeing where it sets this up.
>I'm currently looking through all the glibc functions to find outhow to do
>this. Is there a simple code snippet somewhere that shows how to set up the
>console and operate a simple C program (aka Hello World!)?
>Thanks for the help.
>Brian Rose 
>Brian dot Rose at icn dot siemens dot com 
>If you hold a Unix shell to your ear, do you hear the C?

Content-Type: text/plain;
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;

/* $Id: asrbl.c,v 1.48 2002/03/05 10:34:09 eriang Exp $ */

 * File:    mini_init.c
 * By:      Erik Anggard, PacketFront Sweden AB
 * Created: 2001-10-02
 * Minimal init process.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/reboot.h>
#include <sys/mount.h>
#include <ufs/ufs/ufsmount.h>
#include <sys/cdefs.h>
#include <sys/socket.h>
#include <stddef.h>
#include <syslog.h>

 * Defines
#define PATH_CONSOLE "/dev/console"
#define MAXCMD 128

 * Prototypes
static void reboot_system(void);
static void critical(char *msg);
static int setup_tty(char *name, int redirect);
void badsig_handler(int sig);
static int setup_signals(void);

 * Globals 
int single = 0;

 * main
main(int argc, char *argv[])
	struct ufs_args args;
	char cmdstr[MAXCMD+1], *s, *s2;
	int done;

	if (argc == 2 && !strcmp(argv[1], "-s"))
		single = 1;
	if (single) {
		openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);

		/* remount root fs in read-write */
		bzero(&args, sizeof(struct ufs_args));
		args.export.ex_root = DEFAULT_ROOTUID;
		if (mount(MOUNT_FFS, "/", MNT_UPDATE, &args) == -1)
			syslog(LOG_ALERT, "init: failed to remount root files "
			       "system read-write\n");


		setup_tty(PATH_CONSOLE, 1);


	done = 0;
	while (!done) {
		/* Display simple prompt. */
		printf("# ");
		if ((s = fgets(cmdstr, MAXCMD, stdin)) != NULL) {
			/* strip white space */
			while (isspace(*s)) s++;
			s2 = s;
			while (*s2 != '\0') s2++;
			while (isspace(*s2) && s2 > s) s2--;
			s2[1] = '\0';
			if (*s == '\0')
			/* Handle commands. */
			if (!strcmp(s, "reboot")) {
				done = 1;
			} else if (!strcmp(s, "test")) {
			} else {
				printf("unkown command: %s\n", s);

	if (single)

	return (0);

 * reboot
static void 

	if (reboot(RB_AUTOBOOT, NULL) == -1)

	for (;;);

 * critical
static void 
critical(char *msg)
	syslog(LOG_EMERG, "%s", msg);

/* Setup the console for output/input/whatever. Much of this is
 * taken from the NetBSD init and libs. 
static int 
setup_tty(char *name, int redirect)
	int fd;

	sleep(2); /* NetBSD does this. */

	if((fd = open(name, O_RDWR)) == -1)
		critical("Unable to open tty");

	/* Taken from login_tty */
	if(ioctl(fd, TIOCSCTTY, NULL) == -1)
		critical("Unable to set controlling tty");
	if (redirect) {
		dup2(fd, 0);
		dup2(fd, 1);
		dup2(fd, 2);
	if (fd > 2)

	return 0;

 * badsig_handler
badsig_handler(int sig)
	char text[64];

	snprintf(text, 64, "Received signal %d", sig);

/* Signal choices taken from NetBSD init. */
static int 
	struct sigaction sa;
	sigset_t mask;
	sa.sa_flags = 0;
	sa.sa_handler = badsig_handler;
	sigaction(SIGSYS, &sa, NULL);
	sigaction(SIGABRT, &sa, NULL);
	sigaction(SIGFPE, &sa, NULL);
	sigaction(SIGILL, &sa, NULL);
	sigaction(SIGSEGV, &sa, NULL);
	sigaction(SIGBUS, &sa, NULL);
	sigaction(SIGXCPU, &sa, NULL);
	sigaction(SIGXFSZ, &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);
	sa.sa_flags = 0;
	sa.sa_handler = (void *)reboot_system;
	sigaction(SIGUSR1, &sa, NULL);
	sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
	sa.sa_handler = badsig_handler;
	sigaction(SIGCHLD, &sa, NULL);

	sigdelset(&mask, SIGABRT);
	sigdelset(&mask, SIGFPE);
	sigdelset(&mask, SIGILL);
	sigdelset(&mask, SIGSEGV);
	sigdelset(&mask, SIGBUS);
	sigdelset(&mask, SIGSYS);
	sigdelset(&mask, SIGXCPU);
	sigdelset(&mask, SIGXFSZ);
	sigdelset(&mask, SIGHUP);
	sigdelset(&mask, SIGTERM);
	sigdelset(&mask, SIGUSR1);
	sigprocmask(SIG_SETMASK, &mask, NULL);

	return 0;