Commit | Line | Data |
---|---|---|
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 | ||
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 | 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 | ||
49 | extern 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 | ||
105 | extern 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 | ||
120 | static 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 | ||
142 | static 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 | ||
150 | extern 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 | ||
173 | extern 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 | ||
185 | extern 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 | ||
206 | extern 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 | ||
221 | extern 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 | ||
245 | extern 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 | ||
257 | extern void prettyprint_fn(int fd, char *name, Node *n) { | |
258 | fprint(fd, "fn %S {%T}\n", name, n); | |
259 | } |