diff options
| author | Kyle Evans <kevans@FreeBSD.org> | 2019-11-05 02:30:41 +0000 |
|---|---|---|
| committer | Kyle Evans <kevans@FreeBSD.org> | 2019-11-05 02:30:41 +0000 |
| commit | 6d180b1360b19930587764af836c009419cc3365 (patch) | |
| tree | 621f0a5101f7b09d6254a2c0e641bda3d385d86c /release/picobsd/tinyware/oinit | |
| parent | 74954211d655f782278bea06fe59f42baeb06634 (diff) | |
Notes
Diffstat (limited to 'release/picobsd/tinyware/oinit')
| -rw-r--r-- | release/picobsd/tinyware/oinit/Makefile | 22 | ||||
| -rw-r--r-- | release/picobsd/tinyware/oinit/README | 123 | ||||
| -rw-r--r-- | release/picobsd/tinyware/oinit/oinit.c | 947 |
3 files changed, 0 insertions, 1092 deletions
diff --git a/release/picobsd/tinyware/oinit/Makefile b/release/picobsd/tinyware/oinit/Makefile deleted file mode 100644 index 072bbba8a840..000000000000 --- a/release/picobsd/tinyware/oinit/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# $FreeBSD$ -# -PROG= oinit - -SH_PATH?= /bin/sh -SH_NAME?= -sh -SH_ARG?= /etc/rc - -CFLAGS= -DSH_PATH=\"${SH_PATH}\" -DSH_NAME=\"${SH_NAME}\" \ - -DSH_ARG=\"${SH_ARG}\" - - -#CFLAGS+= -DUSE_HISTORY -#CFLAGS+= -DOINIT_RC=\"/etc/oinit.rc\" - -#LDADD= -lutil -ledit -ltermcap -LIBADD= util -MAN= - -.include <bsd.prog.mk> - - diff --git a/release/picobsd/tinyware/oinit/README b/release/picobsd/tinyware/oinit/README deleted file mode 100644 index e34c404f4a8d..000000000000 --- a/release/picobsd/tinyware/oinit/README +++ /dev/null @@ -1,123 +0,0 @@ -Warsaw, 1998.07.07 - -This README shortly describes the features of "oinit" - a very simplistic -version of init(8) combined with a shell. - -Features --------- - -* oinit is able to run system in multi- and single-user modes, -* it can be started on system with DEVFS/SLICE (i.e. empty /dev), -* provides minimalistic user interface, called "shell()", -* it can run the system startup script (/etc/rc), -* it can be compiled with -DOINIT_RC to use its own startup script - (*very* primitive, but doesn't require any real shell to run it!), -* doesn't require the whole chain of init->getty->login->shell to be run, -* it is extremely small, and is ideally suited for situations when - there is little memory. - -As an additional bonus you receive some obvious and some hidden bugs... :-)) -This code is at most alpha quality yet. - - -How it works ------------- - -Unlike normal init(8), it forks itself on given number of vty's immediately -providing shell() interface. Currently it doesn't require (and is unable to -perform) any authentication, but this is easy to add if needed. - -Standard version of FreeBSD kernel looks for /sbin/init first, and then -tries to execute it. If it fails, it tries to find: - /sbin/oinit - /sbin/init.bak - /stand/sysinstall - -So it is easy to make use of it even on standard system - just put it in -/sbin/oinit and rename /sbin/init to something else, e.g. /sbin/init.bak. - -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -!!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -Init (or oinit) plays crucial role in the system. If you plan to do any -changes to your system's init, make sure you have a boot floppy with working -version of statically compiled init(8) on it - you can very easily put your -system in unusable state when fiddling with it. -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Shell() interface ------------------ - -It allows you to issue built-in and external commands. Built-in commands -are listed below. For each command there is short help available, with -example of usage. - - cd change working directory - pwd print working directory - set set environment variable (no expansion) - unset unset environment variable - env print all environment variables - echo echo arguments on stdout - exit exit from shell (oinit will start a new one after some delay) - . source-in a file with commands - ? help - -Any other command is passed to execvp(3) as it is. - -EXCEPTION: if you end the command line with a '&', the command is started -as daemon. This is NOT the same as in normal shell, where the '&' puts a -process in background. Here the newly started process is totally dissociated -from terminal. - -Prompt tells you: -* your `pwd` -* your PID -* and that you are root ('#'). - -WARNING: this pseudo-shell doesn't do any expansion whatsoever. - -To do list ----------- - -- oinit proper: - * fix signal handling and transitions, - * invent a one-file configuration database (combining as many files - from /etc as possible into one) able to properly handle inter- - dependencies in running various daemons, - * allow for interpreting of such database, and running various - programs ourselves (this would eventually allow to make /bin/sh - an option, not necessity), - * better hooks for incorporating other modules into oinit (see e.g. - the telnet() below), - * add optional authentication, - -- shell(): - * more built-ins: perhaps 'kill' and 'ps', - * variable expansion, - * globbing, - * conditionals, - * history? (it depends on how much memory it needs). - * programmatic hooks for easy customisation of user interface (like - hierarchy of commands and contexts), - * ... - -- implement as a routine (like shell()) a small remote login daemon telnet(), - as a built-in module to oinit. It would implement the simplest options of - normal telnet, and would itself handle authentication, passing control to - shell() on success. The authentication routine would be the same as for - checking console access. - -And allow me for a moment of day-dreaming: I'd like to rewrite oinit one day -to be a monolithic one-in-all application, non-forking but multithreaded... It -would contain all the modules, such as shell(), telnet(), ifconfig() etc... -started as threads, not separate processes. - -Credits -------- - -The overall framework was taken from FreeBSD /sbin/init. - -Andrzej Bialecki -<abial@freebsd.org> - -$FreeBSD$ diff --git a/release/picobsd/tinyware/oinit/oinit.c b/release/picobsd/tinyware/oinit/oinit.c deleted file mode 100644 index 7715f3e67a5b..000000000000 --- a/release/picobsd/tinyware/oinit/oinit.c +++ /dev/null @@ -1,947 +0,0 @@ -/*- - * 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. - * - * $FreeBSD$ - */ - -/* - * 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[16]; /* 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(char *); -int pwd(char *); -int echo(char *); -int xit(char *); -int set(char *); -int unset(char *); -int env(char *); -int help(char *); -int sourcer(char *); -void do_command(int shell, char *cmdline); -void transition_handler(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=xterm",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("do_command(%s): exit code=%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=xterm"); - 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 -#ifndef SH_NAME -#define SH_NAME "-sh" -#endif -#ifndef SH_PATH -#define SH_PATH _PATH_BSHELL -#endif -#ifndef SH_ARG -#define SH_ARG "/etc/rc" -#endif -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_NAME; - argv[1]=SH_ARG; - argv[2]=0; - execvp(SH_PATH,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) -{ - int fd; - - 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); - 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",_PATH_DEV,MNT_NOEXEC|MNT_RDONLY,0); - - /* Fill in the sess structures. */ - /* XXX Really, should be filled based upon config file. */ - for(i=0;i<MAX_CONS;i++) { - if(i==0) { - sprintf(ttys[i].tty,_PATH_CONSOLE); - } else { - sprintf(ttys[i].tty,"%sv%c",_PATH_TTY,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); -} |
