/release/picobsd/tinyware/oinit/oinit.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 947 lines · 731 code · 72 blank · 144 comment · 118 complexity · daab6c215de086a8d36a77672739e71f MD5 · raw file

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