1996-08-26 18:22:31 +00:00
|
|
|
/* I can't stand it anymore! Please can't we just write the
|
|
|
|
whole Unix system in lisp or something? */
|
|
|
|
|
|
|
|
/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
This file is part of GNU Bash, the Bourne Again SHell.
|
|
|
|
|
|
|
|
Bash is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free
|
2000-03-17 21:46:59 +00:00
|
|
|
Software Foundation; either version 2, or (at your option) any later
|
1996-08-26 18:22:31 +00:00
|
|
|
version.
|
|
|
|
|
|
|
|
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with Bash; see the file COPYING. If not, write to the Free Software
|
2000-03-17 21:46:59 +00:00
|
|
|
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
/* */
|
|
|
|
/* Unwind Protection Scheme for Bash */
|
|
|
|
/* */
|
|
|
|
/* **************************************************************** */
|
|
|
|
#include "config.h"
|
1996-12-23 17:02:34 +00:00
|
|
|
|
|
|
|
#include "bashtypes.h"
|
1997-06-05 14:59:13 +00:00
|
|
|
#include "bashansi.h"
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
#if defined (HAVE_UNISTD_H)
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
#include "command.h"
|
|
|
|
#include "general.h"
|
|
|
|
#include "unwind_prot.h"
|
|
|
|
#include "quit.h"
|
1996-12-23 17:02:34 +00:00
|
|
|
#include "sig.h"
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
/* If CLEANUP is null, then ARG contains a tag to throw back to. */
|
|
|
|
typedef struct _uwp {
|
|
|
|
struct _uwp *next;
|
|
|
|
Function *cleanup;
|
|
|
|
char *arg;
|
|
|
|
} UNWIND_ELT;
|
|
|
|
|
1997-06-05 14:59:13 +00:00
|
|
|
/* Structure describing a saved variable and the value to restore it to.
|
|
|
|
If a cleanup function is set to restore_variable, the `arg' pointer
|
|
|
|
points to this. */
|
|
|
|
typedef struct {
|
|
|
|
int *variable;
|
|
|
|
char *desired_setting;
|
|
|
|
int size;
|
|
|
|
} SAVED_VAR;
|
|
|
|
|
|
|
|
static void unwind_frame_discard_internal (), unwind_frame_run_internal ();
|
|
|
|
static void add_unwind_protect_internal (), remove_unwind_protect_internal ();
|
|
|
|
static void run_unwind_protects_internal (), without_interrupts ();
|
|
|
|
|
|
|
|
static void restore_variable ();
|
|
|
|
static void discard_saved_var ();
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
|
|
|
|
|
|
|
|
extern int interrupt_immediately;
|
|
|
|
|
|
|
|
/* Run a function without interrupts. This relies on the fact that the
|
|
|
|
FUNCTION cannot change the value of interrupt_immediately. (I.e., does
|
|
|
|
not call QUIT (). */
|
|
|
|
static void
|
|
|
|
without_interrupts (function, arg1, arg2)
|
|
|
|
VFunction *function;
|
|
|
|
char *arg1, *arg2;
|
|
|
|
{
|
|
|
|
int old_interrupt_immediately;
|
|
|
|
|
|
|
|
old_interrupt_immediately = interrupt_immediately;
|
|
|
|
interrupt_immediately = 0;
|
|
|
|
|
|
|
|
(*function)(arg1, arg2);
|
|
|
|
|
|
|
|
interrupt_immediately = old_interrupt_immediately;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start the beginning of a region. */
|
|
|
|
void
|
|
|
|
begin_unwind_frame (tag)
|
|
|
|
char *tag;
|
|
|
|
{
|
|
|
|
add_unwind_protect ((Function *)NULL, tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Discard the unwind protects back to TAG. */
|
|
|
|
void
|
|
|
|
discard_unwind_frame (tag)
|
|
|
|
char *tag;
|
|
|
|
{
|
|
|
|
if (unwind_protect_list)
|
|
|
|
without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Run the unwind protects back to TAG. */
|
|
|
|
void
|
|
|
|
run_unwind_frame (tag)
|
|
|
|
char *tag;
|
|
|
|
{
|
|
|
|
if (unwind_protect_list)
|
|
|
|
without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the function CLEANUP with ARG to the list of unwindable things. */
|
|
|
|
void
|
|
|
|
add_unwind_protect (cleanup, arg)
|
|
|
|
Function *cleanup;
|
|
|
|
char *arg;
|
|
|
|
{
|
|
|
|
without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove the top unwind protect from the list. */
|
|
|
|
void
|
|
|
|
remove_unwind_protect ()
|
|
|
|
{
|
|
|
|
if (unwind_protect_list)
|
|
|
|
without_interrupts
|
|
|
|
(remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Run the list of cleanup functions in unwind_protect_list. */
|
|
|
|
void
|
|
|
|
run_unwind_protects ()
|
|
|
|
{
|
|
|
|
if (unwind_protect_list)
|
|
|
|
without_interrupts
|
|
|
|
(run_unwind_protects_internal, (char *)NULL, (char *)NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
/* */
|
|
|
|
/* The Actual Functions */
|
|
|
|
/* */
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_unwind_protect_internal (cleanup, arg)
|
|
|
|
Function *cleanup;
|
|
|
|
char *arg;
|
|
|
|
{
|
|
|
|
UNWIND_ELT *elt;
|
|
|
|
|
|
|
|
elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
|
|
|
|
elt->cleanup = cleanup;
|
|
|
|
elt->arg = arg;
|
|
|
|
elt->next = unwind_protect_list;
|
|
|
|
unwind_protect_list = elt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_unwind_protect_internal ()
|
|
|
|
{
|
1997-06-05 14:59:13 +00:00
|
|
|
UNWIND_ELT *elt;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
1997-06-05 14:59:13 +00:00
|
|
|
elt = unwind_protect_list;
|
1996-08-26 18:22:31 +00:00
|
|
|
if (elt)
|
|
|
|
{
|
|
|
|
unwind_protect_list = unwind_protect_list->next;
|
1997-06-05 14:59:13 +00:00
|
|
|
if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
|
|
|
|
discard_saved_var ((SAVED_VAR *)elt->arg);
|
1996-08-26 18:22:31 +00:00
|
|
|
free (elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_unwind_protects_internal ()
|
|
|
|
{
|
|
|
|
UNWIND_ELT *t, *elt = unwind_protect_list;
|
|
|
|
|
|
|
|
while (elt)
|
|
|
|
{
|
|
|
|
/* This function can be run at strange times, like when unwinding
|
1997-06-05 14:59:13 +00:00
|
|
|
the entire world of unwind protects. Thus, we may come across
|
1996-08-26 18:22:31 +00:00
|
|
|
an element which is simply a label for a catch frame. Don't call
|
|
|
|
the non-existant function. */
|
|
|
|
if (elt->cleanup)
|
|
|
|
(*(elt->cleanup)) (elt->arg);
|
|
|
|
|
|
|
|
t = elt;
|
|
|
|
elt = elt->next;
|
|
|
|
free (t);
|
|
|
|
}
|
|
|
|
unwind_protect_list = elt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unwind_frame_discard_internal (tag)
|
|
|
|
char *tag;
|
|
|
|
{
|
|
|
|
UNWIND_ELT *elt;
|
|
|
|
|
|
|
|
while (elt = unwind_protect_list)
|
|
|
|
{
|
|
|
|
unwind_protect_list = unwind_protect_list->next;
|
1997-06-05 14:59:13 +00:00
|
|
|
if (elt->cleanup == 0 && (STREQ (elt->arg, tag)))
|
1996-08-26 18:22:31 +00:00
|
|
|
{
|
|
|
|
free (elt);
|
|
|
|
break;
|
|
|
|
}
|
1997-06-05 14:59:13 +00:00
|
|
|
else if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
|
|
|
|
{
|
|
|
|
discard_saved_var ((SAVED_VAR *)elt->arg);
|
|
|
|
free (elt);
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
else
|
|
|
|
free (elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unwind_frame_run_internal (tag)
|
|
|
|
char *tag;
|
|
|
|
{
|
|
|
|
UNWIND_ELT *elt;
|
|
|
|
|
|
|
|
while (elt = unwind_protect_list)
|
|
|
|
{
|
|
|
|
unwind_protect_list = elt->next;
|
|
|
|
|
|
|
|
/* If tag, then compare. */
|
|
|
|
if (!elt->cleanup)
|
|
|
|
{
|
|
|
|
if (STREQ (elt->arg, tag))
|
|
|
|
{
|
|
|
|
free (elt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free (elt);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
(*(elt->cleanup)) (elt->arg);
|
|
|
|
free (elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-06-05 14:59:13 +00:00
|
|
|
static void
|
|
|
|
discard_saved_var (sv)
|
|
|
|
SAVED_VAR *sv;
|
|
|
|
{
|
|
|
|
if (sv->size != sizeof (int))
|
|
|
|
free (sv->desired_setting);
|
|
|
|
free (sv);
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
/* Restore the value of a variable, based on the contents of SV. If
|
|
|
|
sv->size is greater than sizeof (int), sv->desired_setting points to
|
|
|
|
a block of memory SIZE bytes long holding the value, rather than the
|
|
|
|
value itself. This block of memory is copied back into the variable. */
|
|
|
|
static void
|
|
|
|
restore_variable (sv)
|
|
|
|
SAVED_VAR *sv;
|
|
|
|
{
|
1996-12-23 17:02:34 +00:00
|
|
|
if (sv->size != sizeof (int))
|
1996-08-26 18:22:31 +00:00
|
|
|
{
|
1997-06-05 14:59:13 +00:00
|
|
|
FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
|
1996-08-26 18:22:31 +00:00
|
|
|
free (sv->desired_setting);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*(sv->variable) = (int)sv->desired_setting;
|
|
|
|
|
|
|
|
free (sv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the value of a variable so it will be restored when unwind-protects
|
|
|
|
are run. VAR is a pointer to the variable. VALUE is the value to be
|
|
|
|
saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
|
|
|
|
can be saved in an int, memory will be allocated and the value saved
|
|
|
|
into that using bcopy (). */
|
|
|
|
void
|
|
|
|
unwind_protect_var (var, value, size)
|
|
|
|
int *var;
|
|
|
|
char *value;
|
|
|
|
int size;
|
|
|
|
{
|
|
|
|
SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
|
|
|
|
|
|
|
|
s->variable = var;
|
1996-12-23 17:02:34 +00:00
|
|
|
if (size != sizeof (int))
|
1996-08-26 18:22:31 +00:00
|
|
|
{
|
1997-06-05 14:59:13 +00:00
|
|
|
/* There is a problem here when VALUE is 0. This tries to copy the
|
|
|
|
first SIZE bytes starting at memory location 0 into
|
|
|
|
s->desired_setting. There is no guarantee that these bytes are
|
|
|
|
0, or make a valid null pointer. We can try to bzero the space,
|
|
|
|
or just save it as 0 (or (void *)0). If we do the latter, make
|
|
|
|
sure restore_variable is changed to understand it. */
|
1996-08-26 18:22:31 +00:00
|
|
|
s->desired_setting = (char *)xmalloc (size);
|
1997-06-05 14:59:13 +00:00
|
|
|
if (value == 0)
|
|
|
|
bzero ((char *)s->desired_setting, size);
|
|
|
|
else
|
|
|
|
FASTCOPY (value, (char *)s->desired_setting, size);
|
1996-08-26 18:22:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
s->desired_setting = value;
|
|
|
|
s->size = size;
|
|
|
|
add_unwind_protect ((Function *)restore_variable, (char *)s);
|
|
|
|
}
|