138589Sabial/*- 238589Sabial * Copyright (c) 1998 Andrzej Bialecki 338589Sabial * All rights reserved. 438589Sabial * 538589Sabial * Redistribution and use in source and binary forms, with or without 638589Sabial * modification, are permitted provided that the following conditions 738589Sabial * are met: 838589Sabial * 1. Redistributions of source code must retain the above copyright 938589Sabial * notice, this list of conditions and the following disclaimer. 1038589Sabial * 2. Redistributions in binary form must reproduce the above copyright 1138589Sabial * notice, this list of conditions and the following disclaimer in the 1238589Sabial * documentation and/or other materials provided with the distribution. 1338589Sabial * 1438589Sabial * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538589Sabial * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638589Sabial * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738589Sabial * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838589Sabial * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938589Sabial * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038589Sabial * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138589Sabial * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238589Sabial * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338589Sabial * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438589Sabial * SUCH DAMAGE. 2538589Sabial * 2650479Speter * $FreeBSD$ 2738589Sabial */ 2838589Sabial 2938589Sabial/* 3038589Sabial * A primitive version of init(8) with simplistic user interface 3138589Sabial */ 3238589Sabial 3338589Sabial#include <sys/types.h> 3438589Sabial#include <sys/param.h> 3538589Sabial#include <sys/mount.h> 3638589Sabial#include <sys/reboot.h> 3738589Sabial#include <sys/time.h> 3838589Sabial#include <sys/resource.h> 3938589Sabial#include <sys/wait.h> 4038589Sabial#include <ctype.h> 4138589Sabial#include <err.h> 4238589Sabial 4338589Sabial#ifdef USE_HISTORY 4438589Sabial#error "Not yet. But it's quite simple to add - patches are welcome!" 4538589Sabial#endif 4638589Sabial 4738589Sabial#include <errno.h> 4838589Sabial#include <fcntl.h> 4938589Sabial#include <libutil.h> 5038589Sabial#include <paths.h> 5138589Sabial#include <setjmp.h> 5238589Sabial#include <signal.h> 5338589Sabial#include <stdio.h> 5438589Sabial#include <string.h> 5538589Sabial#include <syslog.h> 5638589Sabial#include <unistd.h> 5738589Sabial#include <varargs.h> 5838589Sabial 5938589Sabial#define BUFSIZE 1024 6038589Sabial#define MAX_CONS 12 6138589Sabial 6238589Sabial#define NONE 0 6338589Sabial#define SINGLE 1 6438589Sabial#define MULTI 2 6538589Sabial#define DEATH 3 6638589Sabial 6738589Sabial#define FALSE 0 6838589Sabial#define TRUE 1 6938589Sabial 7038589Sabialchar cwd[BUFSIZE]; 7138589Sabialchar vty[]="0123456789abcdef"; 7238589Sabialchar *progname; 7338589Sabialchar *motd=NULL; 7438589Sabialint ncons=MAX_CONS; 7538589Sabialint Reboot=FALSE; 7638589Sabialint transition=MULTI; 7738589Sabialint prevtrans=SINGLE; 7838589Sabialjmp_buf machine; 7938589Sabial 8038589Sabialchar *trans[]={ "NONE", "SINGLE", "MULTI", "DEATH" }; 8138589Sabial 8238589Sabialextern char **environ; 8338589Sabial 8438589Sabial/* Struct for holding session state */ 8538589Sabialstruct sess { 8641191Sabial char tty[16]; /* vty device path */ 8738589Sabial pid_t pid; /* pid of process running on it */ 8838589Sabial int (*func)(int argc, char **argv); 8938589Sabial /* internal function to run on it (after forking) */ 9038589Sabial} ttys[MAX_CONS]; 9138589Sabial 9238589Sabial/* Struct for built-in command */ 9338589Sabialstruct command { 9438589Sabial char *cmd; /* command name */ 9538589Sabial char *descr; /* command description */ 9638589Sabial char *usage; /* usage */ 9738589Sabial char *example; /* example of usage */ 9838589Sabial int (*func)(char *); /* callback function */ 9938589Sabial}; 10038589Sabial 10138589Sabial/* Prototypes */ 102104744Salfredint cd(char *); 103104744Salfredint pwd(char *); 104104744Salfredint echo(char *); 105104744Salfredint xit(char *); 106104744Salfredint set(char *); 107104744Salfredint unset(char *); 108104744Salfredint env(char *); 109104744Salfredint help(char *); 110104744Salfredint sourcer(char *); 111104744Salfredvoid do_command(int shell, char *cmdline); 112104744Salfredvoid transition_handler(int); 11338589Sabial 11438589Sabial/* Table of built-in functions */ 11538589Sabialstruct command bltins[]={ 11638589Sabial {"cd","Change working directory","cd [dir]","cd /etc",cd}, 11738589Sabial {"pwd","Print current directory","pwd","pwd",pwd}, 11838589Sabial {"exit","Exit from shell()","exit","exit",xit}, 119199251Sed {"set","Set environment variable","set [VAR=value]","set TERM=xterm",set}, 12038589Sabial {"unset","Unset environment variable","unset VAR","unset EDITOR",unset}, 12138589Sabial {"echo","Echo arguments on stdout","echo arg1 arg2 ...","echo Hello World!",echo}, 12238589Sabial {"env","Print all environment variables","env","env",env}, 12338589Sabial {".","Source-in a file with commands",". filename",". /etc/rc",sourcer}, 12438589Sabial {"?","Print this help :-)","? [command]","? set",help}, 12538589Sabial {NULL,NULL,NULL,NULL,NULL} 12638589Sabial}; 12738589Sabial 12838589Sabial/* 12938589Sabial * Built-in 'cd <path>' handler 13038589Sabial */ 13138589Sabialint 13238589Sabialcd(char *path) 13338589Sabial{ 13438589Sabial if(chdir(path)) return(-1); 13538589Sabial getcwd(cwd,BUFSIZE); 13638589Sabial return(0); 13738589Sabial} 13838589Sabial 13938589Sabial/* 14038589Sabial * Built-in 'pwd' handler 14138589Sabial */ 14238589Sabialint 14338589Sabialpwd(char *dummy) 14438589Sabial{ 14538589Sabial 14638589Sabial if(getcwd(cwd,BUFSIZE)==NULL) return(-1); 14738589Sabial printf("%s\n",cwd); 14838589Sabial return(0); 14938589Sabial} 15038589Sabial 15138589Sabial/* 15238589Sabial * Built-in 'exit' handler 15338589Sabial */ 15438589Sabialint 15538589Sabialxit(char *dummy) 15638589Sabial{ 15738589Sabial _exit(0); 15838589Sabial} 15938589Sabial 16038589Sabial/* 16138589Sabial * Built-in 'echo' handler 16238589Sabial */ 16338589Sabialint 16438589Sabialecho(char *args) 16538589Sabial{ 16638589Sabial int i=0,j; 16738589Sabial int len; 16838589Sabial char c; 16938589Sabial int s_quote=0,d_quote=0; 17038589Sabial int sep=0,no_lf=0; 17138589Sabial 17238589Sabial if(args==NULL) { 17338589Sabial printf("\n"); 17438589Sabial return; 17538589Sabial } 17638589Sabial len=strlen(args); 17738589Sabial if(len>=2) { 17838589Sabial if(args[0]=='-' && args[1]=='n') { 17938589Sabial no_lf++; 18038589Sabial i=2; 18138589Sabial while(i<len && (args[i]==' ' || args[i]=='\t')) i++; 18238589Sabial } 18338589Sabial } 18438589Sabial while(i<len) { 18538589Sabial c=args[i]; 18638589Sabial switch(c) { 18738589Sabial case ' ': 18838589Sabial case '\t': 18938589Sabial if(s_quote||d_quote) { 19038589Sabial putchar(c); 19138589Sabial } else if(!sep) { 19238589Sabial putchar(' '); 19338589Sabial sep=1; 19438589Sabial } 19538589Sabial break; 19638589Sabial case '\\': 19738589Sabial i++; 19838589Sabial c=args[i]; 19938589Sabial switch(c) { 20038589Sabial case 'n': 20138589Sabial putchar('\n'); 20238589Sabial break; 20338589Sabial case 'b': 20438589Sabial putchar('\b'); 20538589Sabial break; 20638589Sabial case 't': 20738589Sabial putchar('\t'); 20838589Sabial break; 20938589Sabial case 'r': 21038589Sabial putchar('\r'); 21138589Sabial break; 21238589Sabial default: 21338589Sabial putchar(c); 21438589Sabial break; 21538589Sabial } 21638589Sabial break; 21738589Sabial case '"': 21838589Sabial if(!d_quote) { 21938589Sabial d_quote=1; 22038589Sabial for(j=i+1;j<len;j++) { 22138589Sabial if(args[j]=='\\') { 22238589Sabial j++; 22338589Sabial continue; 22438589Sabial } 22538589Sabial if(args[j]=='"') { 22638589Sabial d_quote=2; 22738589Sabial break; 22838589Sabial } 22938589Sabial } 23038589Sabial if(d_quote!=2) { 23138589Sabial printf("\necho(): unmatched \"\n"); 23238589Sabial return; 23338589Sabial } 23438589Sabial } else d_quote=0; 23538589Sabial break; 23638589Sabial case '\'': 23738589Sabial if(!s_quote) { 23838589Sabial s_quote=1; 23938589Sabial for(j=i+1;j<len;j++) { 24038589Sabial if(args[j]=='\\') { 24138589Sabial j++; 24238589Sabial continue; 24338589Sabial } 24438589Sabial if(args[j]=='\'') { 24538589Sabial s_quote=2; 24638589Sabial break; 24738589Sabial } 24838589Sabial } 24938589Sabial if(s_quote!=2) { 25038589Sabial printf("\necho(): unmatched '\n"); 25138589Sabial return; 25238589Sabial } 25338589Sabial } else s_quote=0; 25438589Sabial break; 25538589Sabial case '`': 25638589Sabial printf("echo(): backquote not implemented yet!\n"); 25738589Sabial break; 25838589Sabial default: 25938589Sabial sep=0; 26038589Sabial putchar(c); 26138589Sabial break; 26238589Sabial } 26338589Sabial i++; 26438589Sabial } 26538589Sabial if(!no_lf) putchar('\n'); 26638589Sabial fflush(stdout); 26738589Sabial} 26838589Sabial 26938589Sabial/* 27038589Sabial * Built-in 'set VAR=value' handler 27138589Sabial */ 27238589Sabialint 27338589Sabialset(char *var) 27438589Sabial{ 27538589Sabial int res; 27638589Sabial 27738589Sabial if(var==NULL) return(env(NULL)); 27838589Sabial res=putenv(var); 27938589Sabial if(res) printf("set: %s\n",strerror(errno)); 28038589Sabial return(res); 28138589Sabial} 28238589Sabial 28338589Sabial/* 28438589Sabial * Built-in 'env' handler 28538589Sabial */ 28638589Sabialint 28738589Sabialenv(char *dummy) 28838589Sabial{ 28938589Sabial char **e; 29038589Sabial 29138589Sabial e=environ; 29238589Sabial while(*e!=NULL) { 29338589Sabial printf("%s\n",*e++); 29438589Sabial } 29538589Sabial return(0); 29638589Sabial} 29738589Sabial 29838589Sabial/* 29938589Sabial * Built-in 'unset VAR' handler 30038589Sabial */ 30138589Sabialint 30238589Sabialunset(char *var) 30338589Sabial{ 30438589Sabial if(var==NULL) { 30538589Sabial printf("%s: parameter required.\n",progname); 30638589Sabial return(-1); 30738589Sabial } 30838589Sabial return(unsetenv(var)); 30938589Sabial} 31038589Sabial 31138589Sabial/* 31238589Sabial * Built-in '?' handler 31338589Sabial */ 31438589Sabialint 31538589Sabialhelp(char *cmd) 31638589Sabial{ 31738589Sabial struct command *x; 31838589Sabial int found=0; 31938589Sabial 32038589Sabial if(cmd==NULL) { 32138589Sabial printf("\nBuilt-in commands:\n"); 32238589Sabial printf("-------------------\n"); 32338589Sabial x=bltins; 32438589Sabial while(x->cmd!=NULL) { 32538589Sabial printf("%s\t%s\n",x->cmd,x->descr); 32638589Sabial x++; 32738589Sabial } 32838589Sabial printf("\nEnter '? <cmd>' for details.\n\n"); 32938589Sabial return(0); 33038589Sabial } else { 33138589Sabial x=bltins; 33238589Sabial while(x->cmd!=NULL) { 33338589Sabial if(strcmp(x->cmd,cmd)==0) { 33438589Sabial found++; 33538589Sabial break; 33638589Sabial } 33738589Sabial x++; 33838589Sabial } 33938589Sabial if(found) { 34038589Sabial printf("\n%s\t%s:\n",x->cmd,x->descr); 34138589Sabial printf("\tUsage:\n\t\t%s\n",x->usage); 34238589Sabial printf("\te.g:\n\t\t%s\n\n",x->example); 34338589Sabial return(0); 34438589Sabial } else { 34538589Sabial printf("\n%s: no such command.\n\n",cmd); 34638589Sabial return(-1); 34738589Sabial } 34838589Sabial } 34938589Sabial} 35038589Sabial 35138589Sabial/* 35238589Sabial * Signal handler for shell() 35338589Sabial */ 35438589Sabialvoid 35538589Sabialshell_sig(int sig) 35638589Sabial{ 35738589Sabial switch(sig) { 35838589Sabial case SIGINT: 35938589Sabial case SIGQUIT: 36038589Sabial case SIGTERM: 36138589Sabial /* ignore ? */ 36238589Sabial break; 36338589Sabial default: 36438589Sabial break; 36538589Sabial } 36638589Sabial} 36738589Sabial 36838589Sabial/* 36938589Sabial * Built-in '.' handler (read-in and execute commands from file) 37038589Sabial */ 37138589Sabialint 37238589Sabialsourcer(char *fname) 37338589Sabial{ 37438589Sabial FILE *fd; 37538589Sabial char buf[512],*tok,*arg,**av; 37638589Sabial int ac,len,f,res,i; 37738589Sabial pid_t pid; 37838589Sabial char *sep=" \t"; 37938589Sabial 38038589Sabial fd=fopen(fname,"r"); 38138589Sabial if(fd==NULL) { 38238589Sabial printf("Couldn't open file '%s'\n",fname); 38338589Sabial return(-1); 38438589Sabial } 38538589Sabial while(!feof(fd)) { 38638589Sabial memset(buf,0,512); 38738589Sabial if(fgets(buf,512,fd)==NULL) continue; 38838589Sabial if((*buf=='#') || (*buf=='\n')) continue; 38938589Sabial len=strlen(buf); 39038589Sabial buf[len-1]='\0'; 39138589Sabial if(strncmp(buf,"ncons",5)==0) { 39238589Sabial tok=strtok(buf,sep); 39338589Sabial tok=strtok(NULL,sep); 39438589Sabial ncons=atoi(tok); 39538589Sabial if((ncons<1)||(ncons>MAX_CONS)) { 39638589Sabial syslog(LOG_EMERG,"%s: bad ncons value; defaulting to %d\n",fname,MAX_CONS); 39738589Sabial ncons=MAX_CONS; 39838589Sabial } 39938589Sabial continue; 40038589Sabial } else if(strncmp(buf,"motd",4)==0) { 40138589Sabial tok=strtok(buf,sep); 40238589Sabial motd=strdup(strtok(NULL,sep)); 40338589Sabial continue; 40438589Sabial } else { 40538589Sabial do_command(0,buf); 40638589Sabial } 40738589Sabial /* Next command, please. */ 40838589Sabial } 40938589Sabial fclose(fd); 41038589Sabial syslog(LOG_EMERG,"Done with %s",fname); 41138589Sabial} 41238589Sabial 41338589Sabialvoid 41438589Sabialdo_command(int shell, char *cmdline) 41538589Sabial{ 41638589Sabial char *tok,*c,*sep=" \t"; 41738589Sabial char **av; 41838589Sabial struct command *x; 41938589Sabial int found,len; 42038589Sabial int ac,i,f,res; 42138589Sabial int bg=0; 42238589Sabial pid_t pid; 42338589Sabial 42438589Sabial len=strlen(cmdline); 42538589Sabial if(cmdline[len-1]=='&') { 42638589Sabial bg++; 42738589Sabial cmdline[len-1]='\0'; 42838589Sabial len--; 42938589Sabial } else bg=0; 43038589Sabial tok=strtok(cmdline,sep); 43138589Sabial x=bltins; 43238589Sabial found=0; 43338589Sabial while(x->cmd!=NULL) { 43438589Sabial if(strcmp(x->cmd,tok)==0) { 43538589Sabial found++; 43638589Sabial break; 43738589Sabial } 43838589Sabial x++; 43938589Sabial } 44038589Sabial if(found) { 44138589Sabial tok=cmdline+strlen(x->cmd)+1; 44238589Sabial while(*tok && isblank(*tok) && (tok<(cmdline+len))) tok++; 44338589Sabial if(*tok==NULL) tok=NULL; 44438589Sabial x->func(tok); 44538589Sabial return; 44638589Sabial } 44738589Sabial ac=0; 44838589Sabial av=(char **)calloc(((len+1)/2+1),sizeof(char *)); 44938589Sabial av[ac++]=tok; 45038589Sabial while((av[ac++]=strtok(NULL,sep))!=NULL) 45138589Sabial continue; 45238589Sabial switch((pid=fork())) { 45338589Sabial case 0: 45438589Sabial if(shell) { 45538589Sabial signal(SIGINT,SIG_DFL); 45638589Sabial signal(SIGQUIT,SIG_DFL); 45738589Sabial signal(SIGTERM,SIG_DFL); 45838589Sabial signal(SIGHUP,SIG_DFL); 45938589Sabial } else { 46038589Sabial close(0); 46138589Sabial close(1); 46238589Sabial close(2); 46338589Sabial f=open(_PATH_CONSOLE,O_RDWR); 46438589Sabial dup2(f,0); 46538589Sabial dup2(f,1); 46638589Sabial dup2(f,2); 46738589Sabial if(f>2) close(f); 46838589Sabial } 46938589Sabial if(bg) { 47038589Sabial if(daemon(0,0)) { 47138589Sabial printf("do_command(%s): failed to run bg: %s\n", 47238589Sabial av[0],strerror(errno)); 47338589Sabial _exit(100); 47438589Sabial } 47538589Sabial } 47638589Sabial execvp(av[0],av); 47738589Sabial /* Something went wrong... */ 47838589Sabial printf("do_command(%s): %s\n",av[0],strerror(errno)); 47938589Sabial _exit(100); 48038589Sabial break; 48138589Sabial case -1: 48238589Sabial printf("do_command(): %s\n",strerror(errno)); 48338589Sabial break; 48438589Sabial default: 48538589Sabial while(waitpid(pid,&res,0)!=pid) continue; 48638589Sabial if(WEXITSTATUS(res)) { 48740412Sabial printf("do_command(%s): exit code=%d\n", 48838589Sabial av[0],WEXITSTATUS(res)); 48938589Sabial } 49038589Sabial break; 49138589Sabial } 49238589Sabial free(av); 49338589Sabial return; 49438589Sabial} 49538589Sabial 49638589Sabial/* 49738589Sabial * This is the user interface. This routine gets executed on each 49838589Sabial * virtual console serviced by init. 49938589Sabial * 50038589Sabial * It works as normal shell does - for each external command it forks 50138589Sabial * and execs, for each internal command just executes a function. 50238589Sabial */ 50338589Sabial 50438589Sabialint 50538589Sabialshell(int argc, char **argv) 50638589Sabial{ 50738589Sabial char buf[BUFSIZE]; 50838589Sabial char *prompt=" # "; 50938589Sabial int fd; 51038589Sabial int res; 51138589Sabial pid_t mypid; 51238589Sabial 51338589Sabial if(motd!=NULL) { 51438589Sabial if((fd=open(motd,O_RDONLY))!=-1) { 51538589Sabial do { 51638589Sabial res=read(fd,buf,BUFSIZE); 51738589Sabial res=write(1,buf,res); 51838589Sabial } while(res>0); 51938589Sabial close(fd); 52038589Sabial } 52138589Sabial } 52238589Sabial 52338589Sabial printf("\n\n+=========================================================+\n"); 52438589Sabial printf("| Built-in shell() (enter '?' for short help on commands) |\n"); 52538589Sabial printf("+=========================================================+\n\n"); 52638589Sabial getcwd(cwd,BUFSIZE); 52738589Sabial mypid=getpid(); 52838589Sabial signal(SIGINT,shell_sig); 52938589Sabial signal(SIGQUIT,shell_sig); 53038589Sabial signal(SIGTERM,shell_sig); 53138589Sabial while(!feof(stdin)) { 53238589Sabial memset(buf,0,BUFSIZE); 53338589Sabial printf("(%d)%s%s",mypid,cwd,prompt); 53438589Sabial fflush(stdout); 53538589Sabial if(fgets(buf,BUFSIZE-1,stdin)==NULL) continue; 53638589Sabial buf[strlen(buf)-1]='\0'; 53738589Sabial if(strlen(buf)==0) continue; 53838589Sabial do_command(1,buf); 53938589Sabial } 54038589Sabial return(0); 54138589Sabial} 54238589Sabial 54338589Sabial/* 54438589Sabial * Stub for executing some external program on a console. This is called 54538589Sabial * from previously forked copy of our process, so that exec is ok. 54638589Sabial */ 54738589Sabialint 54838589Sabialexternal_cmd(int argc, char **argv) 54938589Sabial{ 55038589Sabial execvp(argv[0],argv); 55138589Sabial} 55238589Sabial 55338589Sabial/* 55438589Sabial * Acquire vty and properly attach ourselves to it. 55538589Sabial * Also, build basic environment for running user interface. 55638589Sabial */ 55738589Sabial 55838589Sabialint 55938589Sabialstart_session(int vty, int argc, char **argv) 56038589Sabial{ 56138589Sabial int fd; 56238589Sabial char *t; 56338589Sabial 56438589Sabial close(0); 56538589Sabial close(1); 56638589Sabial close(2); 56738589Sabial revoke(ttys[vty].tty); 56838589Sabial fd=open(ttys[vty].tty,O_RDWR); 56938589Sabial dup2(fd,0); 57038589Sabial dup2(fd,1); 57138589Sabial dup2(fd,2); 57238589Sabial if(fd>2) close(fd); 57338589Sabial login_tty(fd); 57438589Sabial setpgid(0,getpid()); 575199251Sed putenv("TERM=xterm"); 57638589Sabial putenv("HOME=/"); 57738589Sabial putenv("PATH=/stand:/bin:/usr/bin:/sbin:."); 57838589Sabial signal(SIGHUP,SIG_DFL); 57938589Sabial signal(SIGINT,SIG_DFL); 58038589Sabial signal(SIGQUIT,SIG_DFL); 58138589Sabial signal(SIGTERM,SIG_DFL); 58238589Sabial chdir("/"); 58338589Sabial t=(char *)(rindex(ttys[vty].tty,'/')+1); 58438589Sabial printf("\n\n\nStarting session on %s.\n",t); 58538589Sabial ttys[vty].func(argc,argv); 58638589Sabial _exit(0); 58738589Sabial} 58838589Sabial 58938589Sabial/* 59038589Sabial * Execute system startup script /etc/rc 59138589Sabial * 59238589Sabial * (Of course if you don't like it - I don't - you can run anything you 59338589Sabial * want here. Perhaps it would be useful just to read some config DB and 59438589Sabial * do these things ourselves, avoiding forking lots of shells and scripts.) 59538589Sabial */ 59638589Sabial 59738589Sabial/* If OINIT_RC is defined, oinit will use it's own configuration file, 59838589Sabial * /etc/oinit.rc. It's format is described below. Otherwise, it will use 59938589Sabial * normal /etc/rc interpreted by Bourne shell. 60038589Sabial */ 60138589Sabial#ifndef OINIT_RC 60271295Salex#ifndef SH_NAME 60371295Salex#define SH_NAME "-sh" 60471295Salex#endif 60571295Salex#ifndef SH_PATH 60671295Salex#define SH_PATH _PATH_BSHELL 60771295Salex#endif 60871295Salex#ifndef SH_ARG 60971295Salex#define SH_ARG "/etc/rc" 61071295Salex#endif 61138589Sabialvoid 61238589Sabialruncom() 61338589Sabial{ 61438589Sabial char *argv[3]; 61538589Sabial pid_t pid; 61638589Sabial int st; 61738589Sabial int fd; 61838589Sabial 61938589Sabial if((pid=fork())==0) { 62038589Sabial /* child */ 62138589Sabial close(0); 62238589Sabial close(1); 62338589Sabial close(2); 62438589Sabial fd=open(_PATH_CONSOLE,O_RDWR); 62538589Sabial dup2(fd,0); 62638589Sabial dup2(fd,1); 62738589Sabial dup2(fd,2); 62838589Sabial if(fd>2) close(fd); 62971295Salex argv[0]=SH_NAME; 63071295Salex argv[1]=SH_ARG; 63138589Sabial argv[2]=0; 63271295Salex execvp(SH_PATH,argv); 63338589Sabial printf("runcom(): %s\n",strerror(errno)); 63438589Sabial _exit(1); 63538589Sabial } 63638589Sabial /* Wait for child to exit */ 63738589Sabial while(pid!=waitpid(pid,(int *)0,0)) continue; 63838589Sabial return; 63938589Sabial} 64038589Sabial#else 64138589Sabial/* Alternative /etc/rc - default is /etc/oinit.rc. Its format is as follows: 64238589Sabial * - each empty line or line beginning with a '#' is discarded 64338589Sabial * - any other line must contain a keyword, or a (nonblocking) command to run. 64438589Sabial * 64538589Sabial * Thus far, the following keywords are defined: 64638589Sabial * ncons <number> number of virtual consoles to open 64738589Sabial * motd <pathname> full path to motd file 64838589Sabial * 64938589Sabial * Examples of commands to run: 65038589Sabial * 65138589Sabial * ifconfig lo0 inet 127.0.0.1 netmask 255.0.0.0 65238589Sabial * ifconfig ed0 inet 148.81.168.10 netmask 255.255.255.0 65338589Sabial * kbdcontrol -l /usr/share/syscons/my_map.kbd 65438589Sabial */ 65538589Sabialvoid 65638589Sabialruncom(char *fname) 65738589Sabial{ 65841191Sabial int fd; 65941191Sabial 66041191Sabial close(0); 66141191Sabial close(1); 66241191Sabial close(2); 66341191Sabial fd=open(_PATH_CONSOLE,O_RDWR); 66441191Sabial dup2(fd,0); 66541191Sabial dup2(fd,1); 66641191Sabial dup2(fd,2); 66741191Sabial if(fd>2) close(fd); 66838589Sabial sourcer(fname); 66938589Sabial} 67038589Sabial#endif 67138589Sabial 67238589Sabialint 67338589Sabialrun_multi() 67438589Sabial{ 67538589Sabial int i,j; 67638589Sabial pid_t pid; 67738589Sabial int found; 67838589Sabial 67938589Sabial /* Run /etc/rc if not in single user */ 68038589Sabial#ifndef OINIT_RC 68138589Sabial if(prevtrans==SINGLE) runcom(); 68238589Sabial#else 68338589Sabial if(prevtrans==SINGLE) runcom(OINIT_RC); 68438589Sabial#endif 68538589Sabial if(transition!=MULTI) return(-1); 68638589Sabial 68738589Sabial syslog(LOG_EMERG,"*** Starting multi-user mode ***"); 68838589Sabial 68938589Sabial /* Fork shell interface for each console */ 69038589Sabial for(i=0;i<ncons;i++) { 69138589Sabial if(ttys[i].pid==0) { 69238589Sabial switch(pid=fork()) { 69338589Sabial case 0: 69438589Sabial start_session(i,0,NULL); 69538589Sabial break; 69638589Sabial case -1: 69738589Sabial printf("%s: %s\n",progname,strerror(errno)); 69838589Sabial break; 69938589Sabial default: 70038589Sabial ttys[i].pid=pid; 70138589Sabial break; 70238589Sabial } 70338589Sabial } 70438589Sabial } 70538589Sabial /* Initialize any other services we'll use - most probably this will 70638589Sabial * be a 'telnet' service (some day...). 70738589Sabial */ 70838589Sabial /* */ 70938589Sabial 71038589Sabial /* Emulate multi-user */ 71138589Sabial while(transition==MULTI) { 71238589Sabial /* XXX Modify this to allow for checking for the input on 71338589Sabial * XXX listening sockets, and forking a 'telnet' service. 71438589Sabial */ 71538589Sabial /* */ 71638589Sabial 71738589Sabial /* Wait for any process to exit */ 71838589Sabial pid=waitpid(-1,(int *)0,0); 71938589Sabial if(pid==-1) continue; 72038589Sabial found=0; 72138589Sabial j=-1; 72238589Sabial /* search if it's one of our sessions */ 72338589Sabial for(i=0;i<ncons;i++) { 72438589Sabial if(ttys[i].pid==pid) { 72538589Sabial found++; 72638589Sabial j=i; 72738589Sabial ttys[j].pid=0; 72838589Sabial break; 72938589Sabial } 73038589Sabial } 73138589Sabial if(!found) { 73238589Sabial /* Just collect the process's status */ 73338589Sabial continue; 73438589Sabial } else { 73538589Sabial /* restart shell() on a console, if it died */ 73638589Sabial if(transition!=MULTI) return(0); 73738589Sabial switch(pid=fork()) { 73838589Sabial case 0: 73938589Sabial sleep(1); 74038589Sabial start_session(j,0,NULL); 74138589Sabial break; 74238589Sabial case -1: 74338589Sabial printf("%s: %s\n",progname,strerror(errno)); 74438589Sabial break; 74538589Sabial default: 74638589Sabial ttys[j].pid=pid; 74738589Sabial break; 74838589Sabial } 74938589Sabial } 75038589Sabial } 75138589Sabial} 75238589Sabial 75338589Sabialint clang; 75438589Sabial 75538589Sabialvoid 75638589Sabialkill_timer(int sig) 75738589Sabial{ 75838589Sabial clang=1; 75938589Sabial} 76038589Sabial 76138589Sabialkill_ttys() 76238589Sabial{ 76338589Sabial} 76438589Sabial 76538589Sabial/* 76638589Sabial * Start a shell on ttyv0 (i.e. the console). 76738589Sabial */ 76838589Sabial 76938589Sabialint 77038589Sabialrun_single() 77138589Sabial{ 77238589Sabial int i; 77338589Sabial pid_t pid,wpid; 77438589Sabial static int sigs[2]={SIGTERM,SIGKILL}; 77538589Sabial 77638589Sabial syslog(LOG_EMERG,"*** Starting single-user mode ***"); 77738589Sabial /* Kill all existing sessions */ 77838589Sabial syslog(LOG_EMERG,"Killing all existing sessions..."); 77938589Sabial for(i=0;i<MAX_CONS;i++) { 78038589Sabial kill(ttys[i].pid,SIGHUP); 78138589Sabial ttys[i].pid=0; 78238589Sabial } 78338589Sabial for(i=0;i<2;i++) { 78438589Sabial if(kill(-1,sigs[i])==-1 && errno==ESRCH) break; 78538589Sabial clang=0; 78638589Sabial alarm(10); 78738589Sabial do { 78838589Sabial pid=waitpid(-1,(int *)0,WUNTRACED); 78938589Sabial if(errno==EINTR) continue; 79038589Sabial else break; 79138589Sabial } while (clang==0); 79238589Sabial } 79338589Sabial if(errno!=ECHILD) { 79438589Sabial syslog(LOG_EMERG,"Some processes would not die; ps -axl advised"); 79538589Sabial } 79638589Sabial /* Single-user */ 79738589Sabial switch(pid=fork()) { 79838589Sabial case 0: 79938589Sabial start_session(0,0,NULL); 80038589Sabial break; 80138589Sabial case -1: 80238589Sabial printf("%s: %s\n",progname,strerror(errno)); 80338589Sabial printf("The system is seriously hosed. I'm dying...\n"); 80438589Sabial transition=DEATH; 80538589Sabial return(-1); 80638589Sabial break; 80738589Sabial default: 80838589Sabial do { 80938589Sabial wpid=waitpid(pid,(int *)0,WUNTRACED); 81038589Sabial } while(wpid!=pid && transition==SINGLE); 81138589Sabial if(transition!=DEATH) { 81238589Sabial prevtrans=transition; 81338589Sabial transition=MULTI; 81438589Sabial } 81538589Sabial break; 81638589Sabial } 81738589Sabial return(0); 81838589Sabial} 81938589Sabial 82038589Sabial/* 82138589Sabial * Transition handler - installed as signal handler. 82238589Sabial */ 82338589Sabial 82438589Sabialvoid 82538589Sabialtransition_handler(int sig) 82638589Sabial{ 82738589Sabial 82838589Sabial switch(sig) { 82938589Sabial case SIGHUP: 83038589Sabial case SIGTERM: 83138589Sabial prevtrans=transition; 83238589Sabial transition=SINGLE; 83338589Sabial syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]); 83438589Sabial if(prevtrans!=transition) longjmp(machine,sig); 83538589Sabial break; 83638589Sabial case SIGINT: 83738589Sabial case SIGQUIT: 83838589Sabial prevtrans=transition; 83938589Sabial transition=DEATH; 84038589Sabial syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]); 84138589Sabial if(prevtrans!=transition) longjmp(machine,sig); 84238589Sabial break; 84338589Sabial default: 84438589Sabial syslog(LOG_EMERG,"pid=%d sig=%s (ignored)\n",getpid(),sys_siglist[sig]); 84538589Sabial break; 84638589Sabial } 84738589Sabial} 84838589Sabial 84938589Sabial/* 85038589Sabial * Change system state appropriately to the signals 85138589Sabial */ 85238589Sabial 85338589Sabialint 85438589Sabialtransition_machine() 85538589Sabial{ 85638589Sabial int i; 85738589Sabial 85838589Sabial while(transition!=DEATH) { 85938589Sabial switch(transition) { 86038589Sabial case MULTI: 86138589Sabial run_multi(); 86238589Sabial break; 86338589Sabial case SINGLE: 86438589Sabial run_single(); 86538589Sabial break; 86638589Sabial } 86738589Sabial } 86838589Sabial syslog(LOG_EMERG,"Killing all existing sessions..."); 86938589Sabial /* Kill all sessions */ 87038589Sabial kill(-1,SIGKILL); 87138589Sabial /* Be nice and wait for them */ 87238589Sabial while(waitpid(-1,(int *)0,WNOHANG|WUNTRACED)>0) continue; 87338589Sabial unmount("/",0); 87438589Sabial reboot(RB_AUTOBOOT); 87538589Sabial /* NOTREACHED */ 87638589Sabial} 87738589Sabial 87838589Sabialint 87938589Sabialmain(int argc, char **argv) 88038589Sabial{ 88138589Sabial int devfs=0,c,i; 88238589Sabial 88338589Sabial /* These are copied from real init(8) */ 88438589Sabial if(getuid()!=0) 88538589Sabial errx(1,"%s",strerror(EPERM)); 88638589Sabial openlog("init",LOG_CONS|LOG_ODELAY,LOG_AUTH); 88738589Sabial if(setsid()<0) 88838589Sabial warn("initial setsid() failed"); 88938589Sabial if(setlogin("root")<0) 89038589Sabial warn("setlogin() failed"); 89138589Sabial 89238589Sabial close(0); 89338589Sabial close(1); 89438589Sabial close(2); 89538589Sabial chdir("/"); 89638589Sabial 89738589Sabial progname=rindex(argv[0],'/'); 89838589Sabial if(progname==NULL) { 89938589Sabial progname=argv[0]; 90038589Sabial } else progname++; 90138589Sabial 90238589Sabial transition=MULTI; 90338589Sabial 90438589Sabial /* We must recognize the same options as real init does */ 90538589Sabial while((c=getopt(argc,argv,"dsf"))!=-1) { 90638589Sabial switch(c) { 90738589Sabial case 'd': 90838589Sabial devfs=1; 90938589Sabial break; 91038589Sabial case 's': 91138589Sabial transition=SINGLE; 91238589Sabial break; 91338589Sabial case 'f': 91438589Sabial break; 91538589Sabial default: 91638589Sabial printf("%s: unrecognized flag '-%c'\n",progname,c); 91738589Sabial break; 91838589Sabial } 91938589Sabial } 92038589Sabial if(devfs) 92169793Sobrien mount("devfs",_PATH_DEV,MNT_NOEXEC|MNT_RDONLY,0); 92238589Sabial 92338589Sabial /* Fill in the sess structures. */ 92441191Sabial /* XXX Really, should be filled based upon config file. */ 92538589Sabial for(i=0;i<MAX_CONS;i++) { 92641191Sabial if(i==0) { 92769793Sobrien sprintf(ttys[i].tty,_PATH_CONSOLE); 92841191Sabial } else { 92969793Sobrien sprintf(ttys[i].tty,"%sv%c",_PATH_TTY,vty[i]); 93041191Sabial } 93138589Sabial ttys[i].pid=0; 93238589Sabial ttys[i].func=shell; 93338589Sabial } 93438589Sabial 93538589Sabial getcwd(cwd,BUFSIZE); 93638589Sabial 93738589Sabial signal(SIGINT,transition_handler); 93838589Sabial signal(SIGQUIT,transition_handler); 93938589Sabial signal(SIGTERM,transition_handler); 94038589Sabial signal(SIGHUP,transition_handler); 94138589Sabial signal(SIGALRM,kill_timer); 94238589Sabial 94338589Sabial setjmp(machine); 94438589Sabial transition_machine(transition); 94538589Sabial /* NOTREACHED */ 94638589Sabial exit(100); 94738589Sabial} 948