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