]> git.ipfire.org Git - thirdparty/bash.git/blame - unwind_prot.c
changes to quoting for some globbing characters; regularize error behavior of builtin...
[thirdparty/bash.git] / unwind_prot.c
CommitLineData
2e4498b3
CR
1/* unwind_prot.c - a simple unwind-protect system for internal variables */
2
726f6388
JA
3/* I can't stand it anymore! Please can't we just write the
4 whole Unix system in lisp or something? */
5
d267701a 6/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
726f6388 7
2e4498b3 8 This file is part of GNU Bash, the Bourne Again SHell.
726f6388 9
2e4498b3
CR
10 Bash is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
726f6388 14
2e4498b3
CR
15 Bash is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
726f6388 19
2e4498b3
CR
20 You should have received a copy of the GNU General Public License
21 along with Bash. If not, see <http://www.gnu.org/licenses/>.
22*/
726f6388
JA
23
24/* **************************************************************** */
25/* */
26/* Unwind Protection Scheme for Bash */
27/* */
28/* **************************************************************** */
726f6388 29#include "config.h"
ccc6cda3
JA
30
31#include "bashtypes.h"
d166f048
JA
32#include "bashansi.h"
33
ccc6cda3
JA
34#if defined (HAVE_UNISTD_H)
35# include <unistd.h>
36#endif
37
a67031fe 38#if defined (HAVE_STDDEF_H)
f73dda09
JA
39# include <stddef.h>
40#endif
41
42#ifndef offsetof
43# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
44#endif
45
726f6388
JA
46#include "command.h"
47#include "general.h"
48#include "unwind_prot.h"
ccc6cda3 49#include "sig.h"
83509ab7 50#include "quit.h"
701f36c2 51#include "bashintl.h" /* for _() */
adc6cff5 52#include "error.h" /* for internal_warning */
34ec1876 53#include "ocache.h"
726f6388 54
f73dda09 55/* Structure describing a saved variable and the value to restore it to. */
d166f048 56typedef struct {
f73dda09 57 char *variable;
d166f048 58 int size;
f73dda09 59 char desired_setting[1]; /* actual size is `size' */
d166f048
JA
60} SAVED_VAR;
61
f73dda09
JA
62/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
63 If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
64 variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
65typedef union uwp {
66 struct uwp_head {
67 union uwp *next;
877ff726 68 sh_uwfunc_t *cleanup;
f73dda09
JA
69 } head;
70 struct {
71 struct uwp_head uwp_head;
877ff726 72 void *v;
f73dda09
JA
73 } arg;
74 struct {
75 struct uwp_head uwp_head;
76 SAVED_VAR v;
77 } sv;
78} UNWIND_ELT;
79
d267701a
CR
80static void unwind_frame_discard_internal (char *);
81static void unwind_frame_run_internal (char *);
877ff726 82static void add_unwind_protect_internal (sh_uwfunc_t *, void *);
d267701a
CR
83static void remove_unwind_protect_internal (void);
84static void run_unwind_protects_internal (void);
85static void clear_unwind_protects_internal (int);
877ff726
CR
86static inline void restore_variable (void *);
87static void unwind_protect_mem_internal (void *, int);
726f6388
JA
88
89static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
90
34ec1876
CR
91/* Allocating from a cache of unwind-protect elements */
92#define UWCACHESIZE 128
93
94sh_obj_cache_t uwcache = {0, 0, 0};
95
96#if 0
7117c2d2
JA
97#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
98#define uwpfree(elt) free(elt)
34ec1876
CR
99#else
100#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt)
101#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt)
102#endif
103
104void
a61ffa78 105uwp_init (void)
34ec1876
CR
106{
107 ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE);
108}
726f6388 109
726f6388
JA
110/* Start the beginning of a region. */
111void
a61ffa78 112begin_unwind_frame (char *tag)
726f6388 113{
d267701a 114 add_unwind_protect (NULL, tag);
726f6388
JA
115}
116
117/* Discard the unwind protects back to TAG. */
118void
a61ffa78 119discard_unwind_frame (char *tag)
726f6388
JA
120{
121 if (unwind_protect_list)
d267701a 122 unwind_frame_discard_internal (tag);
726f6388
JA
123}
124
125/* Run the unwind protects back to TAG. */
126void
a61ffa78 127run_unwind_frame (char *tag)
726f6388
JA
128{
129 if (unwind_protect_list)
d267701a 130 unwind_frame_run_internal (tag);
726f6388
JA
131}
132
133/* Add the function CLEANUP with ARG to the list of unwindable things. */
134void
877ff726 135add_unwind_protect (sh_uwfunc_t *cleanup, void *arg)
726f6388 136{
d267701a 137 add_unwind_protect_internal (cleanup, arg);
726f6388
JA
138}
139
140/* Remove the top unwind protect from the list. */
141void
a61ffa78 142remove_unwind_protect (void)
726f6388
JA
143{
144 if (unwind_protect_list)
d267701a 145 remove_unwind_protect_internal ();
726f6388
JA
146}
147
148/* Run the list of cleanup functions in unwind_protect_list. */
149void
a61ffa78 150run_unwind_protects (void)
726f6388
JA
151{
152 if (unwind_protect_list)
d267701a 153 run_unwind_protects_internal ();
726f6388
JA
154}
155
28ef6c31
JA
156/* Erase the unwind-protect list. If flags is 1, free the elements. */
157void
a61ffa78 158clear_unwind_protect_list (int flags)
28ef6c31
JA
159{
160 if (unwind_protect_list)
d267701a 161 clear_unwind_protects_internal (flags);
28ef6c31
JA
162}
163
1fa6db60 164int
a61ffa78 165have_unwind_protects (void)
1fa6db60
CR
166{
167 return (unwind_protect_list != 0);
168}
169
fbbc416f 170int
a61ffa78 171unwind_protect_tag_on_stack (const char *tag)
fbbc416f
CR
172{
173 UNWIND_ELT *elt;
174
175 elt = unwind_protect_list;
176 while (elt)
177 {
178 if (elt->head.cleanup == 0 && STREQ (elt->arg.v, tag))
179 return 1;
180 elt = elt->head.next;
181 }
182 return 0;
183}
184
726f6388
JA
185/* **************************************************************** */
186/* */
28ef6c31 187/* The Actual Functions */
726f6388
JA
188/* */
189/* **************************************************************** */
190
191static void
877ff726 192add_unwind_protect_internal (sh_uwfunc_t *cleanup, void *arg)
726f6388
JA
193{
194 UNWIND_ELT *elt;
195
7117c2d2 196 uwpalloc (elt);
f73dda09
JA
197 elt->head.next = unwind_protect_list;
198 elt->head.cleanup = cleanup;
199 elt->arg.v = arg;
726f6388
JA
200 unwind_protect_list = elt;
201}
202
203static void
d267701a 204remove_unwind_protect_internal (void)
726f6388 205{
d166f048 206 UNWIND_ELT *elt;
726f6388 207
d166f048 208 elt = unwind_protect_list;
726f6388
JA
209 if (elt)
210 {
f73dda09 211 unwind_protect_list = unwind_protect_list->head.next;
7117c2d2 212 uwpfree (elt);
726f6388
JA
213 }
214}
215
216static void
d267701a 217run_unwind_protects_internal (void)
726f6388 218{
d267701a 219 unwind_frame_run_internal (NULL);
726f6388
JA
220}
221
222static void
d267701a 223clear_unwind_protects_internal (int flag)
28ef6c31 224{
f73dda09 225 if (flag)
28ef6c31
JA
226 {
227 while (unwind_protect_list)
d267701a 228 remove_unwind_protect_internal ();
28ef6c31
JA
229 }
230 unwind_protect_list = (UNWIND_ELT *)NULL;
231}
232
233static void
d267701a 234unwind_frame_discard_internal (char *tag)
726f6388
JA
235{
236 UNWIND_ELT *elt;
048b249e 237 int found;
726f6388 238
048b249e 239 found = 0;
726f6388
JA
240 while (elt = unwind_protect_list)
241 {
f73dda09
JA
242 unwind_protect_list = unwind_protect_list->head.next;
243 if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
726f6388 244 {
7117c2d2 245 uwpfree (elt);
048b249e 246 found = 1;
726f6388
JA
247 break;
248 }
249 else
7117c2d2 250 uwpfree (elt);
726f6388 251 }
048b249e
CR
252
253 if (found == 0)
701f36c2 254 internal_warning (_("unwind_frame_discard: %s: frame not found"), tag);
726f6388
JA
255}
256
f73dda09
JA
257/* Restore the value of a variable, based on the contents of SV.
258 sv->desired_setting is a block of memory SIZE bytes long holding the
259 value itself. This block of memory is copied back into the variable. */
260static inline void
877ff726 261restore_variable (void *arg)
f73dda09 262{
877ff726
CR
263 SAVED_VAR *sv;
264 sv = arg;
f73dda09
JA
265 FASTCOPY (sv->desired_setting, sv->variable, sv->size);
266}
267
726f6388 268static void
d267701a 269unwind_frame_run_internal (char *tag)
726f6388
JA
270{
271 UNWIND_ELT *elt;
048b249e 272 int found;
726f6388 273
048b249e 274 found = 0;
726f6388
JA
275 while (elt = unwind_protect_list)
276 {
f73dda09 277 unwind_protect_list = elt->head.next;
726f6388
JA
278
279 /* If tag, then compare. */
048b249e 280 if (elt->head.cleanup == 0)
726f6388 281 {
f73dda09 282 if (tag && STREQ (elt->arg.v, tag))
726f6388 283 {
7117c2d2 284 uwpfree (elt);
048b249e 285 found = 1;
726f6388
JA
286 break;
287 }
726f6388
JA
288 }
289 else
290 {
877ff726 291 if (elt->head.cleanup == restore_variable)
f73dda09
JA
292 restore_variable (&elt->sv.v);
293 else
294 (*(elt->head.cleanup)) (elt->arg.v);
726f6388 295 }
726f6388 296
7117c2d2 297 uwpfree (elt);
f73dda09 298 }
048b249e 299 if (tag && found == 0)
701f36c2 300 internal_warning (_("unwind_frame_run: %s: frame not found"), tag);
d166f048 301}
726f6388 302
726f6388 303static void
877ff726 304unwind_protect_mem_internal (void *var, int size)
726f6388 305{
2e725f73 306 size_t allocated;
f73dda09 307 UNWIND_ELT *elt;
726f6388 308
f73dda09 309 allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
dd4e3abc
CR
310 if (allocated < sizeof (UNWIND_ELT))
311 allocated = sizeof (UNWIND_ELT);
f73dda09
JA
312 elt = (UNWIND_ELT *)xmalloc (allocated);
313 elt->head.next = unwind_protect_list;
877ff726 314 elt->head.cleanup = restore_variable;
f73dda09
JA
315 elt->sv.v.variable = var;
316 elt->sv.v.size = size;
317 FASTCOPY (var, elt->sv.v.desired_setting, size);
318 unwind_protect_list = elt;
726f6388
JA
319}
320
321/* Save the value of a variable so it will be restored when unwind-protects
f73dda09
JA
322 are run. VAR is a pointer to the variable. SIZE is the size in
323 bytes of VAR. */
726f6388 324void
a61ffa78 325unwind_protect_mem (char *var, int size)
726f6388 326{
877ff726 327 unwind_protect_mem_internal (var, size);
726f6388 328}
048b249e
CR
329
330#if defined (DEBUG)
06dff54a
CR
331#include <stdio.h>
332
048b249e 333void
a61ffa78 334print_unwind_protect_tags (void)
048b249e
CR
335{
336 UNWIND_ELT *elt;
337
338 elt = unwind_protect_list;
339 while (elt)
340 {
048b249e 341 if (elt->head.cleanup == 0)
877ff726 342 fprintf(stderr, "tag: %s\n", (char *)elt->arg.v);
fbbc416f 343 elt = elt->head.next;
048b249e
CR
344 }
345}
346#endif