diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/builtin.c | 38 | ||||
-rw-r--r-- | Src/exec.c | 16 |
2 files changed, 45 insertions, 9 deletions
diff --git a/Src/builtin.c b/Src/builtin.c index 815ec0aca..9f5afc32e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3202,6 +3202,11 @@ err: return 0; } +/* Flag that we should exit the shell as soon as all functions return. */ +/**/ +int +exit_pending; + /* break, bye, continue, exit, logout, return -- most of these take * * one numeric argument, and the other (logout) is related to return. * * (return is treated as a logout when in a login shell.) */ @@ -3248,10 +3253,22 @@ bin_break(char *name, char **argv, char *ops, int func) zerrnam(name, "not login shell", NULL, 0); return 1; } - zexit(num, 0); - break; + /*FALLTHROUGH*/ case BIN_EXIT: - zexit(num, 0); + if (locallevel) { + /* + * We don't exit directly from functions to allow tidying + * up, in particular EXIT traps. We still need to perform + * the usual interactive tests to see if we can exit at + * all, however. + */ + if (stopmsg || (zexit(0,2), !stopmsg)) { + retflag = 1; + breaks = loops; + exit_pending = (num << 1) | 1; + } + } else + zexit(num, 0); break; } return 0; @@ -3290,16 +3307,19 @@ checkjobs(void) } /* exit the shell. val is the return value of the shell. * - * from_signal should be non-zero if zexit is being called * - * because of a signal. */ + * from_where is + * 1 if zexit is called because of a signal + * 2 if we can't actually exit yet (e.g. functions need + * terminating) but should perform the usual interactive tests. + */ /**/ mod_export void -zexit(int val, int from_signal) +zexit(int val, int from_where) { static int in_exit; - if (isset(MONITOR) && !stopmsg && !from_signal) { + if (isset(MONITOR) && !stopmsg && from_where != 1) { scanjobs(); /* check if jobs need printing */ if (isset(CHECKJOBS)) checkjobs(); /* check if any jobs are running/stopped */ @@ -3308,12 +3328,12 @@ zexit(int val, int from_signal) return; } } - if (in_exit++ && from_signal) + if (from_where == 2 || (in_exit++ && from_where)) return; if (isset(MONITOR)) { /* send SIGHUP to any jobs left running */ - killrunjobs(from_signal); + killrunjobs(from_where == 1); } if (isset(RCS) && interact) { if (!nohistsave) diff --git a/Src/exec.c b/Src/exec.c index 17ba376dd..c55494b96 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3429,6 +3429,22 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval) if (noreturnval) lastval = oldlastval; popheap(); + + if (exit_pending) { + if (locallevel) { + /* Still functions to return: force them to do so. */ + retflag = 1; + breaks = loops; + } else { + /* + * All functions finished: time to exit the shell. + * We already did the `stopmsg' test when the + * exit command was handled. + */ + stopmsg = 1; + zexit(exit_pending >> 1, 0); + } + } } /* This finally executes a shell function and any function wrappers * |