home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / simpleinit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-09  |  8.8 KB  |  439 lines

  1. /* simpleinit.c - poe@daimi.aau.dk */
  2. /* Version 1.21 */
  3.  
  4. #include <sys/types.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <limits.h>
  8. #include <stdio.h>
  9. #include <fcntl.h>
  10. #include <string.h>
  11. #include <signal.h>
  12. #include <pwd.h>
  13. #include <sys/file.h>
  14. #include <sys/wait.h>
  15. #include <sys/stat.h>
  16. #include <sys/sysmacros.h>
  17. #include <utmp.h>
  18. #ifdef SHADOW_PWD
  19. #include <shadow.h>
  20. #endif
  21.  
  22. #include "pathnames.h"
  23.  
  24. #define CMDSIZ 150    /* max size of a line in inittab */
  25. #define NUMCMD 30    /* max number of lines in inittab */
  26. #define NUMTOK 20    /* max number of tokens in inittab command */
  27.  
  28. #define RUN_RC
  29. #define TZFILE "/etc/TZ"
  30. char tzone[CMDSIZ];
  31. /* #define DEBUGGING */
  32.  
  33. /* Define this if you want init to ignore the termcap field in inittab for
  34.    console ttys. */
  35. /* #define SPECIAL_CONSOLE_TERM */
  36.  
  37. #define ever (;;)
  38.  
  39. struct initline {
  40.     pid_t    pid;
  41.     char    tty[10];
  42.     char    termcap[30];
  43.     char    *toks[NUMTOK];
  44.     char    line[CMDSIZ];
  45. };
  46.  
  47. struct initline inittab[NUMCMD];
  48. int numcmd;
  49. int stopped = 0;    /* are we stopped */
  50.  
  51. int do_rc();
  52. void spawn(), hup_handler(), read_inittab();
  53. void tstp_handler(), int_handler(), set_tz(), write_wtmp();
  54. int boot_single();
  55.  
  56. void err(char *s)
  57. {
  58.     int fd;
  59.     
  60.     if((fd = open("/dev/console", O_WRONLY)) < 0) return;
  61.  
  62.     write(fd, "init: ", 6);    
  63.     write(fd, s, strlen(s));
  64.     close(fd);
  65. }
  66.  
  67. void
  68. enter_single()
  69. {
  70.     pid_t pid;
  71.     int i;
  72.  
  73.     err("Booting to single user mode.\n");
  74.     if((pid = fork()) == 0) {
  75.     /* the child */
  76.     execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
  77.     err("exec of single user shell failed\n");
  78.     } else if(pid > 0) {
  79.     while(wait(&i) != pid) /* nothing */;
  80.     } else if(pid < 0) {
  81.     err("fork of single user shell failed\n");
  82.     }
  83.     unlink(_PATH_SINGLE);
  84. }
  85.  
  86. int main(int argc, char *argv[])
  87. {
  88.     int     vec,i;
  89.     pid_t    pid;
  90.  
  91. #ifdef SET_TZ
  92.     set_tz();
  93. #endif
  94.     /* 
  95.      * start up in single user mode if /etc/singleboot exists or if
  96.      * argv[1] is "single".
  97.      */
  98.     if(boot_single(0, argc, argv)) enter_single();
  99.  
  100. #ifdef RUN_RC
  101.     if(do_rc() != 0 && boot_single(1, argc, argv)) enter_single();
  102. #endif
  103.  
  104.     write_wtmp();    /* write boottime record */
  105.  
  106.     for(i = 0; i < NUMCMD; i++)
  107.         inittab[i].pid = -1;
  108.  
  109.     read_inittab();
  110.  
  111. #ifdef DEBUGGING
  112.     for(i = 0; i < numcmd; i++) {
  113.         char **p;
  114.         p = inittab[i].toks;
  115.         printf("toks= %s %s %s %s\n",p[0], p[1], p[2], p[3]);
  116.         printf("tty= %s\n", inittab[i].tty);
  117.         printf("termcap= %s\n", inittab[i].termcap);
  118.     }
  119.     exit(0);
  120. #endif
  121.     signal(SIGHUP, hup_handler);
  122.     signal(SIGTSTP, tstp_handler);
  123.     signal(SIGINT, int_handler);
  124.  
  125.     for(i = 0; i < getdtablesize(); i++) close(i);
  126.  
  127.     for(i = 0; i < numcmd; i++)
  128.         spawn(i);
  129.     
  130.     for ever {
  131.         pid = wait(&vec);
  132.  
  133.         /* clear utmp entry, and append to wtmp if possible */
  134.         {
  135.             struct utmp *ut;
  136.             int ut_fd;
  137.  
  138.             utmpname(_PATH_UTMP);
  139.             setutent();
  140.             while(ut = getutent()) {
  141.             if(ut->ut_pid == pid) {
  142.                 time(&ut->ut_time);
  143.                 memset(&ut->ut_user, 0, UT_NAMESIZE);
  144.                 memset(&ut->ut_host, 0, sizeof(ut->ut_host));
  145.                 ut->ut_type = DEAD_PROCESS;
  146.                 ut->ut_pid = 0;
  147.                 ut->ut_addr = 0;
  148.                 endutent();
  149.                 pututline(ut);
  150.                 if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
  151.                 flock(ut_fd, LOCK_EX|LOCK_NB);
  152.                 write(ut_fd, ut, sizeof(struct utmp));
  153.                 flock(ut_fd, LOCK_UN|LOCK_NB);
  154.                 close(ut_fd);
  155.                 }
  156.                 break;
  157.             }
  158.             }
  159.             endutent();
  160.         }
  161.  
  162.         for(i = 0; i < numcmd; i++) {
  163.             if(pid == inittab[i].pid || inittab[i].pid < 0) {
  164.                 if(stopped) inittab[i].pid = -1;
  165.                 else spawn(i);
  166.                 break;
  167.             }
  168.         }
  169.     }
  170. }    
  171.  
  172. #define MAXTRIES 3 /* number of tries allowed when giving the password */
  173.  
  174. /*
  175.  * return true if we should boot up in singleuser mode. If argv[i] is 
  176.  * "single" or the file /etc/singleboot exists, then singleuser mode should
  177.  * be entered. If /etc/securesingle exists ask for root password first.
  178.  */
  179. int boot_single(int singlearg, int argc, char *argv[])
  180. {
  181.     char *pass, *rootpass = NULL;
  182.     struct passwd *pwd;
  183.     int i;
  184.  
  185.     for(i = 1; i < argc; i++) {
  186.         if(argv[i] && !strcmp(argv[i], "single")) singlearg = 1;
  187.     }
  188.  
  189.     if(access(_PATH_SINGLE, 04) == 0 || singlearg) {
  190.         if(access(_PATH_SECURE, 04) == 0) {
  191.             if((pwd = getpwnam("root")) || (pwd = getpwuid(0)))
  192.               rootpass = pwd->pw_passwd;
  193.             else
  194.               return 1; /* a bad /etc/passwd should not lock out */
  195.  
  196.             for(i = 0; i < MAXTRIES; i++) {
  197.                 pass = getpass("Password: ");
  198.                 if(pass == NULL) continue;
  199.                 
  200.                 if(!strcmp(crypt(pass, rootpass), rootpass)) {
  201.                     return 1;
  202.                 }
  203.  
  204.                 puts("\nWrong password.\n");
  205.             }
  206.         } else return 1;
  207.     }
  208.     return 0;
  209. }
  210.  
  211. /*
  212.  * run /etc/rc. The environment is passed to the script, so the RC environment
  213.  * variable can be used to decide what to do. RC may be set from LILO.
  214.  */
  215. int do_rc()
  216. {
  217.     pid_t pid;
  218.     int stat;
  219.     
  220.     if((pid = fork()) == 0) {
  221.         /* the child */
  222.         char *argv[2];
  223.  
  224.         argv[0] = _PATH_BSHELL;
  225.         argv[1] = (char *)0;
  226.  
  227.         close(0);
  228.         if(open(_PATH_RC, O_RDONLY, 0) == 0) {
  229.             execv(_PATH_BSHELL, argv);
  230.             err("exec rc failed\n");
  231.             _exit(2);
  232.         }
  233.         err("open of rc file failed\n");
  234.         _exit(1);
  235.     } else if(pid > 0) {
  236.         /* parent, wait till rc process dies before spawning */
  237.         while(wait(&stat) != pid) /* nothing */;
  238.     } else if(pid < 0) {
  239.         err("fork of rc shell failed\n");
  240.     }
  241.     return WEXITSTATUS(stat);
  242. }
  243.  
  244. void spawn(int i)
  245. {
  246.     pid_t pid;
  247.     int j;
  248.     
  249.     if((pid = fork()) < 0) {
  250.         inittab[i].pid = -1;
  251.         err("fork failed\n");
  252.         return;
  253.     }
  254.     if(pid) {
  255.         /* this is the parent */
  256.         inittab[i].pid = pid;
  257.         return;
  258.     } else {
  259.         /* this is the child */
  260.         char term[40];
  261.         char tz[CMDSIZ];
  262.         char *env[3];
  263.         
  264.         setsid();
  265.         for(j = 0; j < getdtablesize(); j++)
  266.             (void) close(j);
  267.  
  268.         (void) sprintf(term, "TERM=%s", inittab[i].termcap);
  269.         env[0] = term;
  270.         env[1] = (char *)0;
  271. #ifdef SET_TZ
  272.         (void) sprintf(tz, "TZ=%s", tzone);
  273.         env[1] = tz;
  274. #endif
  275.         env[2] = (char *)0;
  276.  
  277.         execve(inittab[i].toks[0], inittab[i].toks, env);
  278.         err("exec failed\n");
  279.         sleep(5);
  280.         _exit(1);
  281.     }
  282. }
  283.  
  284. void read_inittab()
  285. {
  286.     FILE *f;
  287.     char buf[CMDSIZ];
  288.     int i,j,k;
  289.     char *ptr, *getty;
  290.     char tty[50];
  291.     struct stat stb;
  292.     char *termenv, *getenv();
  293.     
  294.     termenv = getenv("TERM");    /* set by kernel */
  295.     /* termenv = "vt100"; */
  296.             
  297.     if(!(f = fopen(_PATH_INITTAB, "r"))) {
  298.         err("cannot open inittab\n");
  299.         _exit(1);
  300.     }
  301.  
  302.     i = 0;
  303.     while(!feof(f) && i < NUMCMD - 2) {
  304.         if(fgets(buf, CMDSIZ - 1, f) == 0) break;
  305.         buf[CMDSIZ-1] = 0;
  306.  
  307.         for(k = 0; k < CMDSIZ && buf[k]; k++) {
  308.             if(buf[k] == '#') { 
  309.                 buf[k] = 0; break; 
  310.             }
  311.         }
  312.  
  313.         if(buf[0] == 0 || buf[0] == '\n') continue;
  314.  
  315.         (void) strcpy(inittab[i].line, buf);
  316.  
  317.         (void) strtok(inittab[i].line, ":");
  318.         (void) strncpy(inittab[i].tty, inittab[i].line, 10);
  319.         inittab[i].tty[9] = 0;
  320.         (void) strncpy(inittab[i].termcap,
  321.                 strtok((char *)0, ":"), 30);
  322.         inittab[i].termcap[29] = 0;
  323.  
  324.         getty = strtok((char *)0, ":");
  325.         (void) strtok(getty, " \t\n");
  326.         inittab[i].toks[0] = getty;
  327.         j = 1;
  328.         while(ptr = strtok((char *)0, " \t\n"))
  329.             inittab[i].toks[j++] = ptr;
  330.         inittab[i].toks[j] = (char *)0;
  331.  
  332. #ifdef SPECIAL_CONSOLE_TERM
  333.         /* special-case termcap for the console ttys */
  334.         (void) sprintf(tty, "/dev/%s", inittab[i].tty);
  335.         if(!termenv || stat(tty, &stb) < 0) {
  336.             err("no TERM or cannot stat tty\n");
  337.         } else {
  338.             /* is it a console tty? */
  339.             if(major(stb.st_rdev) == 4 && minor(stb.st_rdev) < 64) {
  340.                 strncpy(inittab[i].termcap, termenv, 30);
  341.                 inittab[i].termcap[29] = 0;
  342.             }
  343.         }
  344. #endif
  345.  
  346.         i++;
  347.     }
  348.     fclose(f);
  349.     numcmd = i;
  350. }
  351.  
  352. void hup_handler()
  353. {
  354.     int i,j;
  355.     int oldnum;
  356.     struct initline    savetab[NUMCMD];
  357.     int had_already;
  358.  
  359.     (void) signal(SIGHUP, SIG_IGN);
  360.  
  361.     memcpy(savetab, inittab, NUMCMD * sizeof(struct initline));
  362.     oldnum = numcmd;        
  363.     read_inittab();
  364.     
  365.     for(i = 0; i < numcmd; i++) {
  366.         had_already = 0;
  367.         for(j = 0; j < oldnum; j++) {
  368.             if(!strcmp(savetab[j].tty, inittab[i].tty)) {
  369.                 had_already = 1;
  370.                 if((inittab[i].pid = savetab[j].pid) < 0)
  371.                     spawn(i);
  372.             }
  373.         }
  374.         if(!had_already) spawn(i);
  375.     }
  376.     
  377.     (void) signal(SIGHUP, hup_handler);
  378. }
  379.  
  380. void tstp_handler()
  381. {
  382.     stopped = ~stopped;
  383.     if(!stopped) hup_handler();
  384.  
  385.     signal(SIGTSTP, tstp_handler);
  386. }
  387.  
  388. void int_handler()
  389. {
  390.     /*
  391.      * After Linux 0.96b PL1, we get a SIGINT when
  392.      * the user presses Ctrl-Alt-Del...
  393.      */
  394.  
  395.     int pid;
  396.     
  397.     sync();
  398.     sync();
  399.     if((pid = fork()) == 0) {
  400.         /* reboot properly... */
  401.         execl(_PATH_REBOOT, _PATH_REBOOT, (char *)0);
  402.         reboot(0xfee1dead, 672274793, 0x1234567);
  403.     } else if(pid < 0)
  404.         /* fork failed, try the hard way... */
  405.         reboot(0xfee1dead, 672274793, 0x1234567);
  406. }
  407.  
  408. void set_tz()
  409. {
  410.     FILE *f;
  411.     int len;
  412.  
  413.     if((f=fopen(TZFILE, "r")) == (FILE *)NULL) return;
  414.     fgets(tzone, CMDSIZ-2, f);
  415.     fclose(f);
  416.     if((len=strlen(tzone)) < 2) return;
  417.     tzone[len-1] = 0; /* get rid of the '\n' */
  418.     setenv("TZ", tzone, 0);
  419. }
  420.  
  421. void write_wtmp()
  422. {
  423.     int fd;
  424.     struct utmp ut;
  425.     
  426.     memset((char *)&ut, 0, sizeof(ut));
  427.     strcpy(ut.ut_line, "~");
  428.     memset(ut.ut_name, 0, sizeof(ut.ut_name));
  429.     time(&ut.ut_time);
  430.     ut.ut_type = BOOT_TIME;
  431.     
  432.     if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
  433.     flock(fd, LOCK_EX|LOCK_NB); /* make sure init won't hang */
  434.     write(fd, (char *)&ut, sizeof(ut));
  435.     flock(fd, LOCK_UN|LOCK_NB);
  436.     close(fd);
  437.     }
  438. }     
  439.