summaryrefslogtreecommitdiff
path: root/fn.c
diff options
context:
space:
mode:
authorByron Rakitzis <byron@archone.tamu.edu>1992-05-27 00:00:01 +0100
committerToby Goodwin <toby@paccrat.org>2015-05-16 21:22:56 +0100
commit26bb34cf036027dfa22dfae8d8fc2f6bfd6acb75 (patch)
tree589705b2492ce4681760846d9ca45600f0af298d /fn.c
release: rc-1.4
Diffstat (limited to 'fn.c')
-rw-r--r--fn.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/fn.c b/fn.c
new file mode 100644
index 0000000..02de02b
--- /dev/null
+++ b/fn.c
@@ -0,0 +1,266 @@
+/*
+ fn.c: functions for adding and deleting functions from the symbol table.
+ Support for signal handlers is also found here.
+*/
+
+#include <signal.h>
+#include <errno.h>
+#include "rc.h"
+#include "sigmsgs.h"
+
+static void fn_handler(int), dud_handler(int);
+
+static bool runexit = FALSE;
+static Node *handlers[NUMOFSIGNALS], null;
+static void (*def_sigint)(int) = SIG_DFL,
+ (*def_sigquit)(int) = SIG_DFL,
+ (*def_sigterm)(int) = SIG_DFL;
+
+/*
+ Set signals to default values for rc. This means that interactive
+ shells ignore SIGTERM, etc.
+*/
+
+extern void inithandler() {
+ int i;
+ null.type = nBody;
+ null.u[0].p = null.u[1].p = NULL;
+ for (i = 1; i < NUMOFSIGNALS; i++)
+#ifdef NOSIGCLD
+ if (i != SIGCLD)
+#endif
+ if (sighandlers[i] == SIG_IGN)
+ fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */
+ if (interactive || sighandlers[SIGINT] != SIG_IGN) {
+ def_sigint = sigint;
+ fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */
+ }
+ if (!dashdee) {
+ if (interactive || sighandlers[SIGQUIT] != SIG_IGN) {
+ def_sigquit = dud_handler;
+ fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */
+ }
+ if (interactive) {
+ def_sigterm = dud_handler;
+ fnrm("sigterm"); /* ditto for SIGTERM */
+ }
+ }
+}
+
+/* only run this in a child process! resets signals to their default values */
+
+extern void setsigdefaults(bool sysvbackground) {
+ int i;
+ /*
+ General housekeeping: setsigdefaults happens after fork(),
+ so it's a convenient place to clean up open file descriptors.
+ (history file, scripts, etc.)
+ */
+ closefds();
+ /*
+ Restore signals to SIG_DFL, paying close attention to
+ a few quirks: SIGINT, SIGQUIT and are treated specially
+ depending on whether we are doing v7-style backgrounding
+ or not; the default action for SIGINT, SIGQUIT and SIGTERM
+ must be set to the appropriate action; finally, care must
+ be taken not to set to SIG_DFL any signals which are being
+ ignored.
+ */
+ for (i = 1; i < NUMOFSIGNALS; i++)
+ if (sighandlers[i] != SIG_IGN) {
+ handlers[i] = NULL;
+ switch (i) {
+ case SIGINT:
+ if (sysvbackground) {
+ def_sigint = SIG_IGN;
+ fnassign("sigint", NULL); /* ignore */
+ } else {
+ def_sigint = SIG_DFL;
+ goto sigcommon;
+ }
+ break;
+ case SIGQUIT:
+ if (sysvbackground) {
+ def_sigquit = SIG_IGN;
+ fnassign("sigquit", NULL); /* ignore */
+ } else {
+ def_sigquit = SIG_DFL;
+ goto sigcommon;
+ }
+ break;
+ case SIGTERM:
+ def_sigterm = SIG_DFL;
+ /* FALLTHROUGH */
+ sigcommon:
+ default:
+ if (sighandlers[i] != SIG_DFL) {
+ rc_signal(i, SIG_DFL);
+ delete_fn(signals[i].name);
+ }
+ }
+ }
+ delete_fn("sigexit");
+ runexit = FALSE; /* No sigexit on subshells */
+}
+
+/* rc's exit. if runexit is set, run the sigexit function. */
+
+extern void rc_exit(int stat) {
+ static char *sigexit[2] = {
+ "sigexit",
+ NULL
+ };
+ if (runexit) {
+ runexit = FALSE;
+ funcall(sigexit);
+ stat = getstatus();
+ }
+ exit(stat);
+}
+
+/* The signal handler for all functions. calls walk() */
+
+static void fn_handler(int s) {
+ List *dollarzero;
+ Estack e;
+ Edata star;
+ int olderrno;
+ if (s < 1 || s >= NUMOFSIGNALS)
+ panic("unknown signal");
+ olderrno = errno;
+ dollarzero = nnew(List);
+ dollarzero->w = signals[s].name;
+ dollarzero->n = NULL;
+ varassign("*", dollarzero, TRUE);
+ star.name = "*";
+ except(eVarstack, star, &e);
+ walk(handlers[s], TRUE);
+ varrm("*", TRUE);
+ unexcept(); /* eVarstack */
+ errno = olderrno;
+}
+
+/* A dud signal handler for SIGQUIT and SIGTERM */
+
+static void dud_handler(int s) {
+}
+
+/*
+ Assign a function in Node form. Check to see if the function is also
+ a signal, and set the signal vectors appropriately.
+*/
+
+extern void fnassign(char *name, Node *def) {
+ Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */
+ Function *new = get_fn_place(name);
+ int i;
+ new->def = newdef;
+ new->extdef = NULL;
+ if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */
+#ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */
+ if (streq(name, "sigcld"))
+ rc_error("can't trap SIGCLD");
+#endif
+ if (streq(name, "sigexit"))
+ runexit = TRUE;
+ for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
+ if (streq(signals[i].name, name)) {
+ handlers[i] = newdef;
+ if (def == NULL)
+ rc_signal(i, SIG_IGN);
+ else
+ rc_signal(i, fn_handler);
+ break;
+ }
+ }
+}
+
+/* Assign a function from the environment. Store just the external representation */
+
+extern void fnassign_string(char *extdef) {
+ char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
+ Function *new;
+ if (name == NULL)
+ return;
+ new = get_fn_place(name);
+ new->def = NULL;
+ new->extdef = ecpy(extdef);
+}
+
+/* Return a function in Node form, evaluating an entry from the environment if necessary */
+
+extern Node *fnlookup(char *name) {
+ Function *look = lookup_fn(name);
+ Node *ret;
+ if (look == NULL)
+ return NULL; /* not found */
+ if (look->def != NULL)
+ return look->def;
+ if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
+ return &null;
+ ret = parse_fn(name, look->extdef);
+ if (ret == NULL) {
+ efree(look->extdef);
+ look->extdef = NULL;
+ return &null;
+ } else {
+ return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */
+ }
+}
+
+/* Return a function in string form (used by makeenv) */
+
+extern char *fnlookup_string(char *name) {
+ Function *look = lookup_fn(name);
+
+ if (look == NULL)
+ return NULL;
+ if (look->extdef != NULL)
+ return look->extdef;
+ return look->extdef = fun2str(name, look->def);
+}
+
+/*
+ Remove a function from the symbol table. If it also defines a signal
+ handler, restore the signal handler to its default value.
+*/
+
+extern void fnrm(char *name) {
+ int i;
+ for (i = 1; i < NUMOFSIGNALS; i++)
+ if (streq(signals[i].name, name)) {
+ handlers[i] = NULL;
+ switch (i) {
+ case SIGINT:
+ rc_signal(i, def_sigint);
+ break;
+ case SIGQUIT:
+ rc_signal(i, def_sigquit);
+ break;
+ case SIGTERM:
+ rc_signal(i, def_sigterm);
+ break;
+ default:
+ rc_signal(i, SIG_DFL);
+ }
+ }
+ if (streq(name, "sigexit"))
+ runexit = FALSE;
+ delete_fn(name);
+}
+
+extern void whatare_all_signals() {
+ int i;
+ for (i = 1; i < NUMOFSIGNALS; i++)
+ if (*signals[i].name != '\0')
+ if (sighandlers[i] == SIG_IGN)
+ fprint(1, "fn %s {}\n", signals[i].name);
+ else if (sighandlers[i] == fn_handler)
+ fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]);
+ else
+ fprint(1, "fn %s\n", signals[i].name);
+}
+
+extern void prettyprint_fn(int fd, char *name, Node *n) {
+ fprint(fd, "fn %S {%T}\n", name, n);
+}