oinit.c revision 272461
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1998 Andrzej Bialecki 31553Srgrimes * All rights reserved. 41863Swollman * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * 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: releng/10.1/release/picobsd/tinyware/oinit/oinit.c 199251 2009-11-13 11:32:14Z ed $ 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 70char cwd[BUFSIZE]; 71char vty[]="0123456789abcdef"; 72char *progname; 73char *motd=NULL; 74int ncons=MAX_CONS; 75int Reboot=FALSE; 76int transition=MULTI; 77int prevtrans=SINGLE; 78jmp_buf machine; 79 80char *trans[]={ "NONE", "SINGLE", "MULTI", "DEATH" }; 81 82extern char **environ; 83 84/* Struct for holding session state */ 85struct 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 */ 93struct 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 */ 102int cd(char *); 103int pwd(char *); 104int echo(char *); 105int xit(char *); 106int set(char *); 107int unset(char *); 108int env(char *); 109int help(char *); 110int sourcer(char *); 111void do_command(int shell, char *cmdline); 112void transition_handler(int); 113 114/* Table of built-in functions */ 115struct 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 */ 131int 132cd(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 */ 142int 143pwd(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 */ 154int 155xit(char *dummy) 156{ 157 _exit(0); 158} 159 160/* 161 * Built-in 'echo' handler 162 */ 163int 164echo(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 */ 272int 273set(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 */ 286int 287env(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 */ 301int 302unset(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 */ 314int 315help(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 */ 354void 355shell_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 */ 371int 372sourcer(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 413void 414do_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 504int 505shell(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 */ 547int 548external_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 558int 559start_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 611void 612runcom() 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 */ 655void 656runcom(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 672int 673run_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 753int clang; 754 755void 756kill_timer(int sig) 757{ 758 clang=1; 759} 760 761kill_ttys() 762{ 763} 764 765/* 766 * Start a shell on ttyv0 (i.e. the console). 767 */ 768 769int 770run_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 824void 825transition_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 853int 854transition_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 878int 879main(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