1
0
Fork 0
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:
Johnothan King 2021-04-14 19:37:57 -07:00 committed by GitHub
parent df47731d7d
commit 2c38fb93fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 254 additions and 43 deletions

9
NEWS
View file

@ -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

View file

@ -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";

View file

@ -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[];

View file

@ -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. */

View file

@ -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:

View file

@ -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();

View file

@ -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))

View file

@ -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

View file

@ -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*);