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
cd(char * path)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
pwd(char * dummy)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
xit(char * dummy)155 xit(char *dummy)
156 {
157 _exit(0);
158 }
159
160 /*
161 * Built-in 'echo' handler
162 */
163 int
echo(char * args)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
set(char * var)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
env(char * dummy)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
unset(char * var)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
help(char * cmd)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
shell_sig(int sig)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
sourcer(char * fname)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
do_command(int shell,char * cmdline)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
shell(int argc,char ** argv)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
external_cmd(int argc,char ** argv)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
start_session(int vty,int argc,char ** argv)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
runcom()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
runcom(char * fname)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
run_multi()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
kill_timer(int sig)756 kill_timer(int sig)
757 {
758 clang=1;
759 }
760
kill_ttys()761 kill_ttys()
762 {
763 }
764
765 /*
766 * Start a shell on ttyv0 (i.e. the console).
767 */
768
769 int
run_single()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
transition_handler(int sig)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
transition_machine()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
main(int argc,char ** argv)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 }
948