home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / pdksh-4.5.lha / pdksh-4.5 / sh / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-01  |  9.9 KB  |  513 lines

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