home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume30 / rc / part05 / fn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-30  |  6.5 KB  |  267 lines

  1. /*
  2.    fn.c: functions for adding and deleting functions from the symbol table.
  3.    Support for signal handlers is also found here.
  4. */
  5.  
  6. #include <signal.h>
  7. #include <errno.h>
  8. #include "rc.h"
  9. #include "sigmsgs.h"
  10.  
  11. static void fn_handler(int), dud_handler(int);
  12.  
  13. static bool runexit = FALSE;
  14. static Node *handlers[NUMOFSIGNALS], null;
  15. static void (*def_sigint)(int) = SIG_DFL,
  16.         (*def_sigquit)(int) = SIG_DFL,
  17.         (*def_sigterm)(int) = SIG_DFL;
  18.  
  19. /*
  20.    Set signals to default values for rc. This means that interactive
  21.    shells ignore SIGTERM, etc.
  22. */
  23.  
  24. extern void inithandler() {
  25.     int i;
  26.     null.type = nBody;
  27.     null.u[0].p = null.u[1].p = NULL;
  28.     for (i = 1; i < NUMOFSIGNALS; i++)
  29. #ifdef NOSIGCLD
  30.         if (i != SIGCLD)
  31. #endif
  32.         if (sighandlers[i] == SIG_IGN)
  33.             fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */
  34.     if (interactive || sighandlers[SIGINT] != SIG_IGN) {
  35.         def_sigint = sigint;
  36.         fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */
  37.     }
  38.     if (!dashdee) {
  39.         if (interactive || sighandlers[SIGQUIT] != SIG_IGN) {
  40.             def_sigquit = dud_handler;
  41.             fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */
  42.         }
  43.         if (interactive) {
  44.             def_sigterm = dud_handler;
  45.             fnrm("sigterm"); /* ditto for SIGTERM */
  46.         }
  47.     }
  48. }
  49.  
  50. /* only run this in a child process! resets signals to their default values */
  51.  
  52. extern void setsigdefaults(bool sysvbackground) {
  53.     int i;
  54.     /*
  55.        General housekeeping: setsigdefaults happens after fork(),
  56.        so it's a convenient place to clean up open file descriptors.
  57.        (history file, scripts, etc.)
  58.     */
  59.     closefds();
  60.     /*
  61.        Restore signals to SIG_DFL, paying close attention to
  62.        a few quirks: SIGINT, SIGQUIT and are treated specially
  63.        depending on whether we are doing v7-style backgrounding
  64.        or not; the default action for SIGINT, SIGQUIT and SIGTERM
  65.        must be set to the appropriate action; finally, care must
  66.        be taken not to set to SIG_DFL any signals which are being
  67.        ignored.
  68.     */
  69.     for (i = 1; i < NUMOFSIGNALS; i++)
  70.         if (sighandlers[i] != SIG_IGN) {
  71.             handlers[i] = NULL;
  72.             switch (i) {
  73.             case SIGINT:
  74.                 if (sysvbackground) {
  75.                     def_sigint = SIG_IGN;
  76.                     fnassign("sigint", NULL); /* ignore */
  77.                 } else {
  78.                     def_sigint = SIG_DFL;
  79.                     goto sigcommon;
  80.                 }
  81.                 break;
  82.             case SIGQUIT:
  83.                 if (sysvbackground) {
  84.                     def_sigquit = SIG_IGN;
  85.                     fnassign("sigquit", NULL); /* ignore */
  86.                 } else {
  87.                     def_sigquit = SIG_DFL;
  88.                     goto sigcommon;
  89.                 }
  90.                 break;
  91.             case SIGTERM:
  92.                 def_sigterm = SIG_DFL;
  93.                 /* FALLTHROUGH */
  94.             sigcommon:
  95.             default:
  96.                 if (sighandlers[i] != SIG_DFL) {
  97.                     rc_signal(i, SIG_DFL);
  98.                     delete_fn(signals[i].name);
  99.                 }
  100.             }
  101.         }
  102.     delete_fn("sigexit");
  103.     runexit = FALSE; /* No sigexit on subshells */
  104. }
  105.  
  106. /* rc's exit. if runexit is set, run the sigexit function. */
  107.  
  108. extern void rc_exit(int stat) {
  109.     static char *sigexit[2] = {
  110.         "sigexit",
  111.         NULL
  112.     };
  113.     if (runexit) {
  114.         runexit = FALSE;
  115.         funcall(sigexit);
  116.         stat = getstatus();
  117.     }
  118.     exit(stat);
  119. }
  120.  
  121. /* The signal handler for all functions. calls walk() */
  122.  
  123. static void fn_handler(int s) {
  124.     List *dollarzero;
  125.     Estack e;
  126.     Edata star;
  127.     int olderrno;
  128.     if (s < 1 || s >= NUMOFSIGNALS)
  129.         panic("unknown signal");
  130.     olderrno = errno;
  131.     dollarzero = nnew(List);
  132.     dollarzero->w = signals[s].name;
  133.     dollarzero->n = NULL;
  134.     varassign("*", dollarzero, TRUE);
  135.     star.name = "*";
  136.     except(eVarstack, star, &e);
  137.     walk(handlers[s], TRUE);
  138.     varrm("*", TRUE);
  139.     unexcept(); /* eVarstack */
  140.     errno = olderrno;
  141. }
  142.  
  143. /* A dud signal handler for SIGQUIT and SIGTERM */
  144.  
  145. static void dud_handler(int s) {
  146. }
  147.  
  148. /*
  149.    Assign a function in Node form. Check to see if the function is also
  150.    a signal, and set the signal vectors appropriately.
  151. */
  152.  
  153. extern void fnassign(char *name, Node *def) {
  154.     Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */
  155.     Function *new = get_fn_place(name);
  156.     int i;
  157.     new->def = newdef;
  158.     new->extdef = NULL;
  159.     if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */
  160. #ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */
  161.         if (streq(name, "sigcld"))
  162.             rc_error("can't trap SIGCLD");
  163. #endif
  164.         if (streq(name, "sigexit"))
  165.             runexit = TRUE;
  166.         for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
  167.             if (streq(signals[i].name, name)) {
  168.                 handlers[i] = newdef;
  169.                 if (def == NULL)
  170.                     rc_signal(i, SIG_IGN);
  171.                 else
  172.                     rc_signal(i, fn_handler);
  173.                 break;
  174.             }
  175.     }
  176. }
  177.  
  178. /* Assign a function from the environment. Store just the external representation */
  179.  
  180. extern void fnassign_string(char *extdef) {
  181.     char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
  182.     Function *new;
  183.     if (name == NULL)
  184.         return;
  185.     new = get_fn_place(name);
  186.     new->def = NULL;
  187.     new->extdef = ecpy(extdef);
  188. }
  189.  
  190. /* Return a function in Node form, evaluating an entry from the environment if necessary */
  191.  
  192. extern Node *fnlookup(char *name) {
  193.     Function *look = lookup_fn(name);
  194.     Node *ret;
  195.     if (look == NULL)
  196.         return NULL; /* not found */
  197.     if (look->def != NULL)
  198.         return look->def;
  199.     if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
  200.         return &null;
  201.     ret = parse_fn(name, look->extdef);
  202.     if (ret == NULL) {
  203.         efree(look->extdef);
  204.         look->extdef = NULL;
  205.         return &null;
  206.     } else {
  207.         return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */
  208.     }
  209. }
  210.  
  211. /* Return a function in string form (used by makeenv) */
  212.  
  213. extern char *fnlookup_string(char *name) {
  214.     Function *look = lookup_fn(name);
  215.  
  216.     if (look == NULL)
  217.         return NULL;
  218.     if (look->extdef != NULL)
  219.         return look->extdef;
  220.     return look->extdef = fun2str(name, look->def);
  221. }
  222.  
  223. /*
  224.    Remove a function from the symbol table. If it also defines a signal
  225.    handler, restore the signal handler to its default value.
  226. */
  227.  
  228. extern void fnrm(char *name) {
  229.     int i;
  230.     for (i = 1; i < NUMOFSIGNALS; i++)
  231.         if (streq(signals[i].name, name)) {
  232.             handlers[i] = NULL;
  233.             switch (i) {
  234.             case SIGINT:
  235.                 rc_signal(i, def_sigint);
  236.                 break;
  237.             case SIGQUIT:
  238.                 rc_signal(i, def_sigquit);
  239.                 break;
  240.             case SIGTERM:
  241.                 rc_signal(i, def_sigterm);
  242.                 break;
  243.             default:
  244.                 rc_signal(i, SIG_DFL);
  245.             }
  246.         }
  247.     if (streq(name, "sigexit"))
  248.         runexit = FALSE;
  249.     delete_fn(name);
  250. }
  251.  
  252. extern void whatare_all_signals() {
  253.     int i;
  254.     for (i = 1; i < NUMOFSIGNALS; i++)
  255.         if (*signals[i].name != '\0')
  256.             if (sighandlers[i] == SIG_IGN)
  257.                 fprint(1, "fn %s {}\n", signals[i].name);
  258.             else if (sighandlers[i] == fn_handler)
  259.                 fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]);
  260.             else
  261.                 fprint(1, "fn %s\n", signals[i].name);
  262. }
  263.  
  264. extern void prettyprint_fn(int fd, char *name, Node *n) {
  265.     fprint(fd, "fn %S {%T}\n", name, n);
  266. }
  267.