aboutsummaryrefslogtreecommitdiff
path: root/release/picobsd/tinyware/oinit/oinit.c
diff options
context:
space:
mode:
authorAndrzej Bialecki <abial@FreeBSD.org>1998-08-27 17:38:45 +0000
committerAndrzej Bialecki <abial@FreeBSD.org>1998-08-27 17:38:45 +0000
commitc9d8fd0a7bb8ae40b9da7c52caec851ca9d0cf3e (patch)
tree0f9c1dcefca21fb605aaf84b621c2813f01fa5e4 /release/picobsd/tinyware/oinit/oinit.c
parent0b0c1554a87b20eb1377566bce8833788ec96394 (diff)
downloadsrc-c9d8fd0a7bb8ae40b9da7c52caec851ca9d0cf3e.tar.gz
src-c9d8fd0a7bb8ae40b9da7c52caec851ca9d0cf3e.zip
Initial import of PicoBSD v0.4 tree.
Notes
Notes: svn path=/cvs2svn/branches/PICOBSD/; revision=38589
Diffstat (limited to 'release/picobsd/tinyware/oinit/oinit.c')
-rw-r--r--release/picobsd/tinyware/oinit/oinit.c924
1 files changed, 924 insertions, 0 deletions
diff --git a/release/picobsd/tinyware/oinit/oinit.c b/release/picobsd/tinyware/oinit/oinit.c
new file mode 100644
index 000000000000..8cadb872a244
--- /dev/null
+++ b/release/picobsd/tinyware/oinit/oinit.c
@@ -0,0 +1,924 @@
+/*-
+ * Copyright (c) 1998 Andrzej Bialecki
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: oinit.c,v 1.8 1998/08/11 06:53:47 abial Exp $
+ */
+
+/*
+ * A primitive version of init(8) with simplistic user interface
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <err.h>
+
+#ifdef USE_HISTORY
+#error "Not yet. But it's quite simple to add - patches are welcome!"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <varargs.h>
+
+#define BUFSIZE 1024
+#define MAX_CONS 12
+
+#define NONE 0
+#define SINGLE 1
+#define MULTI 2
+#define DEATH 3
+
+#define FALSE 0
+#define TRUE 1
+
+char cwd[BUFSIZE];
+char vty[]="0123456789abcdef";
+char *progname;
+char *motd=NULL;
+int ncons=MAX_CONS;
+int Reboot=FALSE;
+int transition=MULTI;
+int prevtrans=SINGLE;
+jmp_buf machine;
+
+char *trans[]={ "NONE", "SINGLE", "MULTI", "DEATH" };
+
+extern char **environ;
+
+/* Struct for holding session state */
+struct sess {
+ char tty[11]; /* vty device path */
+ pid_t pid; /* pid of process running on it */
+ int (*func)(int argc, char **argv);
+ /* internal function to run on it (after forking) */
+} ttys[MAX_CONS];
+
+/* Struct for built-in command */
+struct command {
+ char *cmd; /* command name */
+ char *descr; /* command description */
+ char *usage; /* usage */
+ char *example; /* example of usage */
+ int (*func)(char *); /* callback function */
+};
+
+/* Prototypes */
+int cd __P((char *));
+int pwd __P((char *));
+int echo __P((char *));
+int xit __P((char *));
+int set __P((char *));
+int unset __P((char *));
+int env __P((char *));
+int help __P((char *));
+int sourcer __P((char *));
+void do_command __P((int shell, char *cmdline));
+void transition_handler __P((int));
+
+/* Table of built-in functions */
+struct command bltins[]={
+ {"cd","Change working directory","cd [dir]","cd /etc",cd},
+ {"pwd","Print current directory","pwd","pwd",pwd},
+ {"exit","Exit from shell()","exit","exit",xit},
+ {"set","Set environment variable","set [VAR=value]","set TERM=cons25",set},
+ {"unset","Unset environment variable","unset VAR","unset EDITOR",unset},
+ {"echo","Echo arguments on stdout","echo arg1 arg2 ...","echo Hello World!",echo},
+ {"env","Print all environment variables","env","env",env},
+ {".","Source-in a file with commands",". filename",". /etc/rc",sourcer},
+ {"?","Print this help :-)","? [command]","? set",help},
+ {NULL,NULL,NULL,NULL,NULL}
+};
+
+/*
+ * Built-in 'cd <path>' handler
+ */
+int
+cd(char *path)
+{
+ if(chdir(path)) return(-1);
+ getcwd(cwd,BUFSIZE);
+ return(0);
+}
+
+/*
+ * Built-in 'pwd' handler
+ */
+int
+pwd(char *dummy)
+{
+
+ if(getcwd(cwd,BUFSIZE)==NULL) return(-1);
+ printf("%s\n",cwd);
+ return(0);
+}
+
+/*
+ * Built-in 'exit' handler
+ */
+int
+xit(char *dummy)
+{
+ _exit(0);
+}
+
+/*
+ * Built-in 'echo' handler
+ */
+int
+echo(char *args)
+{
+ int i=0,j;
+ int len;
+ char c;
+ int s_quote=0,d_quote=0;
+ int sep=0,no_lf=0;
+
+ if(args==NULL) {
+ printf("\n");
+ return;
+ }
+ len=strlen(args);
+ if(len>=2) {
+ if(args[0]=='-' && args[1]=='n') {
+ no_lf++;
+ i=2;
+ while(i<len && (args[i]==' ' || args[i]=='\t')) i++;
+ }
+ }
+ while(i<len) {
+ c=args[i];
+ switch(c) {
+ case ' ':
+ case '\t':
+ if(s_quote||d_quote) {
+ putchar(c);
+ } else if(!sep) {
+ putchar(' ');
+ sep=1;
+ }
+ break;
+ case '\\':
+ i++;
+ c=args[i];
+ switch(c) {
+ case 'n':
+ putchar('\n');
+ break;
+ case 'b':
+ putchar('\b');
+ break;
+ case 't':
+ putchar('\t');
+ break;
+ case 'r':
+ putchar('\r');
+ break;
+ default:
+ putchar(c);
+ break;
+ }
+ break;
+ case '"':
+ if(!d_quote) {
+ d_quote=1;
+ for(j=i+1;j<len;j++) {
+ if(args[j]=='\\') {
+ j++;
+ continue;
+ }
+ if(args[j]=='"') {
+ d_quote=2;
+ break;
+ }
+ }
+ if(d_quote!=2) {
+ printf("\necho(): unmatched \"\n");
+ return;
+ }
+ } else d_quote=0;
+ break;
+ case '\'':
+ if(!s_quote) {
+ s_quote=1;
+ for(j=i+1;j<len;j++) {
+ if(args[j]=='\\') {
+ j++;
+ continue;
+ }
+ if(args[j]=='\'') {
+ s_quote=2;
+ break;
+ }
+ }
+ if(s_quote!=2) {
+ printf("\necho(): unmatched '\n");
+ return;
+ }
+ } else s_quote=0;
+ break;
+ case '`':
+ printf("echo(): backquote not implemented yet!\n");
+ break;
+ default:
+ sep=0;
+ putchar(c);
+ break;
+ }
+ i++;
+ }
+ if(!no_lf) putchar('\n');
+ fflush(stdout);
+}
+
+/*
+ * Built-in 'set VAR=value' handler
+ */
+int
+set(char *var)
+{
+ int res;
+
+ if(var==NULL) return(env(NULL));
+ res=putenv(var);
+ if(res) printf("set: %s\n",strerror(errno));
+ return(res);
+}
+
+/*
+ * Built-in 'env' handler
+ */
+int
+env(char *dummy)
+{
+ char **e;
+
+ e=environ;
+ while(*e!=NULL) {
+ printf("%s\n",*e++);
+ }
+ return(0);
+}
+
+/*
+ * Built-in 'unset VAR' handler
+ */
+int
+unset(char *var)
+{
+ if(var==NULL) {
+ printf("%s: parameter required.\n",progname);
+ return(-1);
+ }
+ return(unsetenv(var));
+}
+
+/*
+ * Built-in '?' handler
+ */
+int
+help(char *cmd)
+{
+ struct command *x;
+ int found=0;
+
+ if(cmd==NULL) {
+ printf("\nBuilt-in commands:\n");
+ printf("-------------------\n");
+ x=bltins;
+ while(x->cmd!=NULL) {
+ printf("%s\t%s\n",x->cmd,x->descr);
+ x++;
+ }
+ printf("\nEnter '? <cmd>' for details.\n\n");
+ return(0);
+ } else {
+ x=bltins;
+ while(x->cmd!=NULL) {
+ if(strcmp(x->cmd,cmd)==0) {
+ found++;
+ break;
+ }
+ x++;
+ }
+ if(found) {
+ printf("\n%s\t%s:\n",x->cmd,x->descr);
+ printf("\tUsage:\n\t\t%s\n",x->usage);
+ printf("\te.g:\n\t\t%s\n\n",x->example);
+ return(0);
+ } else {
+ printf("\n%s: no such command.\n\n",cmd);
+ return(-1);
+ }
+ }
+}
+
+/*
+ * Signal handler for shell()
+ */
+void
+shell_sig(int sig)
+{
+ switch(sig) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ /* ignore ? */
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Built-in '.' handler (read-in and execute commands from file)
+ */
+int
+sourcer(char *fname)
+{
+ FILE *fd;
+ char buf[512],*tok,*arg,**av;
+ int ac,len,f,res,i;
+ pid_t pid;
+ char *sep=" \t";
+
+ fd=fopen(fname,"r");
+ if(fd==NULL) {
+ printf("Couldn't open file '%s'\n",fname);
+ return(-1);
+ }
+ while(!feof(fd)) {
+ memset(buf,0,512);
+ if(fgets(buf,512,fd)==NULL) continue;
+ if((*buf=='#') || (*buf=='\n')) continue;
+ len=strlen(buf);
+ buf[len-1]='\0';
+ if(strncmp(buf,"ncons",5)==0) {
+ tok=strtok(buf,sep);
+ tok=strtok(NULL,sep);
+ ncons=atoi(tok);
+ if((ncons<1)||(ncons>MAX_CONS)) {
+ syslog(LOG_EMERG,"%s: bad ncons value; defaulting to %d\n",fname,MAX_CONS);
+ ncons=MAX_CONS;
+ }
+ continue;
+ } else if(strncmp(buf,"motd",4)==0) {
+ tok=strtok(buf,sep);
+ motd=strdup(strtok(NULL,sep));
+ continue;
+ } else {
+ do_command(0,buf);
+ }
+ /* Next command, please. */
+ }
+ fclose(fd);
+ syslog(LOG_EMERG,"Done with %s",fname);
+}
+
+void
+do_command(int shell, char *cmdline)
+{
+ char *tok,*c,*sep=" \t";
+ char **av;
+ struct command *x;
+ int found,len;
+ int ac,i,f,res;
+ int bg=0;
+ pid_t pid;
+
+ len=strlen(cmdline);
+ if(cmdline[len-1]=='&') {
+ bg++;
+ cmdline[len-1]='\0';
+ len--;
+ } else bg=0;
+ tok=strtok(cmdline,sep);
+ x=bltins;
+ found=0;
+ while(x->cmd!=NULL) {
+ if(strcmp(x->cmd,tok)==0) {
+ found++;
+ break;
+ }
+ x++;
+ }
+ if(found) {
+ tok=cmdline+strlen(x->cmd)+1;
+ while(*tok && isblank(*tok) && (tok<(cmdline+len))) tok++;
+ if(*tok==NULL) tok=NULL;
+ x->func(tok);
+ return;
+ }
+ ac=0;
+ av=(char **)calloc(((len+1)/2+1),sizeof(char *));
+ av[ac++]=tok;
+ while((av[ac++]=strtok(NULL,sep))!=NULL)
+ continue;
+ switch((pid=fork())) {
+ case 0:
+ if(shell) {
+ signal(SIGINT,SIG_DFL);
+ signal(SIGQUIT,SIG_DFL);
+ signal(SIGTERM,SIG_DFL);
+ signal(SIGHUP,SIG_DFL);
+ } else {
+ close(0);
+ close(1);
+ close(2);
+ f=open(_PATH_CONSOLE,O_RDWR);
+ dup2(f,0);
+ dup2(f,1);
+ dup2(f,2);
+ if(f>2) close(f);
+ }
+ if(bg) {
+ if(daemon(0,0)) {
+ printf("do_command(%s): failed to run bg: %s\n",
+ av[0],strerror(errno));
+ _exit(100);
+ }
+ }
+ execvp(av[0],av);
+ /* Something went wrong... */
+ printf("do_command(%s): %s\n",av[0],strerror(errno));
+ _exit(100);
+ break;
+ case -1:
+ printf("do_command(): %s\n",strerror(errno));
+ break;
+ default:
+ while(waitpid(pid,&res,0)!=pid) continue;
+ if(WEXITSTATUS(res)) {
+ printf("%s exited with status %d\n",
+ av[0],WEXITSTATUS(res));
+ }
+ break;
+ }
+ free(av);
+ return;
+}
+
+/*
+ * This is the user interface. This routine gets executed on each
+ * virtual console serviced by init.
+ *
+ * It works as normal shell does - for each external command it forks
+ * and execs, for each internal command just executes a function.
+ */
+
+int
+shell(int argc, char **argv)
+{
+ char buf[BUFSIZE];
+ char *prompt=" # ";
+ int fd;
+ int res;
+ pid_t mypid;
+
+ if(motd!=NULL) {
+ if((fd=open(motd,O_RDONLY))!=-1) {
+ do {
+ res=read(fd,buf,BUFSIZE);
+ res=write(1,buf,res);
+ } while(res>0);
+ close(fd);
+ }
+ }
+
+ printf("\n\n+=========================================================+\n");
+ printf("| Built-in shell() (enter '?' for short help on commands) |\n");
+ printf("+=========================================================+\n\n");
+ getcwd(cwd,BUFSIZE);
+ mypid=getpid();
+ signal(SIGINT,shell_sig);
+ signal(SIGQUIT,shell_sig);
+ signal(SIGTERM,shell_sig);
+ while(!feof(stdin)) {
+ memset(buf,0,BUFSIZE);
+ printf("(%d)%s%s",mypid,cwd,prompt);
+ fflush(stdout);
+ if(fgets(buf,BUFSIZE-1,stdin)==NULL) continue;
+ buf[strlen(buf)-1]='\0';
+ if(strlen(buf)==0) continue;
+ do_command(1,buf);
+ }
+ return(0);
+}
+
+/*
+ * Stub for executing some external program on a console. This is called
+ * from previously forked copy of our process, so that exec is ok.
+ */
+int
+external_cmd(int argc, char **argv)
+{
+ execvp(argv[0],argv);
+}
+
+/*
+ * Acquire vty and properly attach ourselves to it.
+ * Also, build basic environment for running user interface.
+ */
+
+int
+start_session(int vty, int argc, char **argv)
+{
+ int fd;
+ char *t;
+
+ close(0);
+ close(1);
+ close(2);
+ revoke(ttys[vty].tty);
+ fd=open(ttys[vty].tty,O_RDWR);
+ dup2(fd,0);
+ dup2(fd,1);
+ dup2(fd,2);
+ if(fd>2) close(fd);
+ login_tty(fd);
+ setpgid(0,getpid());
+ putenv("TERM=cons25");
+ putenv("HOME=/");
+ putenv("PATH=/stand:/bin:/usr/bin:/sbin:.");
+ signal(SIGHUP,SIG_DFL);
+ signal(SIGINT,SIG_DFL);
+ signal(SIGQUIT,SIG_DFL);
+ signal(SIGTERM,SIG_DFL);
+ chdir("/");
+ t=(char *)(rindex(ttys[vty].tty,'/')+1);
+ printf("\n\n\nStarting session on %s.\n",t);
+ ttys[vty].func(argc,argv);
+ _exit(0);
+}
+
+/*
+ * Execute system startup script /etc/rc
+ *
+ * (Of course if you don't like it - I don't - you can run anything you
+ * want here. Perhaps it would be useful just to read some config DB and
+ * do these things ourselves, avoiding forking lots of shells and scripts.)
+ */
+
+/* If OINIT_RC is defined, oinit will use it's own configuration file,
+ * /etc/oinit.rc. It's format is described below. Otherwise, it will use
+ * normal /etc/rc interpreted by Bourne shell.
+ */
+#ifndef OINIT_RC
+void
+runcom()
+{
+ char *argv[3];
+ pid_t pid;
+ int st;
+ int fd;
+
+ if((pid=fork())==0) {
+ /* child */
+ close(0);
+ close(1);
+ close(2);
+ fd=open(_PATH_CONSOLE,O_RDWR);
+ dup2(fd,0);
+ dup2(fd,1);
+ dup2(fd,2);
+ if(fd>2) close(fd);
+ argv[0]="-sh";
+ argv[1]="/etc/rc";
+ argv[2]=0;
+ execvp("/bin/sh",argv);
+ printf("runcom(): %s\n",strerror(errno));
+ _exit(1);
+ }
+ /* Wait for child to exit */
+ while(pid!=waitpid(pid,(int *)0,0)) continue;
+ return;
+}
+#else
+/* Alternative /etc/rc - default is /etc/oinit.rc. Its format is as follows:
+ * - each empty line or line beginning with a '#' is discarded
+ * - any other line must contain a keyword, or a (nonblocking) command to run.
+ *
+ * Thus far, the following keywords are defined:
+ * ncons <number> number of virtual consoles to open
+ * motd <pathname> full path to motd file
+ *
+ * Examples of commands to run:
+ *
+ * ifconfig lo0 inet 127.0.0.1 netmask 255.0.0.0
+ * ifconfig ed0 inet 148.81.168.10 netmask 255.255.255.0
+ * kbdcontrol -l /usr/share/syscons/my_map.kbd
+ */
+void
+runcom(char *fname)
+{
+ sourcer(fname);
+}
+#endif
+
+int
+run_multi()
+{
+ int i,j;
+ pid_t pid;
+ int found;
+
+ /* Run /etc/rc if not in single user */
+#ifndef OINIT_RC
+ if(prevtrans==SINGLE) runcom();
+#else
+ if(prevtrans==SINGLE) runcom(OINIT_RC);
+#endif
+ if(transition!=MULTI) return(-1);
+
+ syslog(LOG_EMERG,"*** Starting multi-user mode ***");
+
+ /* Fork shell interface for each console */
+ for(i=0;i<ncons;i++) {
+ if(ttys[i].pid==0) {
+ switch(pid=fork()) {
+ case 0:
+ start_session(i,0,NULL);
+ break;
+ case -1:
+ printf("%s: %s\n",progname,strerror(errno));
+ break;
+ default:
+ ttys[i].pid=pid;
+ break;
+ }
+ }
+ }
+ /* Initialize any other services we'll use - most probably this will
+ * be a 'telnet' service (some day...).
+ */
+ /* */
+
+ /* Emulate multi-user */
+ while(transition==MULTI) {
+ /* XXX Modify this to allow for checking for the input on
+ * XXX listening sockets, and forking a 'telnet' service.
+ */
+ /* */
+
+ /* Wait for any process to exit */
+ pid=waitpid(-1,(int *)0,0);
+ if(pid==-1) continue;
+ found=0;
+ j=-1;
+ /* search if it's one of our sessions */
+ for(i=0;i<ncons;i++) {
+ if(ttys[i].pid==pid) {
+ found++;
+ j=i;
+ ttys[j].pid=0;
+ break;
+ }
+ }
+ if(!found) {
+ /* Just collect the process's status */
+ continue;
+ } else {
+ /* restart shell() on a console, if it died */
+ if(transition!=MULTI) return(0);
+ switch(pid=fork()) {
+ case 0:
+ sleep(1);
+ start_session(j,0,NULL);
+ break;
+ case -1:
+ printf("%s: %s\n",progname,strerror(errno));
+ break;
+ default:
+ ttys[j].pid=pid;
+ break;
+ }
+ }
+ }
+}
+
+int clang;
+
+void
+kill_timer(int sig)
+{
+ clang=1;
+}
+
+kill_ttys()
+{
+}
+
+/*
+ * Start a shell on ttyv0 (i.e. the console).
+ */
+
+int
+run_single()
+{
+ int i;
+ pid_t pid,wpid;
+ static int sigs[2]={SIGTERM,SIGKILL};
+
+ syslog(LOG_EMERG,"*** Starting single-user mode ***");
+ /* Kill all existing sessions */
+ syslog(LOG_EMERG,"Killing all existing sessions...");
+ for(i=0;i<MAX_CONS;i++) {
+ kill(ttys[i].pid,SIGHUP);
+ ttys[i].pid=0;
+ }
+ for(i=0;i<2;i++) {
+ if(kill(-1,sigs[i])==-1 && errno==ESRCH) break;
+ clang=0;
+ alarm(10);
+ do {
+ pid=waitpid(-1,(int *)0,WUNTRACED);
+ if(errno==EINTR) continue;
+ else break;
+ } while (clang==0);
+ }
+ if(errno!=ECHILD) {
+ syslog(LOG_EMERG,"Some processes would not die; ps -axl advised");
+ }
+ /* Single-user */
+ switch(pid=fork()) {
+ case 0:
+ start_session(0,0,NULL);
+ break;
+ case -1:
+ printf("%s: %s\n",progname,strerror(errno));
+ printf("The system is seriously hosed. I'm dying...\n");
+ transition=DEATH;
+ return(-1);
+ break;
+ default:
+ do {
+ wpid=waitpid(pid,(int *)0,WUNTRACED);
+ } while(wpid!=pid && transition==SINGLE);
+ if(transition!=DEATH) {
+ prevtrans=transition;
+ transition=MULTI;
+ }
+ break;
+ }
+ return(0);
+}
+
+/*
+ * Transition handler - installed as signal handler.
+ */
+
+void
+transition_handler(int sig)
+{
+
+ switch(sig) {
+ case SIGHUP:
+ case SIGTERM:
+ prevtrans=transition;
+ transition=SINGLE;
+ syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]);
+ if(prevtrans!=transition) longjmp(machine,sig);
+ break;
+ case SIGINT:
+ case SIGQUIT:
+ prevtrans=transition;
+ transition=DEATH;
+ syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]);
+ if(prevtrans!=transition) longjmp(machine,sig);
+ break;
+ default:
+ syslog(LOG_EMERG,"pid=%d sig=%s (ignored)\n",getpid(),sys_siglist[sig]);
+ break;
+ }
+}
+
+/*
+ * Change system state appropriately to the signals
+ */
+
+int
+transition_machine()
+{
+ int i;
+
+ while(transition!=DEATH) {
+ switch(transition) {
+ case MULTI:
+ run_multi();
+ break;
+ case SINGLE:
+ run_single();
+ break;
+ }
+ }
+ syslog(LOG_EMERG,"Killing all existing sessions...");
+ /* Kill all sessions */
+ kill(-1,SIGKILL);
+ /* Be nice and wait for them */
+ while(waitpid(-1,(int *)0,WNOHANG|WUNTRACED)>0) continue;
+ unmount("/",0);
+ reboot(RB_AUTOBOOT);
+ /* NOTREACHED */
+}
+
+int
+main(int argc, char **argv)
+{
+ int devfs=0,c,i;
+
+ /* These are copied from real init(8) */
+ if(getuid()!=0)
+ errx(1,"%s",strerror(EPERM));
+ openlog("init",LOG_CONS|LOG_ODELAY,LOG_AUTH);
+ if(setsid()<0)
+ warn("initial setsid() failed");
+ if(setlogin("root")<0)
+ warn("setlogin() failed");
+
+ close(0);
+ close(1);
+ close(2);
+ chdir("/");
+
+ progname=rindex(argv[0],'/');
+ if(progname==NULL) {
+ progname=argv[0];
+ } else progname++;
+
+ transition=MULTI;
+
+ /* We must recognize the same options as real init does */
+ while((c=getopt(argc,argv,"dsf"))!=-1) {
+ switch(c) {
+ case 'd':
+ devfs=1;
+ break;
+ case 's':
+ transition=SINGLE;
+ break;
+ case 'f':
+ break;
+ default:
+ printf("%s: unrecognized flag '-%c'\n",progname,c);
+ break;
+ }
+ }
+ if(devfs)
+ mount("devfs","/dev",MNT_NOEXEC|MNT_RDONLY,0);
+
+ /* Fill in the sess structures. */
+ /* XXX Really, should be filled basing on config file. */
+ for(i=0;i<MAX_CONS;i++) {
+ sprintf(ttys[i].tty,"/dev/ttyv%c",vty[i]);
+ ttys[i].pid=0;
+ ttys[i].func=shell;
+ }
+
+ getcwd(cwd,BUFSIZE);
+
+ signal(SIGINT,transition_handler);
+ signal(SIGQUIT,transition_handler);
+ signal(SIGTERM,transition_handler);
+ signal(SIGHUP,transition_handler);
+ signal(SIGALRM,kill_timer);
+
+ setjmp(machine);
+ transition_machine(transition);
+ /* NOTREACHED */
+ exit(100);
+}