]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - release/picobsd/tinyware/oinit/oinit.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / release / picobsd / tinyware / oinit / oinit.c
1 /*-
2  * Copyright (c) 1998 Andrzej Bialecki
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 /*
30  * A primitive version of init(8) with simplistic user interface
31  */
32
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/mount.h>
36 #include <sys/reboot.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <sys/wait.h>
40 #include <ctype.h>
41 #include <err.h>
42
43 #ifdef USE_HISTORY
44 #error "Not yet. But it's quite simple to add - patches are welcome!"
45 #endif
46
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <libutil.h>
50 #include <paths.h>
51 #include <setjmp.h>
52 #include <signal.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <syslog.h>
56 #include <unistd.h>
57 #include <varargs.h>
58
59 #define BUFSIZE 1024
60 #define MAX_CONS 12
61
62 #define NONE    0
63 #define SINGLE  1
64 #define MULTI   2
65 #define DEATH   3
66
67 #define FALSE   0
68 #define TRUE    1
69
70 char cwd[BUFSIZE];
71 char vty[]="0123456789abcdef";
72 char *progname;
73 char *motd=NULL;
74 int ncons=MAX_CONS;
75 int Reboot=FALSE;
76 int transition=MULTI;
77 int prevtrans=SINGLE;
78 jmp_buf machine;
79
80 char *trans[]={ "NONE", "SINGLE", "MULTI", "DEATH" };
81
82 extern char **environ;
83
84 /* Struct for holding session state */
85 struct sess {
86         char tty[16];   /* vty device path */
87         pid_t pid;      /* pid of process running on it */
88         int (*func)(int argc, char **argv);
89                         /* internal function to run on it (after forking) */
90 } ttys[MAX_CONS];
91
92 /* Struct for built-in command */
93 struct command {
94         char *cmd;              /* command name */
95         char *descr;            /* command description */
96         char *usage;            /* usage */
97         char *example;          /* example of usage */
98         int (*func)(char *);    /* callback function */
99 };
100
101 /* Prototypes */
102 int cd(char *);
103 int pwd(char *);
104 int echo(char *);
105 int xit(char *);
106 int set(char *);
107 int unset(char *);
108 int env(char *);
109 int help(char *);
110 int sourcer(char *);
111 void do_command(int shell, char *cmdline);
112 void transition_handler(int);
113
114 /* Table of built-in functions */
115 struct command bltins[]={
116         {"cd","Change working directory","cd [dir]","cd /etc",cd},
117         {"pwd","Print current directory","pwd","pwd",pwd},
118         {"exit","Exit from shell()","exit","exit",xit},
119         {"set","Set environment variable","set [VAR=value]","set TERM=xterm",set},
120         {"unset","Unset environment variable","unset VAR","unset EDITOR",unset},
121         {"echo","Echo arguments on stdout","echo arg1 arg2 ...","echo Hello World!",echo},
122         {"env","Print all environment variables","env","env",env},
123         {".","Source-in a file with commands",". filename",". /etc/rc",sourcer},
124         {"?","Print this help :-)","? [command]","? set",help},
125         {NULL,NULL,NULL,NULL,NULL}
126 };
127
128 /*
129  * Built-in 'cd <path>' handler
130  */
131 int
132 cd(char *path)
133 {
134         if(chdir(path)) return(-1);
135         getcwd(cwd,BUFSIZE);
136         return(0);
137 }
138
139 /*
140  * Built-in 'pwd' handler
141  */
142 int
143 pwd(char *dummy)
144 {
145
146         if(getcwd(cwd,BUFSIZE)==NULL) return(-1);
147         printf("%s\n",cwd);
148         return(0);
149 }
150
151 /*
152  * Built-in 'exit' handler
153  */
154 int
155 xit(char *dummy)
156 {
157         _exit(0);
158 }
159
160 /*
161  * Built-in 'echo' handler
162  */
163 int
164 echo(char *args)
165 {
166         int i=0,j;
167         int len;
168         char c;
169         int s_quote=0,d_quote=0;
170         int sep=0,no_lf=0;
171
172         if(args==NULL) {
173                 printf("\n");
174                 return;
175         }
176         len=strlen(args);
177         if(len>=2) {
178                 if(args[0]=='-' && args[1]=='n') {
179                         no_lf++;
180                         i=2;
181                         while(i<len && (args[i]==' ' || args[i]=='\t')) i++;
182                 }
183         }
184         while(i<len) {
185                 c=args[i];
186                 switch(c) {
187                 case ' ':
188                 case '\t':
189                         if(s_quote||d_quote) {
190                                 putchar(c);
191                         } else if(!sep) {
192                                 putchar(' ');
193                                 sep=1;
194                         }
195                         break;
196                 case '\\':
197                         i++;
198                         c=args[i];
199                         switch(c) {
200                         case 'n':
201                                 putchar('\n');
202                                 break;
203                         case 'b':
204                                 putchar('\b');
205                                 break;
206                         case 't':
207                                 putchar('\t');
208                                 break;
209                         case 'r':
210                                 putchar('\r');
211                                 break;
212                         default:
213                                 putchar(c);
214                                 break;
215                         }
216                         break;
217                 case '"':
218                         if(!d_quote) {
219                                 d_quote=1;
220                                 for(j=i+1;j<len;j++) {
221                                         if(args[j]=='\\') {
222                                                 j++;
223                                                 continue;
224                                         }
225                                         if(args[j]=='"') {
226                                                 d_quote=2;
227                                                 break;
228                                         }
229                                 }
230                                 if(d_quote!=2) {
231                                         printf("\necho(): unmatched \"\n");
232                                         return;
233                                 }
234                         } else d_quote=0;
235                         break;
236                 case '\'':
237                         if(!s_quote) {
238                                 s_quote=1;
239                                 for(j=i+1;j<len;j++) {
240                                         if(args[j]=='\\') {
241                                                 j++;
242                                                 continue;
243                                         }
244                                         if(args[j]=='\'') {
245                                                 s_quote=2;
246                                                 break;
247                                         }
248                                 }
249                                 if(s_quote!=2) {
250                                         printf("\necho(): unmatched '\n");
251                                         return;
252                                 }
253                         } else s_quote=0;
254                         break;
255                 case '`':
256                         printf("echo(): backquote not implemented yet!\n");
257                         break;
258                 default:
259                         sep=0;
260                         putchar(c);
261                         break;
262                 }
263                 i++;
264         }
265         if(!no_lf) putchar('\n');
266         fflush(stdout);
267 }
268
269 /*
270  * Built-in 'set VAR=value' handler
271  */
272 int
273 set(char *var)
274 {
275         int res;
276
277         if(var==NULL) return(env(NULL));
278         res=putenv(var);
279         if(res) printf("set: %s\n",strerror(errno));
280         return(res);
281 }
282
283 /*
284  * Built-in 'env' handler
285  */
286 int
287 env(char *dummy)
288 {
289         char **e;
290
291         e=environ;
292         while(*e!=NULL) {
293                 printf("%s\n",*e++);
294         }
295         return(0);
296 }
297
298 /*
299  * Built-in 'unset VAR' handler
300  */
301 int
302 unset(char *var)
303 {
304         if(var==NULL) {
305                 printf("%s: parameter required.\n",progname);
306                 return(-1);
307         }
308         return(unsetenv(var));
309 }
310
311 /*
312  * Built-in '?' handler
313  */
314 int
315 help(char *cmd)
316 {
317         struct command *x;
318         int found=0;
319
320         if(cmd==NULL) {
321                 printf("\nBuilt-in commands:\n");
322                 printf("-------------------\n");
323                 x=bltins;
324                 while(x->cmd!=NULL) {
325                         printf("%s\t%s\n",x->cmd,x->descr);
326                         x++;
327                 }
328                 printf("\nEnter '? <cmd>' for details.\n\n");
329                 return(0);
330         } else {
331                 x=bltins;
332                 while(x->cmd!=NULL) {
333                         if(strcmp(x->cmd,cmd)==0) {
334                                 found++;
335                                 break;
336                         }
337                         x++;
338                 }
339                 if(found) {
340                         printf("\n%s\t%s:\n",x->cmd,x->descr);
341                         printf("\tUsage:\n\t\t%s\n",x->usage);
342                         printf("\te.g:\n\t\t%s\n\n",x->example);
343                         return(0);
344                 } else {
345                         printf("\n%s: no such command.\n\n",cmd);
346                         return(-1);
347                 }
348         }
349 }
350
351 /*
352  * Signal handler for shell()
353  */
354 void
355 shell_sig(int sig)
356 {
357         switch(sig) {
358         case SIGINT:
359         case SIGQUIT:
360         case SIGTERM:
361                 /* ignore ? */
362                 break;
363         default:
364                 break;
365         }
366 }
367
368 /*
369  * Built-in '.' handler (read-in and execute commands from file)
370  */
371 int
372 sourcer(char *fname)
373 {
374         FILE *fd;
375         char buf[512],*tok,*arg,**av;
376         int ac,len,f,res,i;
377         pid_t pid;
378         char *sep=" \t";
379
380         fd=fopen(fname,"r");
381         if(fd==NULL) {
382                 printf("Couldn't open file '%s'\n",fname);
383                 return(-1);
384         }
385         while(!feof(fd)) {
386                 memset(buf,0,512);
387                 if(fgets(buf,512,fd)==NULL) continue;
388                 if((*buf=='#') || (*buf=='\n')) continue;
389                 len=strlen(buf);
390                 buf[len-1]='\0';
391                 if(strncmp(buf,"ncons",5)==0) {
392                         tok=strtok(buf,sep);
393                         tok=strtok(NULL,sep);
394                         ncons=atoi(tok);
395                         if((ncons<1)||(ncons>MAX_CONS)) {
396                                 syslog(LOG_EMERG,"%s: bad ncons value; defaulting to %d\n",fname,MAX_CONS);
397                                 ncons=MAX_CONS;
398                         }
399                         continue;
400                 } else if(strncmp(buf,"motd",4)==0) {
401                         tok=strtok(buf,sep);
402                         motd=strdup(strtok(NULL,sep));
403                         continue;
404                 } else {
405                         do_command(0,buf);
406                 }
407                 /* Next command, please. */
408         }
409         fclose(fd);
410         syslog(LOG_EMERG,"Done with %s",fname);
411 }
412
413 void
414 do_command(int shell, char *cmdline)
415 {
416         char *tok,*c,*sep=" \t";
417         char **av;
418         struct command *x;
419         int found,len;
420         int ac,i,f,res;
421         int bg=0;
422         pid_t pid;
423
424         len=strlen(cmdline);
425         if(cmdline[len-1]=='&') {
426                 bg++;
427                 cmdline[len-1]='\0';
428                 len--;
429         } else bg=0;
430         tok=strtok(cmdline,sep);
431         x=bltins;
432         found=0;
433         while(x->cmd!=NULL) {
434                 if(strcmp(x->cmd,tok)==0) {
435                         found++;
436                         break;
437                 }
438                 x++;
439         }
440         if(found) {
441                 tok=cmdline+strlen(x->cmd)+1;
442                 while(*tok && isblank(*tok) && (tok<(cmdline+len))) tok++;
443                 if(*tok==NULL) tok=NULL;
444                 x->func(tok);
445                 return;
446         }
447         ac=0;
448         av=(char **)calloc(((len+1)/2+1),sizeof(char *));
449         av[ac++]=tok;
450         while((av[ac++]=strtok(NULL,sep))!=NULL)
451                 continue;
452         switch((pid=fork())) {
453         case 0:
454                 if(shell) {
455                         signal(SIGINT,SIG_DFL);
456                         signal(SIGQUIT,SIG_DFL);
457                         signal(SIGTERM,SIG_DFL);
458                         signal(SIGHUP,SIG_DFL);
459                 } else {
460                         close(0);
461                         close(1);
462                         close(2);
463                         f=open(_PATH_CONSOLE,O_RDWR);
464                         dup2(f,0);
465                         dup2(f,1);
466                         dup2(f,2);
467                         if(f>2) close(f);
468                 }
469                 if(bg) {
470                         if(daemon(0,0)) {
471                                 printf("do_command(%s): failed to run bg: %s\n",
472                                 av[0],strerror(errno));
473                                 _exit(100);
474                         }
475                 }
476                 execvp(av[0],av);
477                 /* Something went wrong... */
478                 printf("do_command(%s): %s\n",av[0],strerror(errno));
479                 _exit(100);
480                 break;
481         case -1:
482                 printf("do_command(): %s\n",strerror(errno));
483                 break;
484         default:
485                 while(waitpid(pid,&res,0)!=pid) continue;
486                 if(WEXITSTATUS(res)) {
487                         printf("do_command(%s): exit code=%d\n",
488                                 av[0],WEXITSTATUS(res));
489                 }
490                 break;
491         }
492         free(av);
493         return;
494 }
495
496 /*
497  * This is the user interface. This routine gets executed on each
498  * virtual console serviced by init.
499  *
500  * It works as normal shell does - for each external command it forks
501  * and execs, for each internal command just executes a function.
502  */
503
504 int
505 shell(int argc, char **argv)
506 {
507         char buf[BUFSIZE];
508         char *prompt=" # ";
509         int fd;
510         int res;
511         pid_t mypid;
512
513         if(motd!=NULL) {
514                 if((fd=open(motd,O_RDONLY))!=-1) {
515                         do {
516                                 res=read(fd,buf,BUFSIZE);
517                                 res=write(1,buf,res);
518                         } while(res>0);
519                         close(fd);
520                 }
521         }
522
523         printf("\n\n+=========================================================+\n");
524         printf("| Built-in shell() (enter '?' for short help on commands) |\n");
525         printf("+=========================================================+\n\n");
526         getcwd(cwd,BUFSIZE);
527         mypid=getpid();
528         signal(SIGINT,shell_sig);
529         signal(SIGQUIT,shell_sig);
530         signal(SIGTERM,shell_sig);
531         while(!feof(stdin)) {
532                 memset(buf,0,BUFSIZE);
533                 printf("(%d)%s%s",mypid,cwd,prompt);
534                 fflush(stdout);
535                 if(fgets(buf,BUFSIZE-1,stdin)==NULL) continue;
536                 buf[strlen(buf)-1]='\0';
537                 if(strlen(buf)==0) continue;
538                 do_command(1,buf);
539         }
540         return(0);
541 }
542
543 /*
544  * Stub for executing some external program on a console. This is called
545  * from previously forked copy of our process, so that exec is ok.
546  */
547 int
548 external_cmd(int argc, char **argv)
549 {
550         execvp(argv[0],argv);
551 }
552
553 /*
554  * Acquire vty and properly attach ourselves to it.
555  * Also, build basic environment for running user interface.
556  */
557
558 int
559 start_session(int vty, int argc, char **argv)
560 {
561         int fd;
562         char *t;
563
564         close(0);
565         close(1);
566         close(2);
567         revoke(ttys[vty].tty);
568         fd=open(ttys[vty].tty,O_RDWR);
569         dup2(fd,0);
570         dup2(fd,1);
571         dup2(fd,2);
572         if(fd>2) close(fd);
573         login_tty(fd);
574         setpgid(0,getpid());
575         putenv("TERM=xterm");
576         putenv("HOME=/");
577         putenv("PATH=/stand:/bin:/usr/bin:/sbin:.");
578         signal(SIGHUP,SIG_DFL);
579         signal(SIGINT,SIG_DFL);
580         signal(SIGQUIT,SIG_DFL);
581         signal(SIGTERM,SIG_DFL);
582         chdir("/");
583         t=(char *)(rindex(ttys[vty].tty,'/')+1);
584         printf("\n\n\nStarting session on %s.\n",t);
585         ttys[vty].func(argc,argv);
586         _exit(0);
587 }
588
589 /*
590  * Execute system startup script /etc/rc
591  *
592  * (Of course if you don't like it - I don't - you can run anything you
593  * want here. Perhaps it would be useful just to read some config DB and
594  * do these things ourselves, avoiding forking lots of shells and scripts.)
595  */
596
597 /* If OINIT_RC is defined, oinit will use it's own configuration file, 
598  * /etc/oinit.rc. It's format is described below. Otherwise, it will use
599  * normal /etc/rc interpreted by Bourne shell.
600  */
601 #ifndef OINIT_RC
602 #ifndef SH_NAME
603 #define SH_NAME "-sh"
604 #endif
605 #ifndef SH_PATH
606 #define SH_PATH _PATH_BSHELL
607 #endif
608 #ifndef SH_ARG
609 #define SH_ARG  "/etc/rc"
610 #endif
611 void
612 runcom()
613 {
614         char *argv[3];
615         pid_t pid;
616         int st;
617         int fd;
618
619         if((pid=fork())==0) {
620                 /* child */
621                 close(0);
622                 close(1);
623                 close(2);
624                 fd=open(_PATH_CONSOLE,O_RDWR);
625                 dup2(fd,0);
626                 dup2(fd,1);
627                 dup2(fd,2);
628                 if(fd>2) close(fd);
629                 argv[0]=SH_NAME;
630                 argv[1]=SH_ARG;
631                 argv[2]=0;
632                 execvp(SH_PATH,argv);
633                 printf("runcom(): %s\n",strerror(errno));
634                 _exit(1);
635         }
636         /* Wait for child to exit */
637         while(pid!=waitpid(pid,(int *)0,0)) continue;
638         return;
639 }
640 #else
641 /* Alternative /etc/rc - default is /etc/oinit.rc. Its format is as follows:
642  * - each empty line or line beginning with a '#' is discarded
643  * - any other line must contain a keyword, or a (nonblocking) command to run.
644  *
645  * Thus far, the following keywords are defined:
646  * ncons <number>       number of virtual consoles to open
647  * motd <pathname>      full path to motd file
648  *
649  * Examples of commands to run:
650  *
651  * ifconfig lo0 inet 127.0.0.1 netmask 255.0.0.0
652  * ifconfig ed0 inet 148.81.168.10 netmask 255.255.255.0
653  * kbdcontrol -l /usr/share/syscons/my_map.kbd
654  */
655 void
656 runcom(char *fname)
657 {
658         int fd;
659
660         close(0);
661         close(1);
662         close(2);
663         fd=open(_PATH_CONSOLE,O_RDWR);
664         dup2(fd,0);
665         dup2(fd,1);
666         dup2(fd,2);
667         if(fd>2) close(fd);
668         sourcer(fname);
669 }
670 #endif
671
672 int
673 run_multi()
674 {
675         int i,j;
676         pid_t pid;
677         int found;
678
679         /* Run /etc/rc if not in single user */
680 #ifndef OINIT_RC
681         if(prevtrans==SINGLE) runcom();
682 #else
683         if(prevtrans==SINGLE) runcom(OINIT_RC);
684 #endif
685         if(transition!=MULTI) return(-1);
686
687         syslog(LOG_EMERG,"*** Starting multi-user mode ***");
688
689         /* Fork shell interface for each console */
690         for(i=0;i<ncons;i++) {
691                 if(ttys[i].pid==0) {
692                         switch(pid=fork()) {
693                         case 0:
694                                 start_session(i,0,NULL);
695                                 break;
696                         case -1:
697                                 printf("%s: %s\n",progname,strerror(errno));
698                                 break;
699                         default:
700                                 ttys[i].pid=pid;
701                                 break;
702                         }
703                 }
704         }
705         /* Initialize any other services we'll use - most probably this will
706          * be a 'telnet' service (some day...).
707          */
708         /* */
709
710         /* Emulate multi-user */
711         while(transition==MULTI) {
712                 /* XXX Modify this to allow for checking for the input on
713                  * XXX listening sockets, and forking a 'telnet' service.
714                  */
715                 /* */
716
717                 /* Wait for any process to exit */
718                 pid=waitpid(-1,(int *)0,0);
719                 if(pid==-1) continue;
720                 found=0;
721                 j=-1;
722                 /* search if it's one of our sessions */
723                 for(i=0;i<ncons;i++) {
724                         if(ttys[i].pid==pid) {
725                                 found++;
726                                 j=i;
727                                 ttys[j].pid=0;
728                                 break;
729                         }
730                 }
731                 if(!found) {
732                         /* Just collect the process's status */
733                         continue;
734                 } else {
735                         /* restart shell() on a console, if it died */
736                         if(transition!=MULTI) return(0);
737                         switch(pid=fork()) {
738                         case 0:
739                                 sleep(1);
740                                 start_session(j,0,NULL);
741                                 break;
742                         case -1:
743                                 printf("%s: %s\n",progname,strerror(errno));
744                                 break;
745                         default:
746                                 ttys[j].pid=pid;
747                                 break;
748                         }
749                 }
750         }
751 }
752
753 int clang;
754
755 void
756 kill_timer(int sig)
757 {
758         clang=1;
759 }
760
761 kill_ttys()
762 {
763 }
764
765 /*
766  * Start a shell on ttyv0 (i.e. the console).
767  */
768
769 int
770 run_single()
771 {
772         int i;
773         pid_t pid,wpid;
774         static int sigs[2]={SIGTERM,SIGKILL};
775
776         syslog(LOG_EMERG,"*** Starting single-user mode ***");
777         /* Kill all existing sessions */
778         syslog(LOG_EMERG,"Killing all existing sessions...");
779         for(i=0;i<MAX_CONS;i++) {
780                 kill(ttys[i].pid,SIGHUP);
781                 ttys[i].pid=0;
782         }
783         for(i=0;i<2;i++) {
784                 if(kill(-1,sigs[i])==-1 && errno==ESRCH) break;
785                 clang=0;
786                 alarm(10);
787                 do {
788                         pid=waitpid(-1,(int *)0,WUNTRACED);
789                         if(errno==EINTR) continue;
790                         else break;
791                 } while (clang==0);
792         }
793         if(errno!=ECHILD) {
794                 syslog(LOG_EMERG,"Some processes would not die; ps -axl advised");
795         }
796         /* Single-user */
797         switch(pid=fork()) {
798         case 0:
799                 start_session(0,0,NULL);
800                 break;
801         case -1:
802                 printf("%s: %s\n",progname,strerror(errno));
803                 printf("The system is seriously hosed. I'm dying...\n");
804                 transition=DEATH;
805                 return(-1);
806                 break;
807         default:
808                 do {
809                         wpid=waitpid(pid,(int *)0,WUNTRACED);
810                 } while(wpid!=pid && transition==SINGLE);
811                 if(transition!=DEATH) {
812                         prevtrans=transition;
813                         transition=MULTI;
814                 }
815                 break;
816         }
817         return(0);
818 }
819
820 /*
821  * Transition handler - installed as signal handler.
822  */
823
824 void
825 transition_handler(int sig)
826 {
827
828         switch(sig) {
829         case SIGHUP:
830         case SIGTERM:
831                 prevtrans=transition;
832                 transition=SINGLE;
833                 syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]);
834                 if(prevtrans!=transition) longjmp(machine,sig);
835                 break;
836         case SIGINT:
837         case SIGQUIT:
838                 prevtrans=transition;
839                 transition=DEATH;
840                 syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]);
841                 if(prevtrans!=transition) longjmp(machine,sig);
842                 break;
843         default:
844                 syslog(LOG_EMERG,"pid=%d sig=%s (ignored)\n",getpid(),sys_siglist[sig]);
845                 break;
846         }
847 }
848
849 /*
850  * Change system state appropriately to the signals
851  */
852
853 int
854 transition_machine()
855 {
856         int i;
857
858         while(transition!=DEATH) {
859                 switch(transition) {
860                 case MULTI:
861                         run_multi();
862                         break;
863                 case SINGLE:
864                         run_single();
865                         break;
866                 }
867         }
868         syslog(LOG_EMERG,"Killing all existing sessions...");
869         /* Kill all sessions */
870         kill(-1,SIGKILL);
871         /* Be nice and wait for them */
872         while(waitpid(-1,(int *)0,WNOHANG|WUNTRACED)>0) continue;
873         unmount("/",0);
874         reboot(RB_AUTOBOOT);
875         /* NOTREACHED */
876 }
877
878 int
879 main(int argc, char **argv)
880 {
881         int devfs=0,c,i;
882
883         /* These are copied from real init(8) */
884         if(getuid()!=0)
885                 errx(1,"%s",strerror(EPERM));
886         openlog("init",LOG_CONS|LOG_ODELAY,LOG_AUTH);
887         if(setsid()<0)
888                 warn("initial setsid() failed");
889         if(setlogin("root")<0)
890                 warn("setlogin() failed");
891
892         close(0);
893         close(1);
894         close(2);
895         chdir("/");
896
897         progname=rindex(argv[0],'/');
898         if(progname==NULL) {
899                 progname=argv[0];
900         } else progname++;
901
902         transition=MULTI;
903
904         /* We must recognize the same options as real init does */
905         while((c=getopt(argc,argv,"dsf"))!=-1) {
906                 switch(c) {
907                 case 'd':
908                         devfs=1;
909                         break;
910                 case 's':
911                         transition=SINGLE;
912                         break;
913                 case 'f':
914                         break;
915                 default:
916                         printf("%s: unrecognized flag '-%c'\n",progname,c);
917                         break;
918                 }
919         }
920         if(devfs)
921                 mount("devfs",_PATH_DEV,MNT_NOEXEC|MNT_RDONLY,0);
922
923         /* Fill in the sess structures. */
924         /* XXX Really, should be filled based upon config file. */
925         for(i=0;i<MAX_CONS;i++) {
926                 if(i==0) {
927                         sprintf(ttys[i].tty,_PATH_CONSOLE);
928                 } else {
929                         sprintf(ttys[i].tty,"%sv%c",_PATH_TTY,vty[i]);
930                 }
931                 ttys[i].pid=0;
932                 ttys[i].func=shell;
933         }
934
935         getcwd(cwd,BUFSIZE);
936
937         signal(SIGINT,transition_handler);
938         signal(SIGQUIT,transition_handler);
939         signal(SIGTERM,transition_handler);
940         signal(SIGHUP,transition_handler);
941         signal(SIGALRM,kill_timer);
942
943         setjmp(machine);
944         transition_machine(transition);
945         /* NOTREACHED */
946         exit(100);
947 }