home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / ksh48.zip / sh / main.c < prev    next >
C/C++ Source or Header  |  1993-01-12  |  11KB  |  545 lines

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