1 | /* I can't stand it anymore! Please can't we just write the
|
---|
2 | whole Unix system in lisp or something? */
|
---|
3 |
|
---|
4 | /* Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
---|
5 |
|
---|
6 | This file is part of GNU Bash, the Bourne Again SHell.
|
---|
7 |
|
---|
8 | Bash is free software; you can redistribute it and/or modify it under
|
---|
9 | the terms of the GNU General Public License as published by the Free
|
---|
10 | Software Foundation; either version 2, or (at your option) any later
|
---|
11 | version.
|
---|
12 |
|
---|
13 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
---|
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
---|
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
---|
16 | for more details.
|
---|
17 |
|
---|
18 | You should have received a copy of the GNU General Public License along
|
---|
19 | with Bash; see the file COPYING. If not, write to the Free Software
|
---|
20 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
---|
21 |
|
---|
22 | /* **************************************************************** */
|
---|
23 | /* */
|
---|
24 | /* Unwind Protection Scheme for Bash */
|
---|
25 | /* */
|
---|
26 | /* **************************************************************** */
|
---|
27 | #include "config.h"
|
---|
28 |
|
---|
29 | #include "bashtypes.h"
|
---|
30 | #include "bashansi.h"
|
---|
31 |
|
---|
32 | #if defined (HAVE_UNISTD_H)
|
---|
33 | # include <unistd.h>
|
---|
34 | #endif
|
---|
35 |
|
---|
36 | #if STDC_HEADERS
|
---|
37 | # include <stddef.h>
|
---|
38 | #endif
|
---|
39 |
|
---|
40 | #ifndef offsetof
|
---|
41 | # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
---|
42 | #endif
|
---|
43 |
|
---|
44 | #include "command.h"
|
---|
45 | #include "general.h"
|
---|
46 | #include "unwind_prot.h"
|
---|
47 | #include "quit.h"
|
---|
48 | #include "sig.h"
|
---|
49 |
|
---|
50 | /* Structure describing a saved variable and the value to restore it to. */
|
---|
51 | typedef struct {
|
---|
52 | char *variable;
|
---|
53 | int size;
|
---|
54 | char desired_setting[1]; /* actual size is `size' */
|
---|
55 | } SAVED_VAR;
|
---|
56 |
|
---|
57 | /* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
|
---|
58 | If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
|
---|
59 | variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
|
---|
60 | typedef union uwp {
|
---|
61 | struct uwp_head {
|
---|
62 | union uwp *next;
|
---|
63 | Function *cleanup;
|
---|
64 | } head;
|
---|
65 | struct {
|
---|
66 | struct uwp_head uwp_head;
|
---|
67 | char *v;
|
---|
68 | } arg;
|
---|
69 | struct {
|
---|
70 | struct uwp_head uwp_head;
|
---|
71 | SAVED_VAR v;
|
---|
72 | } sv;
|
---|
73 | } UNWIND_ELT;
|
---|
74 |
|
---|
75 |
|
---|
76 | extern int interrupt_immediately;
|
---|
77 |
|
---|
78 | static void without_interrupts __P((VFunction *, char *, char *));
|
---|
79 | static void unwind_frame_discard_internal __P((char *, char *));
|
---|
80 | static void unwind_frame_run_internal __P((char *, char *));
|
---|
81 | static void add_unwind_protect_internal __P((Function *, char *));
|
---|
82 | static void remove_unwind_protect_internal __P((char *, char *));
|
---|
83 | static void run_unwind_protects_internal __P((char *, char *));
|
---|
84 | static void clear_unwind_protects_internal __P((char *, char *));
|
---|
85 | static inline void restore_variable __P((SAVED_VAR *));
|
---|
86 | static void unwind_protect_mem_internal __P((char *, char *));
|
---|
87 |
|
---|
88 | static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
|
---|
89 |
|
---|
90 | #define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
|
---|
91 | #define uwpfree(elt) free(elt)
|
---|
92 |
|
---|
93 | /* Run a function without interrupts. This relies on the fact that the
|
---|
94 | FUNCTION cannot change the value of interrupt_immediately. (I.e., does
|
---|
95 | not call QUIT (). */
|
---|
96 | static void
|
---|
97 | without_interrupts (function, arg1, arg2)
|
---|
98 | VFunction *function;
|
---|
99 | char *arg1, *arg2;
|
---|
100 | {
|
---|
101 | int old_interrupt_immediately;
|
---|
102 |
|
---|
103 | old_interrupt_immediately = interrupt_immediately;
|
---|
104 | interrupt_immediately = 0;
|
---|
105 |
|
---|
106 | (*function)(arg1, arg2);
|
---|
107 |
|
---|
108 | interrupt_immediately = old_interrupt_immediately;
|
---|
109 | }
|
---|
110 |
|
---|
111 | /* Start the beginning of a region. */
|
---|
112 | void
|
---|
113 | begin_unwind_frame (tag)
|
---|
114 | char *tag;
|
---|
115 | {
|
---|
116 | add_unwind_protect ((Function *)NULL, tag);
|
---|
117 | }
|
---|
118 |
|
---|
119 | /* Discard the unwind protects back to TAG. */
|
---|
120 | void
|
---|
121 | discard_unwind_frame (tag)
|
---|
122 | char *tag;
|
---|
123 | {
|
---|
124 | if (unwind_protect_list)
|
---|
125 | without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
|
---|
126 | }
|
---|
127 |
|
---|
128 | /* Run the unwind protects back to TAG. */
|
---|
129 | void
|
---|
130 | run_unwind_frame (tag)
|
---|
131 | char *tag;
|
---|
132 | {
|
---|
133 | if (unwind_protect_list)
|
---|
134 | without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
|
---|
135 | }
|
---|
136 |
|
---|
137 | /* Add the function CLEANUP with ARG to the list of unwindable things. */
|
---|
138 | void
|
---|
139 | add_unwind_protect (cleanup, arg)
|
---|
140 | Function *cleanup;
|
---|
141 | char *arg;
|
---|
142 | {
|
---|
143 | without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
|
---|
144 | }
|
---|
145 |
|
---|
146 | /* Remove the top unwind protect from the list. */
|
---|
147 | void
|
---|
148 | remove_unwind_protect ()
|
---|
149 | {
|
---|
150 | if (unwind_protect_list)
|
---|
151 | without_interrupts
|
---|
152 | (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
|
---|
153 | }
|
---|
154 |
|
---|
155 | /* Run the list of cleanup functions in unwind_protect_list. */
|
---|
156 | void
|
---|
157 | run_unwind_protects ()
|
---|
158 | {
|
---|
159 | if (unwind_protect_list)
|
---|
160 | without_interrupts
|
---|
161 | (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
|
---|
162 | }
|
---|
163 |
|
---|
164 | /* Erase the unwind-protect list. If flags is 1, free the elements. */
|
---|
165 | void
|
---|
166 | clear_unwind_protect_list (flags)
|
---|
167 | int flags;
|
---|
168 | {
|
---|
169 | char *flag;
|
---|
170 |
|
---|
171 | if (unwind_protect_list)
|
---|
172 | {
|
---|
173 | flag = flags ? "" : (char *)NULL;
|
---|
174 | without_interrupts
|
---|
175 | (clear_unwind_protects_internal, flag, (char *)NULL);
|
---|
176 | }
|
---|
177 | }
|
---|
178 |
|
---|
179 | /* **************************************************************** */
|
---|
180 | /* */
|
---|
181 | /* The Actual Functions */
|
---|
182 | /* */
|
---|
183 | /* **************************************************************** */
|
---|
184 |
|
---|
185 | static void
|
---|
186 | add_unwind_protect_internal (cleanup, arg)
|
---|
187 | Function *cleanup;
|
---|
188 | char *arg;
|
---|
189 | {
|
---|
190 | UNWIND_ELT *elt;
|
---|
191 |
|
---|
192 | uwpalloc (elt);
|
---|
193 | elt->head.next = unwind_protect_list;
|
---|
194 | elt->head.cleanup = cleanup;
|
---|
195 | elt->arg.v = arg;
|
---|
196 | unwind_protect_list = elt;
|
---|
197 | }
|
---|
198 |
|
---|
199 | static void
|
---|
200 | remove_unwind_protect_internal (ignore1, ignore2)
|
---|
201 | char *ignore1, *ignore2;
|
---|
202 | {
|
---|
203 | UNWIND_ELT *elt;
|
---|
204 |
|
---|
205 | elt = unwind_protect_list;
|
---|
206 | if (elt)
|
---|
207 | {
|
---|
208 | unwind_protect_list = unwind_protect_list->head.next;
|
---|
209 | uwpfree (elt);
|
---|
210 | }
|
---|
211 | }
|
---|
212 |
|
---|
213 | static void
|
---|
214 | run_unwind_protects_internal (ignore1, ignore2)
|
---|
215 | char *ignore1, *ignore2;
|
---|
216 | {
|
---|
217 | unwind_frame_run_internal ((char *) NULL, (char *) NULL);
|
---|
218 | }
|
---|
219 |
|
---|
220 | static void
|
---|
221 | clear_unwind_protects_internal (flag, ignore)
|
---|
222 | char *flag, *ignore;
|
---|
223 | {
|
---|
224 | if (flag)
|
---|
225 | {
|
---|
226 | while (unwind_protect_list)
|
---|
227 | remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
|
---|
228 | }
|
---|
229 | unwind_protect_list = (UNWIND_ELT *)NULL;
|
---|
230 | }
|
---|
231 |
|
---|
232 | static void
|
---|
233 | unwind_frame_discard_internal (tag, ignore)
|
---|
234 | char *tag, *ignore;
|
---|
235 | {
|
---|
236 | UNWIND_ELT *elt;
|
---|
237 |
|
---|
238 | while (elt = unwind_protect_list)
|
---|
239 | {
|
---|
240 | unwind_protect_list = unwind_protect_list->head.next;
|
---|
241 | if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
|
---|
242 | {
|
---|
243 | uwpfree (elt);
|
---|
244 | break;
|
---|
245 | }
|
---|
246 | else
|
---|
247 | uwpfree (elt);
|
---|
248 | }
|
---|
249 | }
|
---|
250 |
|
---|
251 | /* Restore the value of a variable, based on the contents of SV.
|
---|
252 | sv->desired_setting is a block of memory SIZE bytes long holding the
|
---|
253 | value itself. This block of memory is copied back into the variable. */
|
---|
254 | static inline void
|
---|
255 | restore_variable (sv)
|
---|
256 | SAVED_VAR *sv;
|
---|
257 | {
|
---|
258 | FASTCOPY (sv->desired_setting, sv->variable, sv->size);
|
---|
259 | }
|
---|
260 |
|
---|
261 | static void
|
---|
262 | unwind_frame_run_internal (tag, ignore)
|
---|
263 | char *tag, *ignore;
|
---|
264 | {
|
---|
265 | UNWIND_ELT *elt;
|
---|
266 |
|
---|
267 | while (elt = unwind_protect_list)
|
---|
268 | {
|
---|
269 | unwind_protect_list = elt->head.next;
|
---|
270 |
|
---|
271 | /* If tag, then compare. */
|
---|
272 | if (!elt->head.cleanup)
|
---|
273 | {
|
---|
274 | if (tag && STREQ (elt->arg.v, tag))
|
---|
275 | {
|
---|
276 | uwpfree (elt);
|
---|
277 | break;
|
---|
278 | }
|
---|
279 | }
|
---|
280 | else
|
---|
281 | {
|
---|
282 | if (elt->head.cleanup == (Function *) restore_variable)
|
---|
283 | restore_variable (&elt->sv.v);
|
---|
284 | else
|
---|
285 | (*(elt->head.cleanup)) (elt->arg.v);
|
---|
286 | }
|
---|
287 |
|
---|
288 | uwpfree (elt);
|
---|
289 | }
|
---|
290 | }
|
---|
291 |
|
---|
292 | static void
|
---|
293 | unwind_protect_mem_internal (var, psize)
|
---|
294 | char *var;
|
---|
295 | char *psize;
|
---|
296 | {
|
---|
297 | int size, allocated;
|
---|
298 | UNWIND_ELT *elt;
|
---|
299 |
|
---|
300 | size = *(int *) psize;
|
---|
301 | allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
|
---|
302 | elt = (UNWIND_ELT *)xmalloc (allocated);
|
---|
303 | elt->head.next = unwind_protect_list;
|
---|
304 | elt->head.cleanup = (Function *) restore_variable;
|
---|
305 | elt->sv.v.variable = var;
|
---|
306 | elt->sv.v.size = size;
|
---|
307 | FASTCOPY (var, elt->sv.v.desired_setting, size);
|
---|
308 | unwind_protect_list = elt;
|
---|
309 | }
|
---|
310 |
|
---|
311 | /* Save the value of a variable so it will be restored when unwind-protects
|
---|
312 | are run. VAR is a pointer to the variable. SIZE is the size in
|
---|
313 | bytes of VAR. */
|
---|
314 | void
|
---|
315 | unwind_protect_mem (var, size)
|
---|
316 | char *var;
|
---|
317 | int size;
|
---|
318 | {
|
---|
319 | without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
|
---|
320 | }
|
---|