diff --git a/NEWS b/NEWS index 58d1854e8fa8..afdf739ffab7 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,11 @@ This documents significant changes in the dev branch of ksh 93u+m. For full details, see the git log at: https://github.com/ksh93/ksh Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. +2024-12-18: + +- Persuant to POSIX.1-2024, exec(1) will no longer cause the shell to exit + when it fails to replace an interactive shell with the given command. + 2024-12-08: - [v1.1] Fixed a bug in the test and [ built-in commands where superfluous diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 639879835976..d69cfb1d38c7 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -18,7 +18,7 @@ #include #include "git.h" -#define SH_RELEASE_DATE "2024-12-08" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2024-12-18" /* must be in this format for $((.sh.version)) */ /* * This comment keeps SH_RELEASE_DATE a few lines away from SH_RELEASE_SVER to avoid * merge conflicts when cherry-picking dev branch commits onto a release branch. diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c index 4d8ef4591972..88dd83851083 100644 --- a/src/cmd/ksh93/sh/path.c +++ b/src/cmd/ksh93/sh/path.c @@ -1001,8 +1001,20 @@ noreturn void path_exec(const char *arg0,char *argv[],struct argnod *local) pp = path_nextcomp(pp,arg0,0); } while(pp); - /* force an exit */ - ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT; + if(sh_isstate(SH_EXEC) && sh_isstate(SH_INTERACTIVE)) + { + /* + * An error just occurred and the shell cannot exit because it's + * interactive. Reincrement SHLVL and turn off the SH_EXEC state. + */ + sh.shlvl++; + sh_offstate(SH_EXEC); + } + else + { + /* Force an exit */ + ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT; + } errno = not_executable ? not_executable : sh.path_err; switch(errno) { diff --git a/src/cmd/ksh93/tests/path.sh b/src/cmd/ksh93/tests/path.sh index 6e3f233f0a53..c8561a8f1003 100755 --- a/src/cmd/ksh93/tests/path.sh +++ b/src/cmd/ksh93/tests/path.sh @@ -1037,5 +1037,17 @@ got=${ type -t whence_t_test 2>&1; } (((e = $?) > 1)) && err_exit 'getconf builtin fails when on same path as external getconf' \ "(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"))" +# ====== +# POSIX.1-2024: If the exec command fails ... an interactive shell may exit from a +# subshell environment but shall not exit if the current shell environment +# is not a subshell environment. +# https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_21 +if((!SHOPT_SCRIPTONLY));then +exp=0 +output=$($SHELL -ic $'PATH=/dev/null exec notacommand\nexit 0' 2>&1) +got=$? +((got==exp)) || err_exit "interactive shells exit after exec(1) fails to run a command (expected status '$exp', got status '$got' with output $(printf %q "$output"))" +fi # !SHOPT_SCRIPTONLY + # ====== exit $((Errors<125?Errors:125))