blob: 628845c5e347b121e1b19233595a5dc1a57aa9c6 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* 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,1989 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
Jari Aaltobb706242000-03-17 21:46:59 +000010Software Foundation; either version 2, or (at your option) any later
Jari Aalto726f6381996-08-26 18:22:31 +000011version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
Jari Aaltobb706242000-03-17 21:46:59 +000020Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
Jari Aalto726f6381996-08-26 18:22:31 +000021
22/* **************************************************************** */
23/* */
24/* Unwind Protection Scheme for Bash */
25/* */
26/* **************************************************************** */
Jari Aalto726f6381996-08-26 18:22:31 +000027#include "config.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000028
29#include "bashtypes.h"
Jari Aaltod166f041997-06-05 14:59:13 +000030#include "bashansi.h"
31
Jari Aaltoccc6cda1996-12-23 17:02:34 +000032#if defined (HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35
Jari Aalto726f6381996-08-26 18:22:31 +000036#include "command.h"
37#include "general.h"
38#include "unwind_prot.h"
39#include "quit.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000040#include "sig.h"
Jari Aalto726f6381996-08-26 18:22:31 +000041
42/* If CLEANUP is null, then ARG contains a tag to throw back to. */
43typedef struct _uwp {
44 struct _uwp *next;
45 Function *cleanup;
46 char *arg;
47} UNWIND_ELT;
48
Jari Aaltod166f041997-06-05 14:59:13 +000049/* Structure describing a saved variable and the value to restore it to.
50 If a cleanup function is set to restore_variable, the `arg' pointer
51 points to this. */
52typedef struct {
53 int *variable;
54 char *desired_setting;
55 int size;
56} SAVED_VAR;
57
Jari Aalto28ef6c32001-04-06 19:14:31 +000058static void without_interrupts ();
59static void unwind_frame_discard_internal ();
60static void unwind_frame_run_internal ();
61static void add_unwind_protect_internal ();
62static void remove_unwind_protect_internal ();
63static void run_unwind_protects_internal ();
64static void clear_unwind_protects_internal ();
Jari Aaltod166f041997-06-05 14:59:13 +000065static void restore_variable ();
66static void discard_saved_var ();
Jari Aalto726f6381996-08-26 18:22:31 +000067
68static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
69
70extern int interrupt_immediately;
71
72/* Run a function without interrupts. This relies on the fact that the
73 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
74 not call QUIT (). */
75static void
76without_interrupts (function, arg1, arg2)
77 VFunction *function;
78 char *arg1, *arg2;
79{
80 int old_interrupt_immediately;
81
82 old_interrupt_immediately = interrupt_immediately;
83 interrupt_immediately = 0;
84
85 (*function)(arg1, arg2);
86
87 interrupt_immediately = old_interrupt_immediately;
88}
89
90/* Start the beginning of a region. */
91void
92begin_unwind_frame (tag)
93 char *tag;
94{
95 add_unwind_protect ((Function *)NULL, tag);
96}
97
98/* Discard the unwind protects back to TAG. */
99void
100discard_unwind_frame (tag)
101 char *tag;
102{
103 if (unwind_protect_list)
104 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
105}
106
107/* Run the unwind protects back to TAG. */
108void
109run_unwind_frame (tag)
110 char *tag;
111{
112 if (unwind_protect_list)
113 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
114}
115
116/* Add the function CLEANUP with ARG to the list of unwindable things. */
117void
118add_unwind_protect (cleanup, arg)
119 Function *cleanup;
120 char *arg;
121{
122 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
123}
124
125/* Remove the top unwind protect from the list. */
126void
127remove_unwind_protect ()
128{
129 if (unwind_protect_list)
130 without_interrupts
131 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
132}
133
134/* Run the list of cleanup functions in unwind_protect_list. */
135void
136run_unwind_protects ()
137{
138 if (unwind_protect_list)
139 without_interrupts
140 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
141}
142
Jari Aalto28ef6c32001-04-06 19:14:31 +0000143/* Erase the unwind-protect list. If flags is 1, free the elements. */
144void
145clear_unwind_protect_list (flags)
146 int flags;
147{
148 if (unwind_protect_list)
149 without_interrupts
150 (clear_unwind_protects_internal, (char *)flags, (char *)NULL);
151}
152
Jari Aalto726f6381996-08-26 18:22:31 +0000153/* **************************************************************** */
154/* */
Jari Aalto28ef6c32001-04-06 19:14:31 +0000155/* The Actual Functions */
Jari Aalto726f6381996-08-26 18:22:31 +0000156/* */
157/* **************************************************************** */
158
159static void
160add_unwind_protect_internal (cleanup, arg)
161 Function *cleanup;
162 char *arg;
163{
164 UNWIND_ELT *elt;
165
166 elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
167 elt->cleanup = cleanup;
168 elt->arg = arg;
169 elt->next = unwind_protect_list;
170 unwind_protect_list = elt;
171}
172
173static void
Jari Aalto28ef6c32001-04-06 19:14:31 +0000174remove_unwind_protect_internal (ignore1, ignore2)
175 char *ignore1, *ignore2;
Jari Aalto726f6381996-08-26 18:22:31 +0000176{
Jari Aaltod166f041997-06-05 14:59:13 +0000177 UNWIND_ELT *elt;
Jari Aalto726f6381996-08-26 18:22:31 +0000178
Jari Aaltod166f041997-06-05 14:59:13 +0000179 elt = unwind_protect_list;
Jari Aalto726f6381996-08-26 18:22:31 +0000180 if (elt)
181 {
182 unwind_protect_list = unwind_protect_list->next;
Jari Aaltod166f041997-06-05 14:59:13 +0000183 if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
184 discard_saved_var ((SAVED_VAR *)elt->arg);
Jari Aalto726f6381996-08-26 18:22:31 +0000185 free (elt);
186 }
187}
188
189static void
Jari Aalto28ef6c32001-04-06 19:14:31 +0000190run_unwind_protects_internal (ignore1, ignore2)
191 char *ignore1, *ignore2;
Jari Aalto726f6381996-08-26 18:22:31 +0000192{
193 UNWIND_ELT *t, *elt = unwind_protect_list;
194
195 while (elt)
196 {
197 /* This function can be run at strange times, like when unwinding
Jari Aaltod166f041997-06-05 14:59:13 +0000198 the entire world of unwind protects. Thus, we may come across
Jari Aalto726f6381996-08-26 18:22:31 +0000199 an element which is simply a label for a catch frame. Don't call
200 the non-existant function. */
201 if (elt->cleanup)
202 (*(elt->cleanup)) (elt->arg);
203
204 t = elt;
205 elt = elt->next;
206 free (t);
207 }
208 unwind_protect_list = elt;
209}
210
211static void
Jari Aalto28ef6c32001-04-06 19:14:31 +0000212clear_unwind_protects_internal (flag, ignore)
213 char *flag, *ignore;
214{
215 int free_elts = (int)flag;
216 UNWIND_ELT *elt;
217
218 if (free_elts != 0 && unwind_protect_list)
219 {
220 while (unwind_protect_list)
221 remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
222 }
223 unwind_protect_list = (UNWIND_ELT *)NULL;
224}
225
226static void
227unwind_frame_discard_internal (tag, ignore)
228 char *tag, *ignore;
Jari Aalto726f6381996-08-26 18:22:31 +0000229{
230 UNWIND_ELT *elt;
231
232 while (elt = unwind_protect_list)
233 {
234 unwind_protect_list = unwind_protect_list->next;
Jari Aaltod166f041997-06-05 14:59:13 +0000235 if (elt->cleanup == 0 && (STREQ (elt->arg, tag)))
Jari Aalto726f6381996-08-26 18:22:31 +0000236 {
237 free (elt);
238 break;
239 }
Jari Aaltod166f041997-06-05 14:59:13 +0000240 else if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
Jari Aalto28ef6c32001-04-06 19:14:31 +0000241 {
242 discard_saved_var ((SAVED_VAR *)elt->arg);
243 free (elt);
244 }
Jari Aalto726f6381996-08-26 18:22:31 +0000245 else
246 free (elt);
247 }
248}
249
250static void
Jari Aalto28ef6c32001-04-06 19:14:31 +0000251unwind_frame_run_internal (tag, ignore)
252 char *tag, *ignore;
Jari Aalto726f6381996-08-26 18:22:31 +0000253{
254 UNWIND_ELT *elt;
255
256 while (elt = unwind_protect_list)
257 {
258 unwind_protect_list = elt->next;
259
260 /* If tag, then compare. */
261 if (!elt->cleanup)
262 {
263 if (STREQ (elt->arg, tag))
264 {
265 free (elt);
266 break;
267 }
268 free (elt);
269 continue;
270 }
271 else
272 {
273 (*(elt->cleanup)) (elt->arg);
274 free (elt);
275 }
276 }
277}
278
Jari Aaltod166f041997-06-05 14:59:13 +0000279static void
280discard_saved_var (sv)
281 SAVED_VAR *sv;
282{
283 if (sv->size != sizeof (int))
284 free (sv->desired_setting);
285 free (sv);
286}
Jari Aalto726f6381996-08-26 18:22:31 +0000287
288/* Restore the value of a variable, based on the contents of SV. If
289 sv->size is greater than sizeof (int), sv->desired_setting points to
290 a block of memory SIZE bytes long holding the value, rather than the
291 value itself. This block of memory is copied back into the variable. */
292static void
293restore_variable (sv)
294 SAVED_VAR *sv;
295{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000296 if (sv->size != sizeof (int))
Jari Aalto726f6381996-08-26 18:22:31 +0000297 {
Jari Aaltod166f041997-06-05 14:59:13 +0000298 FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
Jari Aalto726f6381996-08-26 18:22:31 +0000299 free (sv->desired_setting);
300 }
301 else
302 *(sv->variable) = (int)sv->desired_setting;
303
304 free (sv);
305}
306
307/* Save the value of a variable so it will be restored when unwind-protects
308 are run. VAR is a pointer to the variable. VALUE is the value to be
309 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
310 can be saved in an int, memory will be allocated and the value saved
311 into that using bcopy (). */
312void
313unwind_protect_var (var, value, size)
314 int *var;
315 char *value;
316 int size;
317{
318 SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
319
320 s->variable = var;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000321 if (size != sizeof (int))
Jari Aalto726f6381996-08-26 18:22:31 +0000322 {
323 s->desired_setting = (char *)xmalloc (size);
Jari Aalto28ef6c32001-04-06 19:14:31 +0000324 FASTCOPY (value, (char *)s->desired_setting, size);
Jari Aalto726f6381996-08-26 18:22:31 +0000325 }
326 else
327 s->desired_setting = value;
328 s->size = size;
329 add_unwind_protect ((Function *)restore_variable, (char *)s);
330}