mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 03:32:24 +00:00
Fix the exit status returned when a command isn't executable (#273)
Previous discussion: https://github.com/att/ast/issues/485 If ksh attempts to execute a non-executable command found in the PATH, in some instances the error message and return status are incorrect. In the example below, ksh returns with exit status 126 when using the -c execve(2) optimization or when using fork(2) in an interactive shell. However, using posix_spawn(3) causes the exit status to change: $ echo 'print cannot execute' > /tmp/x # Runs command with spawnveg (i.e., posix_spawn or vfork) $ ksh -c 'PATH=/tmp; x; echo $?' ksh: x: not found 127 # Runs command with execve $ ksh -c 'PATH=/tmp; x'; echo $? ksh: x: cannot execute [Permission denied] 126 # Runs command with fork $ ksh -ic 'PATH=/tmp; x; echo $?' ksh: x: cannot execute [Permission denied] 126 Since 'x' is in the PATH but can't be executed, the correct exit status is 126, not 127. It's worth noting this bug doesn't cause the regression tests to fail with ksh93u+m, but it does cause one test to fail when run under dtksh: path.sh[706]: Long nonexistent command name: got status 126, '' This commit backports various fixes for this bug from ksh2020, with additional fixes applied (since there were still some additional issues the ksh2020 patch didn't fix). The lacking regression test for exit status 126 in path.sh has been rewritten to test for more scenarios where ksh failed to return the correct error message and/or exit status. I can also confirm with this patch applied the path.sh regression tests now pass when run under dtksh. src/cmd/ksh93/sh/path.c: - Add a comment to path_absolute() describing 'oldpp' is the current pointer in the while loop and 'pp' is the next pointer. Backported from: https://github.com/att/ast/commit/a6cad450 - The patch from ksh2020 didn't fix this bug in the SHOPT_SPAWN code (because ksh2020 prefers fork(2)), so issues with the exit status could still occur when using spawnveg. To fix this, always set 'noexec' to the value of errno if can_execute fails. Before this fix, errno was discarded if 'pp' was a null pointer and can_execute failed. - If a command couldn't be executed and the error wasn't ENOENT, save errno in a 'not_executable' variable. If an executable command couldn't be found in the PATH, exit with status 126 and set errno to the saved value. This was based on a ksh2020 bugfix, but it has been reworked a little bit to fix a bug that caused a mismatch between the error message shown and errno. Example with a non-executable file in PATH: $ nonexec ksh2020: nonexec: cannot execute [No such file or directory] The ksh2020 patch: <https://github.com/att/ast/pull/493> - Backport a ksh2020 bugfix for directories in the PATH when running one of the added regression tests on OpenBSD: https://github.com/att/ast/pull/767 src/cmd/ksh93/data/msg.c, src/cmd/ksh93/include/shell.h, src/cmd/ksh93/sh/{path,xec}.c: - If a command name is too long (ENAMETOOLONG), then it wasn't found in the PATH. For that case return exit status 127, like for ENOENT. src/cmd/ksh93/tests/path.sh: - Replace the old test with a new set of more extensive tests. These tests check the error message and exit status when ksh attempts to run a command using any of the following: - execve(2), used with the last command run with -c (*A tests). - posix_spawn(3)/vfork(2), used in noninteractive scripts (*B tests). - fork(2), used in interactive shells with job control (*C tests). - command -x (*D tests). - exec(1) (*E tests). - Add a regression test from ksh2020 for attempting to execute a directory: https://github.com/att/ast/pull/758 src/lib/libast/include/ast.h, src/lib/libast/include/wait.h: - Avoid bitshifts in macros for static error codes. The return values of command not found and exec related errors are static values and should not require any macro magic for calculation. Backported from: https://github.com/att/ast/commit/c073b102 - Simplify EXIT_* and W* macros to use 8 bits.
This commit is contained in:
parent
df47731d7d
commit
2c38fb93fd
9 changed files with 254 additions and 43 deletions
9
NEWS
9
NEWS
|
@ -3,6 +3,15 @@ For full details, see the git log at: https://github.com/ksh93/ksh
|
|||
|
||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||
|
||||
2021-04-13:
|
||||
|
||||
- Fixed a few bugs that could cause ksh to show the wrong error message and/or
|
||||
return the wrong exit status if a command couldn't be executed. In
|
||||
scenarios where the command was found in the PATH but it was not executable,
|
||||
ksh now returns with exit status 126. Otherwise, ksh will return with exit
|
||||
status 127 (such as if the command isn't found or if the command name is
|
||||
too long).
|
||||
|
||||
2021-04-12:
|
||||
|
||||
- Corrected a memory fault when an attempt was made to unset the default
|
||||
|
|
|
@ -83,6 +83,9 @@ const char e_logout[] = "Use 'exit' to terminate this shell";
|
|||
const char e_exec[] = "%s: cannot execute";
|
||||
const char e_pwd[] = "cannot access parent directories";
|
||||
const char e_found[] = "%s: not found";
|
||||
#ifdef ENAMETOOLONG
|
||||
const char e_toolong[] = "%s: file name too long";
|
||||
#endif
|
||||
const char e_defined[] = "%s: function not defined";
|
||||
const char e_nointerp[] = "%s: interpreter not found";
|
||||
const char e_subscript[] = "%s: subscript out of range";
|
||||
|
|
|
@ -147,6 +147,9 @@ typedef union Shnode_u Shnode_t;
|
|||
|
||||
/* error messages */
|
||||
extern const char e_found[];
|
||||
#ifdef ENAMETOOLONG
|
||||
extern const char e_toolong[];
|
||||
#endif
|
||||
extern const char e_format[];
|
||||
extern const char e_number[];
|
||||
extern const char e_restricted[];
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
|
||||
#define SH_RELEASE_SVER "1.0.0-alpha" /* semantic version number: https://semver.org */
|
||||
#define SH_RELEASE_DATE "2021-04-12" /* must be in this format for $((.sh.version)) */
|
||||
#define SH_RELEASE_DATE "2021-04-13" /* must be in this format for $((.sh.version)) */
|
||||
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
|
||||
|
||||
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
||||
|
|
|
@ -769,6 +769,8 @@ Pathcomp_t *path_absolute(Shell_t *shp,register const char *name, Pathcomp_t *pp
|
|||
{
|
||||
sh_sigcheck(shp);
|
||||
shp->bltin_dir = 0;
|
||||
/* In this loop, oldpp is the current pointer.
|
||||
pp is the next pointer. */
|
||||
while(oldpp=pp)
|
||||
{
|
||||
pp = path_nextcomp(shp,pp,name,0);
|
||||
|
@ -901,10 +903,10 @@ Pathcomp_t *path_absolute(Shell_t *shp,register const char *name, Pathcomp_t *pp
|
|||
np->nvflag = n;
|
||||
}
|
||||
}
|
||||
if(f<0 && errno!=ENOENT)
|
||||
noexec = errno;
|
||||
if(!pp || f>=0)
|
||||
break;
|
||||
if(errno!=ENOENT)
|
||||
noexec = errno;
|
||||
}
|
||||
if(f<0)
|
||||
{
|
||||
|
@ -1007,7 +1009,8 @@ noreturn void path_exec(Shell_t *shp,register const char *arg0,register char *ar
|
|||
char **envp;
|
||||
const char *opath;
|
||||
Pathcomp_t *libpath, *pp=0;
|
||||
int slash=0;
|
||||
int slash=0, not_executable=0;
|
||||
pid_t spawnpid;
|
||||
nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
|
||||
envp = sh_envgen();
|
||||
if(strchr(arg0,'/'))
|
||||
|
@ -1038,18 +1041,40 @@ noreturn void path_exec(Shell_t *shp,register const char *arg0,register char *ar
|
|||
}
|
||||
else
|
||||
opath = arg0;
|
||||
path_spawn(shp,opath,argv,envp,libpath,0);
|
||||
spawnpid = path_spawn(shp,opath,argv,envp,libpath,0);
|
||||
if(spawnpid==-1 && shp->path_err!=ENOENT)
|
||||
{
|
||||
/*
|
||||
* A command was found but it couldn't be executed.
|
||||
* POSIX specifies that the shell should continue to search for the
|
||||
* command in PATH and return 126 only when it can't find an executable
|
||||
* file in other elements of PATH.
|
||||
*/
|
||||
not_executable = shp->path_err;
|
||||
}
|
||||
while(pp && (pp->flags&PATH_FPATH))
|
||||
pp = path_nextcomp(shp,pp,arg0,0);
|
||||
}
|
||||
while(pp);
|
||||
/* force an exit */
|
||||
((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
|
||||
if((errno=shp->path_err)==ENOENT)
|
||||
errno = not_executable ? not_executable : shp->path_err;
|
||||
switch(errno)
|
||||
{
|
||||
/* the first two cases return exit status 127 (the command wasn't in the PATH) */
|
||||
case ENOENT:
|
||||
errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
|
||||
else
|
||||
UNREACHABLE();
|
||||
#ifdef ENAMETOOLONG
|
||||
case ENAMETOOLONG:
|
||||
errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_toolong,arg0);
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
/* other cases return exit status 126 (the command was found, but wasn't executable) */
|
||||
default:
|
||||
errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
|
||||
UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
pid_t path_spawn(Shell_t *shp,const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
|
||||
|
@ -1187,6 +1212,8 @@ pid_t path_spawn(Shell_t *shp,const char *opath,register char **argv, char **env
|
|||
return(pid);
|
||||
switch(shp->path_err = errno)
|
||||
{
|
||||
case EISDIR:
|
||||
return -1;
|
||||
case ENOEXEC:
|
||||
#if SHOPT_SUID_EXEC
|
||||
case EPERM:
|
||||
|
|
|
@ -3622,6 +3622,11 @@ static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,in
|
|||
case ENOENT:
|
||||
errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found+4);
|
||||
UNREACHABLE();
|
||||
#ifdef ENAMETOOLONG
|
||||
case ENAMETOOLONG:
|
||||
errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_toolong+4);
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
default:
|
||||
errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4);
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -180,18 +180,7 @@ builtin -d date 2> /dev/null
|
|||
if [[ $(PATH=:/usr/bin; date) != 'hello' ]]
|
||||
then err_exit "leading : in path not working"
|
||||
fi
|
||||
(
|
||||
PATH=$PWD:
|
||||
builtin chmod
|
||||
print 'print cannot execute' > noexec
|
||||
chmod 644 noexec
|
||||
if [[ ! -x noexec ]]
|
||||
then noexec > /dev/null 2>&1
|
||||
else exit 126
|
||||
fi
|
||||
)
|
||||
status=$?
|
||||
[[ $status == 126 ]] || err_exit "exit status of non-executable is $status -- 126 expected"
|
||||
|
||||
builtin -d rm 2> /dev/null
|
||||
chmod=$(whence chmod)
|
||||
rm=$(whence rm)
|
||||
|
@ -734,5 +723,185 @@ PATH=$savePATH
|
|||
[[ -z $got ]] || err_exit "PATH search inconsistent after changing PATH in subshare (got $(printf %q "$got"))"
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
# POSIX: If a command is found but isn't executable, the exit status should be 126.
|
||||
# The tests are arranged as follows:
|
||||
# Test *A runs commands with the -c execve(2) optimization.
|
||||
# Test *B runs commands with spawnveg (i.e., with posix_spawn(3) or vfork(2)).
|
||||
# Test *C runs commands with fork(2) in an interactive shell.
|
||||
# Test *D runs commands with 'command -x'.
|
||||
# Test *E runs commands with 'exec'.
|
||||
# https://github.com/att/ast/issues/485
|
||||
rm -rf noexecute
|
||||
print 'print cannot execute' > noexecute
|
||||
mkdir emptydir cmddir
|
||||
exp=126
|
||||
PATH=$PWD $SHELL -c 'noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 1A: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 1B: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -ic 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 1C: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c 'command -x noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 1D: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c 'exec noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 1E: exit status of exec'd non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
|
||||
# Add an empty directory where the command isn't found.
|
||||
PATH=$PWD:$PWD/emptydir $SHELL -c 'noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 2A: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/emptydir $SHELL -c 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 2B: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/emptydir $SHELL -ic 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 2C: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/emptydir $SHELL -c 'command -x noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 2D: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/emptydir $SHELL -c 'exec noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 2E: exit status of exec'd non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
|
||||
# If an executable command is found after a non-executable command, skip the non-executable one.
|
||||
print 'true' > cmddir/noexecute
|
||||
chmod +x cmddir/noexecute
|
||||
exp=0
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'noexecute'
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 3A: failed to run executable command after encountering non-executable command" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'noexecute; exit $?'
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 3B: failed to run executable command after encountering non-executable command" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -ic 'noexecute; exit $?'
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 3C: failed to run executable command after encountering non-executable command" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'command -x noexecute; exit $?'
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 3D: failed to run executable command after encountering non-executable command" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'exec noexecute'
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 3E: failed to run exec'd executable command after encountering non-executable command" \
|
||||
"(expected $exp, got $got)"
|
||||
|
||||
# Same test as above, but with a directory of the same name in the PATH.
|
||||
rm "$PWD/noexecute"
|
||||
mkdir "$PWD/noexecute"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 4A: failed to run executable command after encountering directory with same name in PATH" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 4B: failed to run executable command after encountering directory with same name in PATH" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -ic 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 4C: failed to run executable command after encountering directory with same name in PATH" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'command -x noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 4D: failed to run executable command after encountering directory with same name in PATH" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD:$PWD/cmddir $SHELL -c 'exec noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 4E: failed to run exec'd executable command after encountering directory with same name in PATH" \
|
||||
"(expected $exp, got $got)"
|
||||
# Don't treat directories as commands.
|
||||
# https://github.com/att/ast/issues/757
|
||||
mkdir cat
|
||||
PATH=".:$PATH" cat < /dev/null || err_exit "Test 4F: directories should not be treated as executables"
|
||||
|
||||
# Test attempts to run directories located in the PATH.
|
||||
exp=126
|
||||
PATH=$PWD $SHELL -c 'noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 5A: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 5B: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -ic 'noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 5C: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c 'command -x noexecute; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 5D: exit status of non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c 'exec noexecute' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 5E: exit status of exec'd non-executable command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
|
||||
# Tests for attempting to run a non-existent command.
|
||||
exp=127
|
||||
PATH=/dev/null $SHELL -c 'nonexist' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 6A: exit status of non-existent command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=/dev/null $SHELL -c 'nonexist; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 6B: exit status of non-existent command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=/dev/null $SHELL -ic 'nonexist; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 6C: exit status of non-existent command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=/dev/null $SHELL -c 'command -x nonexist; exit $?' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 6D: exit status of non-existent command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=/dev/null $SHELL -c 'exec nonexist' > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 6E: exit status of exec'd non-existent command wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
|
||||
# Tests for attempting to use a command name that's too long.
|
||||
# To make the error messages readable, the long string is replaced
|
||||
# with 'LONG_CMD_NAME' in the err_exit output.
|
||||
long_cmd=$(awk -v ORS= 'BEGIN { for(i=0;i<500;i++) print "xxxxxxxxxx"; }')
|
||||
exp=127
|
||||
PATH=$PWD $SHELL -c "$long_cmd" > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 7A: exit status or error message for command with long name wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c "$long_cmd; exit \$?" > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 7B: exit status or error message for command with long name wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -ic "$long_cmd; exit \$?" > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 7C: exit status or error message for command with long name wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c "command -x $long_cmd; exit \$?" > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 7D: exit status or error message for command with long name wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
PATH=$PWD $SHELL -c "exec $long_cmd" > /dev/null 2>&1
|
||||
got=$?
|
||||
[[ $exp == $got ]] || err_exit "Test 7E: exit status or error message for exec'd command with long name wrong" \
|
||||
"(expected $exp, got $got)"
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
|
@ -95,25 +95,20 @@ struct _sfio_s;
|
|||
* exit() support -- this matches shell exit codes
|
||||
*/
|
||||
|
||||
#define EXIT_BITS 8 /* # exit status bits */
|
||||
#define EXIT_BITS 8 /* # exit status bits */
|
||||
|
||||
#define EXIT_USAGE 2 /* usage exit code */
|
||||
#define EXIT_QUIT ((1<<(EXIT_BITS))-1) /* parent should quit */
|
||||
#define EXIT_NOTFOUND ((1<<(EXIT_BITS-1))-1) /* command not found */
|
||||
#define EXIT_NOEXEC ((1<<(EXIT_BITS-1))-2) /* other exec error */
|
||||
#define EXIT_USAGE 2 /* usage exit code */
|
||||
#define EXIT_QUIT 255 /* parent should quit */
|
||||
#define EXIT_NOTFOUND 127 /* command not found */
|
||||
#define EXIT_NOEXEC 126 /* other exec error */
|
||||
|
||||
#define EXIT_CODE(x) ((x)&((1<<EXIT_BITS)-1))
|
||||
#define EXIT_CORE(x) (EXIT_CODE(x)|(1<<EXIT_BITS)|(1<<(EXIT_BITS-1)))
|
||||
#define EXIT_TERM(x) (EXIT_CODE(x)|(1<<EXIT_BITS))
|
||||
#define EXIT_CODE(x) ((x) & EXIT_QUIT)
|
||||
#define EXIT_CORE(x) (EXIT_CODE(x) | 256 | 128)
|
||||
#define EXIT_TERM(x) (EXIT_CODE(x) | 256)
|
||||
|
||||
/*
|
||||
* NOTE: for compatibility the following work for EXIT_BITS={7,8}
|
||||
*/
|
||||
|
||||
#define EXIT_STATUS(x) (((x)&((1<<(EXIT_BITS-2))-1))?(x):EXIT_CODE((x)>>EXIT_BITS))
|
||||
|
||||
#define EXITED_CORE(x) (((x)&((1<<EXIT_BITS)|(1<<(EXIT_BITS-1))))==((1<<EXIT_BITS)|(1<<(EXIT_BITS-1)))||((x)&((1<<(EXIT_BITS-1))|(1<<(EXIT_BITS-2))))==((1<<(EXIT_BITS-1))|(1<<(EXIT_BITS-2))))
|
||||
#define EXITED_TERM(x) ((x)&((1<<EXIT_BITS)|(1<<(EXIT_BITS-1))))
|
||||
#define EXIT_STATUS(x) (((x) & 63) ? (x) : EXIT_CODE((x) >> 8))
|
||||
#define EXITED_CORE(x) (((x) & (256 | 128)) == (256 | 128) || ((x) & (128 | 64)) == (128 | 64))
|
||||
#define EXITED_TERM(x) ((x) & (256 | 128))
|
||||
|
||||
/*
|
||||
* astconflist() flags
|
||||
|
|
|
@ -65,23 +65,23 @@ __STDPP__directive pragma pp:nohide wait waitpid
|
|||
#endif
|
||||
|
||||
#ifndef WIFEXITED
|
||||
#define WIFEXITED(x) (!((x)&((1<<(EXIT_BITS-1))-1)))
|
||||
#define WIFEXITED(x) (!((x) & EXIT_NOTFOUND))
|
||||
#endif
|
||||
|
||||
#ifndef WEXITSTATUS
|
||||
#define WEXITSTATUS(x) (((x)>>EXIT_BITS)&((1<<EXIT_BITS)-1))
|
||||
#define WEXITSTATUS(x) (((x) >> 8) & EXIT_QUIT)
|
||||
#endif
|
||||
|
||||
#ifndef WIFSIGNALED
|
||||
#define WIFSIGNALED(x) (((x)&((1<<(EXIT_BITS-1))-1))!=0)
|
||||
#define WIFSIGNALED(x) (((x) & EXIT_NOTFOUND) != 0)
|
||||
#endif
|
||||
|
||||
#ifndef WTERMSIG
|
||||
#define WTERMSIG(x) ((x)&((1<<(EXIT_BITS-1))-1))
|
||||
#define WTERMSIG(x) ((x) & EXIT_NOTFOUND)
|
||||
#endif
|
||||
|
||||
#ifndef WIFSTOPPED
|
||||
#define WIFSTOPPED(x) (((x)&((1<<EXIT_BITS)-1))==((1<<(EXIT_BITS-1))-1))
|
||||
#define WIFSTOPPED(x) (((x) & EXIT_QUIT) == EXIT_NOTFOUND)
|
||||
#endif
|
||||
|
||||
#ifndef WSTOPSIG
|
||||
|
@ -89,7 +89,7 @@ __STDPP__directive pragma pp:nohide wait waitpid
|
|||
#endif
|
||||
|
||||
#ifndef WTERMCORE
|
||||
#define WTERMCORE(x) ((x)&(1<<(EXIT_BITS-1)))
|
||||
#define WTERMCORE(x) ((x) & 128)
|
||||
#endif
|
||||
|
||||
extern pid_t wait(int*);
|
||||
|
|
Loading…
Reference in a new issue