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