From 3e79027cd166bf9e0569671195e94bd2e3a0c4dc Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 24 Jul 2022 07:26:43 +0200 Subject: [PATCH] 'command -x': also bypass path-bound built-ins (re: 66e1d446) Since 'command -x' provides xargs-like functionality to repeatedly run external commands if the argument list is too long for one invocation, it makes little sense to use with built-ins. So I decided that 'command -x' should double as a way to guarantee running an external command. However, it was only bypassing plain built-ins and not path-bound builtins (the ones that show up with a virtual directory path name in the output of 'builtin'). src/cmd/ksh93/sh/path.c: - Before looking for a path-bound built-in, check that the SH_XARG state bit is not on. This needs to be done in path_absolute() as well as in path_spawn(). --- NEWS | 3 +++ src/cmd/ksh93/sh/path.c | 4 ++-- src/cmd/ksh93/tests/path.sh | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index ad0b6ec15..03426fa0e 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,9 @@ Any uppercase BUG_* names are modernish shell bug IDs. - Fixed a bug that caused the -b/--notify option to only notify on one job if more than one background job completed at the same time. +- Fixed a bug in the 'command -x' feature introduced on 2021-01-30; it is meant + to always run an external command, but failed to bypass path-bound builtins. + 2022-07-21: - Fixed a bug where a reproducible $RANDOM sequence (after assigning a diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c index 50d6ad864..4eeee6a35 100644 --- a/src/cmd/ksh93/sh/path.c +++ b/src/cmd/ksh93/sh/path.c @@ -757,7 +757,7 @@ Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp, int flag) int n; #endif /* Handle default path-bound builtins */ - if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0)) + if(!sh_isstate(SH_XARG) && *stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0)) return(oldpp); #if SHOPT_DYNAMIC /* Load builtins from dynamic libraries */ @@ -1054,7 +1054,7 @@ pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t char *s, *v; int r, n, pidsize; pid_t pid= -1; - if(nv_search(opath,sh.bltin_tree,0)) + if(!sh_isstate(SH_XARG) && nv_search(opath,sh.bltin_tree,0)) { /* Found a path-bound built-in. Since this was not caught earlier in sh_exec(), it must have been found on a temporarily assigned PATH, as with 'PATH=/opt/ast/bin:$PATH cat'. diff --git a/src/cmd/ksh93/tests/path.sh b/src/cmd/ksh93/tests/path.sh index 35f7624d2..d4263213f 100755 --- a/src/cmd/ksh93/tests/path.sh +++ b/src/cmd/ksh93/tests/path.sh @@ -518,6 +518,15 @@ then "(expected $(printf %q "$exp"), got $(printf %q "$got"))" fi +# Check that adding '-x' runs an external command, also bypassing path-bound builtins +if ! test -x /opt/ast/bin/cat # a physical external utility here would invalidate these tests +then + got=$( PATH=/opt/ast/bin; command -x cat --about 2>&1 ) + [[ $got == *version*'cat ('* ]] && err_exit 'command -x fails to bypass path-bound built-in found in PATH search' + got=$( command -x /opt/ast/bin/cat --about 2>&1 ) + [[ $got == *version*'cat ('* ]] && err_exit 'command -x fails to bypass path-bound built-in by direct pathname' +fi + # ====== # 'command -x' used to hang in an endless E2BIG loop on Linux and macOS ofile=$tmp/command_x_chunks.sh