home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / pdksh-4.9-src.tgz / tar.out / contrib / pdksh / sh / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-28  |  10.1 KB  |  520 lines

  1. /*
  2.  * startup, main loop, enviroments and error handling
  3.  */
  4.  
  5. #ifndef lint
  6. static char *RCSid = "$Id: main.c,v 1.8 93/05/05 21:16:52 sjg Exp $";
  7. #endif
  8.  
  9. #define    EXTERN                /* define EXTERNs in sh.h */
  10.  
  11. #include "stdh.h"
  12. #include <unistd.h>
  13. #include <fcntl.h>
  14. #include <signal.h>
  15. #include <errno.h>
  16. #include <setjmp.h>
  17. #include <time.h>
  18. #include "sh.h"
  19.  
  20. #if !defined(HAVE_REMOVE) && !defined(remove)
  21. #define remove(x)    unlink(x)
  22. #endif
  23.  
  24. /*
  25.  * global data
  26.  */
  27.  
  28. Area    aperm;
  29.  
  30. static    void    reclaim ARGS((void));
  31.  
  32. /*
  33.  * shell initialization
  34.  */
  35.  
  36. static    char    initifs [] = "IFS= \t\n"; /* must be R/W */
  37.  
  38. static    const    char   initsubs [] = 
  39. #ifdef sun                /* sun's don't have a real /bin */
  40.   "${SHELL:=/bin/sh} ${PATH:=/usr/bin:/usr/ucb:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> } ${PS3:=#? } ${MAILCHECK:=600}";
  41. #else
  42. #ifdef __amigaos__
  43.   "${SHELL:=/bin/sh} ${PATH:=.:/bin:/c} ${HOME:=/ram} ${PS1:=$ } ${PS2:=> } ${PS3:=#? } ${MAILCHECK:=600}";
  44. #else
  45.   "${SHELL:=/bin/sh} ${PATH:=/bin:/usr/bin:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> } ${PS3:=#? } ${MAILCHECK:=600}";
  46. #endif
  47. #endif
  48.  
  49. static    const    char *initcoms [] = {
  50.     "cd", ".", NULL,        /* set up $PWD */
  51.     "typeset", "-x", "SHELL", "PATH", "HOME", NULL,
  52.     "typeset", "-r", "PWD", "OLDPWD", NULL,
  53.     "typeset", "-i", "SECONDS=0", "OPTIND=1", NULL,
  54.     "alias",
  55.       "integer=typeset -i", "pwd=print -r \"$PWD\"",
  56.       "history=fc -l", "r=fc -e -", "nohup=nohup ",
  57.       "login=exec login", "newgrp=exec newgrp",
  58.       "type=whence -v", "functions=typeset -f",
  59.       "true=:", "false=let", "[=\\[",
  60. #ifdef JOBS
  61.       "suspend=kill -STOP $$",
  62. #endif
  63.       NULL,
  64.  
  65.     
  66.     NULL
  67. };
  68.  
  69. #ifdef USE_TRACE
  70. /*
  71.  * use SIGUSR1 to bump up Trace_level
  72.  * use SIGUSR2 to clear Trace_level
  73.  */
  74. void
  75. set_TraceLev(sig)
  76.   int sig;
  77. {
  78.   switch(sig)
  79.   {
  80.   case SIGUSR1:
  81.     Trace_level++;
  82.     break;
  83.   case SIGUSR2:
  84.     Trace_level = 0;
  85.     break;
  86.   }
  87. #if defined(_SYSV) && !defined(USE_SIGACT)
  88.   if (sig > 0)
  89.     (void) signal(sig, set_TraceLev);
  90. #endif
  91.   return;
  92. }
  93. #endif
  94.  
  95. main(argc, argv, envp)
  96.     int argc;
  97.     register char **argv;
  98.     char **envp;
  99. {
  100.     register int i;
  101.     register char *arg;
  102.     int cflag = 0, qflag = 0, fflag = 0;
  103.     int argi;
  104.     char *name;
  105.     register Source *s;
  106.     register struct block *l = &globals;
  107.     register char **wp0, **wp;
  108.     extern char ksh_version [];
  109.     extern time_t time();
  110.  
  111. #ifdef USE_SIGACT
  112.     sigemptyset(&Sigact.sa_mask);
  113.     sigemptyset(&Sigact_dfl.sa_mask);
  114.     sigemptyset(&Sigact_ign.sa_mask);
  115.     sigemptyset(&Sigact_trap.sa_mask);
  116.     Sigact.sa_flags = 0;
  117.     Sigact_dfl.sa_flags = 0;
  118.     Sigact_ign.sa_flags = 0;
  119.     Sigact_trap.sa_flags = 0;
  120.     Sigact_dfl.sa_handler = SIG_DFL;
  121.     Sigact_ign.sa_handler = SIG_IGN;
  122.     Sigact_trap.sa_handler = trapsig;
  123. #endif
  124.     ainit(&aperm);        /* initialize permanent Area */
  125.  
  126.     /* set up base enviroment */
  127.     e.type = E_NONE;
  128.     ainit(&e.area);
  129.     e.loc = l;
  130.     e.savefd = NULL;
  131.     e.oenv = NULL;
  132.  
  133.     initctypes();
  134.  
  135.     /* open file streams for fd's 0,1,2 */
  136.     fopenshf(0);    fopenshf(1);    fopenshf(2);
  137.  
  138.     /* set up variable and command dictionaries */
  139.     newblock();        /* set up global l->vars and l->funs */
  140.     tinit(&commands, APERM);
  141.     tinit(&builtins, APERM);
  142.     tinit(&lexicals, APERM);
  143.     tinit(&homedirs, APERM);
  144.  
  145.     init_histvec();
  146.     
  147. #ifdef __amigaos__
  148.     /* there's a bug here that doesn't set the special meaning of
  149.        PATH if it's not already in the environment. Since it's pretty
  150.        nasty to get this right (local stuff in var.c..), I'll `import'
  151.        the default before actually handling the environment */
  152.     import ("PATH=.:/bin:/c");
  153. #endif
  154.  
  155.     /* import enviroment */
  156.     if (envp != NULL)
  157.         for (wp = envp; *wp != NULL; wp++)
  158.             import(*wp);
  159.  
  160.     kshpid = getpid();
  161.     typeset(initifs, 0, 0);    /* for security */
  162.     typeset(ksh_version, 0, 0); /* RDONLY */
  163.  
  164. #ifdef USE_TRACE
  165. #ifdef USE_SIGACT
  166.     Sigact.sa_handler = set_TraceLev;
  167.     sigaction(SIGUSR1, &Sigact, NULL);
  168.     sigaction(SIGUSR2, &Sigact, NULL);
  169. #else
  170.     (void) signal(SIGUSR1, set_TraceLev);
  171.     (void) signal(SIGUSR2, set_TraceLev);
  172. #endif
  173. #ifdef amigaos
  174.     /* I want trace support permanent in the shell, but I don't want
  175.        it to show up unless I want it to ;-) */
  176.     if (getenv ("TRACE_LEVEL"))
  177.       _TRACE(0, ("Traces enabled, main @$lx\n", main));
  178. #else
  179.     _TRACE(0, ("Traces enabled.")); /* allow _TRACE to setup */
  180. #endif
  181. #endif /* USE_TRACE */
  182.  
  183.     /* define shell keywords */
  184.     keywords();
  185.  
  186.     /* define built-in commands */
  187.     for (i = 0; shbuiltins[i].name != NULL; i++)
  188.         builtin(shbuiltins[i].name, shbuiltins[i].func);
  189.     for (i = 0; kshbuiltins[i].name != NULL; i++)
  190.         builtin(kshbuiltins[i].name, kshbuiltins[i].func);
  191.  
  192.     /* assign default shell variable values */
  193.     substitute(initsubs, 0);
  194.     setint(typeset("PPID", INTEGER, 0), (long) getppid());
  195.     typeset("PPID", RDONLY, 0);
  196.     setint(typeset("RANDOM", INTEGER, 0), (long) time((time_t *)0));
  197.     /* execute initialization statements */
  198.     for (wp0 = (char**) initcoms; *wp0 != NULL; wp0 = wp+1) {
  199.         /* copy because the alias initializers are readonly */
  200.         for (wp = wp0; *wp != NULL; wp++)
  201.             *wp = strsave(*wp, ATEMP);
  202.         shcomexec(wp0);
  203.     }
  204.     afreeall(ATEMP);
  205.  
  206.     if (geteuid() == 0)
  207.         setstr(global("PS1"), "# ");
  208.  
  209.     s = pushs(SFILE);
  210.     s->u.file = stdin;
  211.     cflag = 0;
  212.     name = *argv;
  213.  
  214.     /* what a bloody mess */
  215.     if ((argi = 1) < argc) {
  216.         if (argv[argi][0] == '-' && argv[argi][1] != '\0') {
  217.             for (arg = argv[argi++]+1; *arg; arg++) {
  218.                 switch (*arg) {
  219.                   case 'c':
  220.                     cflag = 1;
  221.                     if (argi < argc) {
  222.                         s->type = SSTRING;
  223.                         s->str = argv[argi++];
  224.                     }
  225.                     break;
  226.     
  227.                   case 'q':
  228.                     qflag = 1;
  229.                     break;
  230.  
  231.                   default:
  232.                     if (*arg>='a' && *arg<='z')
  233.                         flag[FLAG(*arg)]++;
  234.                 }
  235.             }
  236.         }
  237.         if (s->type == SFILE && argi < argc && !flag[FSTDIN]) {
  238.             s->file = name = argv[argi++];
  239.             if ((s->u.file = fopen(name, "r")) == NULL)
  240.                 errorf("%s: cannot open\n", name);
  241.             fflag = 1;
  242.             fileno(s->u.file) = savefd(fileno(s->u.file));
  243.             setvbuf(s->u.file, (char *)NULL, _IOFBF, BUFSIZ);
  244.         }
  245.     }
  246.  
  247.     if (s->type == SFILE) {
  248.         if (fileno(s->u.file) == 0)
  249.             flag[FSTDIN] = 1;
  250.         if (isatty(0) && isatty(1) && !cflag && !fflag)
  251.             flag[FTALKING] = 1;
  252.         if (flag[FTALKING] && flag[FSTDIN])
  253.             s->type = STTY;
  254.     }
  255.     if (s->type == STTY) {
  256.         ttyfd = fcntl(0, F_DUPFD, FDBASE);
  257.         (void) fd_clexec(ttyfd);
  258. #ifdef EMACS
  259.           x_init_emacs();
  260. #endif
  261.     }
  262.  
  263.     /* initialize job control */
  264.     j_init();
  265.  
  266.     if (!qflag)
  267.         ignoresig(SIGQUIT);
  268.  
  269.     l->argv = &argv[argi - 1];
  270.     l->argc = argc - argi;
  271.     l->argv[0] = name;
  272.     resetopts();
  273.  
  274.     if (name[0] == '-' ||
  275.         ((arg = strrchr(name, '/')) && *++arg == '-')) {
  276.         flag[FTALKING] = 1;
  277.         (void) include("/etc/profile");
  278.         (void) include(".profile");
  279.     }
  280.     /*
  281.      * do this after reading *profile but before
  282.      * reading $ENV if any.
  283.      */
  284. #if defined(EMACS) || defined(VI)
  285.     if (flag[FTALKING])
  286.       init_editmode();
  287. #endif
  288.  
  289.     /* include $ENV */
  290.     arg = substitute(strval(global("ENV")), DOTILDE);
  291.     if (*arg != '\0')
  292.         (void) include(arg);
  293.  
  294.     if (flag[FTALKING])
  295.     {
  296. #ifdef USE_SIGACT
  297.       sigaction(SIGTERM, &Sigact_trap, NULL);
  298. #else
  299.       signal(SIGTERM, trapsig);
  300. #endif
  301.       ignoresig(SIGINT);
  302.     } else
  303.       flag[FHASHALL] = 1;
  304.  
  305. #ifdef JOBS            /* todo: could go before includes? */
  306.     if (s->type == STTY) {
  307.         flag[FMONITOR] = 1;
  308.         j_change();
  309.     }
  310. #endif
  311.     if (flag[FTALKING])
  312.     {
  313.       hist_init(s);
  314.     }
  315.     argc = shell(s);
  316.     leave(argc);
  317.     return 0;
  318. }
  319.  
  320. int
  321. include(name)
  322.     register char *name;
  323. {
  324.     register FILE *f;
  325.     register Source *s;
  326.  
  327.     if (strcmp(name, "-") != 0) {
  328.         f = fopen(name, "r");
  329.         if (f == NULL)
  330.             return 0;
  331.         /* todo: the savefd doesn't get popped */
  332.         fileno(f) = savefd(fileno(f)); /* questionable */
  333.         setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  334.     } else
  335.         f = stdin;
  336.     s = pushs(SFILE);
  337.     s->u.file = f;
  338.     s->file = name;
  339.     /*return*/ shell(s);
  340.     if (f != stdin)
  341.         fclose(f);
  342.     return 1;
  343. }
  344.  
  345. int
  346. command(comm)
  347.     register char *comm;
  348. {
  349.     register Source *s;
  350.  
  351.     s = pushs(SSTRING);
  352.     s->str = comm;
  353.     return shell(s);
  354. }
  355.  
  356. /*
  357.  * run the commands from the input source, returning status.
  358.  */
  359. int
  360. shell(s)
  361.     Source *s;        /* input source */
  362. {
  363.     struct op *t;
  364.     volatile int attempts = 13;
  365.     volatile int wastty;
  366.     volatile int reading = 0;
  367.     extern void mcheck();
  368.  
  369.     newenv(E_PARSE);
  370.     e.interactive = 1;
  371.     exstat = 0;
  372.     if (setjmp(e.jbuf)) {
  373.         /*shellf("<unwind>");*/
  374.         if (trap)    /* pending SIGINT */
  375.             shellf("\n");
  376.         if (reading && s->type == STTY && s->line)
  377.             s->line--;
  378.         sigtraps[SIGINT].set = 0;
  379.     }
  380.  
  381.     while (1) {
  382.         if (trap)
  383.             runtraps();
  384.         if (flag[FTALKING])
  385.         {
  386. #ifdef USE_SIGACT
  387.           sigaction(SIGINT, &Sigact_trap, NULL);
  388. #else
  389.           signal(SIGINT, trapsig);
  390. #endif
  391.         }
  392.  
  393.         if (s->next == NULL)
  394.             s->echo = flag[FVERBOSE];
  395.  
  396.         j_notify();
  397.  
  398.         if ((wastty = (s->type == STTY)) || s->type == SHIST) {
  399.             prompt = substitute(strval(global("PS1")), 0);
  400.             mcheck();
  401.         }
  402.  
  403.         reading = 1;
  404.         t = compile(s);
  405.         reading = 0;
  406.         j_reap();
  407.         if (t != NULL && t->type == TEOF)
  408.             if (wastty && flag[FIGNEOF] && --attempts > 0) {
  409.                 shellf("Use `exit'\n");
  410.                 s->type = STTY;
  411.                 continue;
  412.             }
  413.             else
  414.                 break;
  415.         flushshf(2);    /* flush -v output */
  416.  
  417.         if (!flag[FNOEXEC] || s->type == STTY)
  418.             execute(t, 0);
  419.  
  420.         reclaim();
  421.     }
  422.     /* Error: */
  423.     quitenv();
  424.     return exstat;
  425. }
  426.  
  427. void
  428. leave(rv)
  429.     int rv;
  430. {
  431.     if (e.type == E_TCOM && e.oenv != NULL)    /* exec'd command */
  432.         unwind();
  433.     runtrap(&sigtraps[0]);
  434.     if (flag[FTALKING])
  435.     {
  436.       hist_finish();
  437.     }
  438.     j_exit();
  439.     exit(rv);
  440.     /* NOTREACHED */
  441. }
  442.  
  443. error()
  444. {
  445.     if (flag[FERREXIT] || !flag[FTALKING])
  446.         leave(1);
  447.     unwind();
  448. }
  449.  
  450. /* return to closest error handler or shell(), exit if none found */
  451. unwind()
  452. {
  453.     while (1)
  454.         switch (e.type) {
  455.           case E_NONE:
  456.             leave(1);
  457.             /* NOTREACHED */
  458.           case E_PARSE:
  459.             longjmp(e.jbuf, 1);
  460.             /* NOTREACHED */
  461.           case E_ERRH:
  462.             longjmp(e.jbuf, 1);
  463.             /* NOTREACHED */
  464.           default:
  465.             quitenv();
  466.             break;
  467.         }
  468. }
  469.  
  470. newenv(type)
  471. {
  472.     register struct env *ep;
  473.  
  474.     ep = (struct env *) alloc(sizeof(*ep), ATEMP);
  475.     *ep = e;
  476.     ainit(&e.area);
  477.     e.type = type;
  478.     e.oenv = ep;
  479.     e.savefd = NULL;
  480.     e.temps = NULL;
  481. }
  482.  
  483. quitenv()
  484. {
  485.     register struct env *ep;
  486.     register int fd;
  487.  
  488.     if ((ep = e.oenv) == NULL)
  489.         exit(exstat);    /* exit child */
  490.     if (e.loc != ep->loc)
  491.         popblock();
  492.     if (e.savefd != NULL)
  493.         for (fd = 0; fd < NUFILE; fd++)
  494.             restfd(fd, e.savefd[fd]);
  495.     reclaim();
  496.     e = *ep;
  497.     afree(ep, ATEMP);
  498. }
  499.  
  500. /* remove temp files and free ATEMP Area */
  501. static void
  502. reclaim()
  503. {
  504.     register struct temp *tp;
  505.  
  506.     for (tp = e.temps; tp != NULL; tp = tp->next)
  507.         remove(tp->name);
  508.     e.temps = NULL;
  509.     afreeall(&e.area);
  510. }
  511.  
  512. void
  513. aerror(ap, msg)
  514.     Area *ap;
  515.     const char *msg;
  516. {
  517.     errorf("alloc internal error: %s\n", msg);
  518. }
  519.  
  520.