Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*  $NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $   */
  2.  
  3. /*-
  4.  * Copyright (c) 1991, 1993
  5.  *  The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Kenneth Almquist.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *  This product includes software developed by the University of
  21.  *  California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #include <sys/cdefs.h>
  40. #ifndef lint
  41. __COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\
  42.     The Regents of the University of California.  All rights reserved.\n");
  43. #endif /* not lint */
  44.  
  45. #ifndef lint
  46. #if 0
  47. static char sccsid[] = "@(#)main.c  8.7 (Berkeley) 7/19/95";
  48. #else
  49. __RCSID("$NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $");
  50. #endif
  51. #endif /* not lint */
  52.  
  53. #include <errno.h>
  54. #include <stdio.h>
  55. #include <signal.h>
  56. #include <sys/stat.h>
  57. #include <unistd.h>
  58. #include <fcntl.h>
  59.  
  60.  
  61. #include "shell.h"
  62. #include "main.h"
  63. #include "mail.h"
  64. #include "options.h"
  65. #include "output.h"
  66. #include "parser.h"
  67. #include "nodes.h"
  68. #include "expand.h"
  69. #include "eval.h"
  70. #include "jobs.h"
  71. #include "input.h"
  72. #include "trap.h"
  73. #include "var.h"
  74. #include "show.h"
  75. #include "memalloc.h"
  76. #include "error.h"
  77. #include "init.h"
  78. #include "mystring.h"
  79. #include "exec.h"
  80. #include "cd.h"
  81.  
  82. #ifdef HETIO
  83. #include "hetio.h"
  84. #endif
  85.  
  86. #define PROFILE 0
  87.  
  88. int rootpid;
  89. int rootshell;
  90. STATIC union node *curcmd;
  91. STATIC union node *prevcmd;
  92. #if PROFILE
  93. short profile_buf[16384];
  94. extern int etext();
  95. #endif
  96.  
  97. STATIC void read_profile (const char *);
  98. STATIC char *find_dot_file (char *);
  99. int main (int, char **);
  100.  
  101. /*
  102.  * Main routine.  We initialize things, parse the arguments, execute
  103.  * profiles if we're a login shell, and then call cmdloop to execute
  104.  * commands.  The setjmp call sets up the location to jump to when an
  105.  * exception occurs.  When an exception occurs the variable "state"
  106.  * is used to figure out how far we had gotten.
  107.  */
  108.  
  109. int
  110. main(argc, argv)
  111.     int argc;
  112.     char **argv;
  113. {
  114.     struct jmploc jmploc;
  115.     struct stackmark smark;
  116.     volatile int state;
  117.     char *shinit;
  118.     int priviliged;
  119.  
  120.     priviliged = getuid() != geteuid() || getgid() != getegid();
  121.  
  122. #if PROFILE
  123.     monitor(4, etext, profile_buf, sizeof profile_buf, 50);
  124. #endif
  125. #if defined(linux) || defined(__GNU__)
  126.     signal(SIGCHLD, SIG_DFL);
  127. #endif
  128.     state = 0;
  129.     if (setjmp(jmploc.loc)) {
  130.         /*
  131.          * When a shell procedure is executed, we raise the
  132.          * exception EXSHELLPROC to clean up before executing
  133.          * the shell procedure.
  134.          */
  135.         switch (exception) {
  136.         case EXSHELLPROC:
  137.             rootpid = getpid();
  138.             rootshell = 1;
  139.             minusc = NULL;
  140.             state = 3;
  141.             break;
  142.  
  143.         case EXEXEC:
  144.             exitstatus = exerrno;
  145.             break;
  146.  
  147.         case EXERROR:
  148.             exitstatus = 2;
  149.             break;
  150.  
  151.         default:
  152.             break;
  153.         }
  154.  
  155.         if (exception != EXSHELLPROC) {
  156.             if (state == 0 || iflag == 0 || ! rootshell)
  157.                 exitshell(exitstatus);
  158.         }
  159.         reset();
  160.         if (exception == EXINT
  161. #if ATTY
  162.          && (! attyset() || equal(termval(), "emacs"))
  163. #endif
  164.          ) {
  165.             out2c('\n');
  166.             flushout(&errout);
  167.         }
  168.         popstackmark(&smark);
  169.         FORCEINTON;             /* enable interrupts */
  170.         if (state == 1)
  171.             goto state1;
  172.         else if (state == 2)
  173.             goto state2;
  174.         else if (state == 3)
  175.             goto state3;
  176.         else
  177.             goto state4;
  178.     }
  179.     handler = &jmploc;
  180. #ifdef DEBUG
  181.     opentrace();
  182.     trputs("Shell args:  ");  trargs(argv);
  183. #endif
  184.     rootpid = getpid();
  185.     rootshell = 1;
  186.     init();
  187.     setstackmark(&smark);
  188.     procargs(argc, argv);
  189.     if (argv[0] && argv[0][0] == '-') {
  190.         state = 1;
  191.         read_profile("/etc/profile");
  192. state1:
  193.         state = 2;
  194.         if (priviliged == 0)
  195.             read_profile(".profile");
  196.         else
  197.             read_profile("/etc/suid_profile");
  198.     }
  199. state2:
  200.     state = 3;
  201.     if (iflag && !priviliged) {
  202.         if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
  203.             state = 3;
  204.             read_profile(shinit);
  205.         }
  206.     }
  207. state3:
  208.     state = 4;
  209.     if (sflag == 0 || minusc) {
  210.         static int sigs[] =  {
  211.             SIGINT, SIGQUIT, SIGHUP,
  212. #ifdef SIGTSTP
  213.             SIGTSTP,
  214. #endif
  215.             SIGPIPE
  216.         };
  217. #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
  218.         int i;
  219.  
  220.         for (i = 0; i < SIGSSIZE; i++)
  221.             setsignal(sigs[i]);
  222.     }
  223.  
  224.     if (minusc)
  225.         evalstring(minusc, 0);
  226.  
  227.     if (sflag || minusc == NULL) {
  228. state4: /* XXX ??? - why isn't this before the "if" statement */
  229.         cmdloop(1);
  230.     }
  231. #if PROFILE
  232.     monitor(0);
  233. #endif
  234.     exitshell(exitstatus);
  235.     /* NOTREACHED */
  236. }
  237.  
  238.  
  239. /*
  240.  * Read and execute commands.  "Top" is nonzero for the top level command
  241.  * loop; it turns on prompting if the shell is interactive.
  242.  */
  243.  
  244. void
  245. cmdloop(top)
  246.     int top;
  247. {
  248.     union node *n;
  249.     struct stackmark smark;
  250.     int inter;
  251.     int numeof = 0;
  252.  
  253.     TRACE(("cmdloop(%d) called\n", top));
  254.     setstackmark(&smark);
  255. #ifdef HETIO
  256.     if(iflag && top)
  257.         hetio_init();
  258. #endif
  259.     for (;;) {
  260.         if (pendingsigs)
  261.             dotrap();
  262.         inter = 0;
  263.         if (iflag && top) {
  264.             inter++;
  265.             showjobs(1);
  266.             chkmail(0);
  267.             flushout(&output);
  268.         }
  269.         n = parsecmd(inter);
  270.         /* showtree(n); DEBUG */
  271.         if (n == NEOF) {
  272.             if (!top || numeof >= 50)
  273.                 break;
  274.             if (!stoppedjobs()) {
  275.                 if (!Iflag)
  276.                     break;
  277.                 out2str("\nUse \"exit\" to leave shell.\n");
  278.             }
  279.             numeof++;
  280.         } else if (n != NULL && nflag == 0) {
  281.             job_warning = (job_warning == 2) ? 1 : 0;
  282.             numeof = 0;
  283.             evaltree(n, 0);
  284.         }
  285.         popstackmark(&smark);
  286.         setstackmark(&smark);
  287.         if (evalskip == SKIPFILE) {
  288.             evalskip = 0;
  289.             break;
  290.         }
  291.     }
  292.     popstackmark(&smark);
  293. }
  294.  
  295.  
  296.  
  297. /*
  298.  * Read /etc/profile or .profile.  Return on error.
  299.  */
  300.  
  301. STATIC void
  302. read_profile(name)
  303.     const char *name;
  304. {
  305.     int fd;
  306.     int xflag_set = 0;
  307.     int vflag_set = 0;
  308.  
  309.     INTOFF;
  310.     if ((fd = open(name, O_RDONLY)) >= 0)
  311.         setinputfd(fd, 1);
  312.     INTON;
  313.     if (fd < 0)
  314.         return;
  315.     /* -q turns off -x and -v just when executing init files */
  316.     if (qflag)  {
  317.         if (xflag)
  318.             xflag = 0, xflag_set = 1;
  319.         if (vflag)
  320.             vflag = 0, vflag_set = 1;
  321.     }
  322.     cmdloop(0);
  323.     if (qflag)  {
  324.         if (xflag_set)
  325.             xflag = 1;
  326.         if (vflag_set)
  327.             vflag = 1;
  328.     }
  329.     popfile();
  330. }
  331.  
  332.  
  333.  
  334. /*
  335.  * Read a file containing shell functions.
  336.  */
  337.  
  338. void
  339. readcmdfile(name)
  340.     char *name;
  341. {
  342.     int fd;
  343.  
  344.     INTOFF;
  345.     if ((fd = open(name, O_RDONLY)) >= 0)
  346.         setinputfd(fd, 1);
  347.     else
  348.         error("Can't open %s", name);
  349.     INTON;
  350.     cmdloop(0);
  351.     popfile();
  352. }
  353.  
  354.  
  355.  
  356. /*
  357.  * Take commands from a file.  To be compatable we should do a path
  358.  * search for the file, which is necessary to find sub-commands.
  359.  */
  360.  
  361.  
  362. STATIC char *
  363. find_dot_file(basename)
  364.     char *basename;
  365. {
  366.     char *fullname;
  367.     const char *path = pathval();
  368.     struct stat statb;
  369.  
  370.     /* don't try this for absolute or relative paths */
  371.     if (strchr(basename, '/'))
  372.         return basename;
  373.  
  374.     while ((fullname = padvance(&path, basename)) != NULL) {
  375.         if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
  376.             /*
  377.              * Don't bother freeing here, since it will
  378.              * be freed by the caller.
  379.              */
  380.             return fullname;
  381.         }
  382.         stunalloc(fullname);
  383.     }
  384.  
  385.     /* not found in the PATH */
  386.     error("%s: not found", basename);
  387.     /* NOTREACHED */
  388. }
  389.  
  390. int
  391. dotcmd(argc, argv)
  392.     int argc;
  393.     char **argv;
  394. {
  395.     struct strlist *sp;
  396.     exitstatus = 0;
  397.  
  398.     for (sp = cmdenviron; sp ; sp = sp->next)
  399.         setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
  400.  
  401.     if (argc >= 2) {        /* That's what SVR2 does */
  402.         char *fullname;
  403.         struct stackmark smark;
  404.  
  405.         setstackmark(&smark);
  406.         fullname = find_dot_file(argv[1]);
  407.         setinputfile(fullname, 1);
  408.         commandname = fullname;
  409.         cmdloop(0);
  410.         popfile();
  411.         popstackmark(&smark);
  412.     }
  413.     return exitstatus;
  414. }
  415.  
  416.  
  417. int
  418. exitcmd(argc, argv)
  419.     int argc;
  420.     char **argv;
  421. {
  422.     extern int oexitstatus;
  423.  
  424.     if (stoppedjobs())
  425.         return 0;
  426.     if (argc > 1)
  427.         exitstatus = number(argv[1]);
  428.     else
  429.         exitstatus = oexitstatus;
  430.     exitshell(exitstatus);
  431.     /* NOTREACHED */
  432. }
  433.