1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

command -x: fix efficiency; always run external cmd (re: acf84e96)

This commit fixes 'command -x' to adapt to OS limitations with
regards to data alignment in the arguments list. A feature test is
added that detects if the OS aligns the argument on 32-bit or
64-bit boundaries or not at all, allowing 'command -x' to avoid
E2BIG errors while maximising efficiency.

Also, as of now, 'command -x' is a way to bypass built-ins and
run/query an external command. Built-ins do not limit the length of
their argument list, so '-x' never made sense to use for them. And
because '-x' hangs on Linux and macOS on every ksh93 release
version to date (see acf84e96), few use it, so there is little
reason not to make this change.

Finally, this fixes a longstanding bug that caused the minimum exit
status of 'command -x' to be 1 if a command with many arguments was
divided into several command invocations. This is done by replacing
broken flaggery with a new SH_XARG state flag bit.

src/cmd/ksh93/features/externs:
- Add new C feature test detecting byte alignment in args list.
  The test writes a #define ARG_ALIGN_BYTES with the amount of
  bytes the OS aligns arguments to, or zero for no alignment.

src/cmd/ksh93/include/defs.h:
- Add new SH_XARG state bit indicating 'command -x' is active.

src/cmd/ksh93/sh/path.c: path_xargs():
- Leave extra 2k in the args buffer instead of 1k, just to be sure;
  some commands add large environment variables these days.
- Fix a bug in subtracting the length of existing arguments and
  environment variables. 'size -= strlen(cp)-1;' subtracts one less
  than the size of cp, which makes no sense; what is necessary is
  to substract the length plus one to account for the terminating
  zero byte, i.e.: 'size -= strlen(cp)+1'.
- Use the ARG_ALIGN_BYTES feature test result to match the OS's
  data alignment requirements.
- path_spawn(): E2BIG: Change to checking SH_XARG state bit.

src/cmd/ksh93/bltins/whence.c: b_command():
- Allow combining -x with -p, -v and -V with the expected results
  by setting P_FLAG to act like 'whence -p'. E.g., as of now,
	command -xv printf
  is equivalent to
	whence -p printf
  but note that 'whence' has no equivalent of 'command -pvx printf'
  which searches $(getconf PATH) for a command.
- When -x will run a command, now set the new SH_XARG state flag.

src/cmd/ksh93/sh/xec.c: sh_exec():
- Change to using the new SH_XARG state bit.
- Skip the check for built-ins if SH_XARG is active, so that
  'command -x' now always runs an external command.

src/lib/libcmd/date.c, src/lib/libcmd/uname.c:
- These path-bound builtins sometimes need to run the external
  system command by the same name, but they did that by hardcoding
  an unportable direct path. Now that 'command -x' runs an external
  command, change this to using 'command -px' to guarantee using
  the known-good external system utility in the default PATH.
- In date.c, fix the format string passed to 'command -px date'
  when setting the date; it was only compatible with BSD systems.
  Use the POSIX variant on non-BSD systems.
This commit is contained in:
Martijn Dekker 2021-01-30 05:51:22 +00:00
parent 005d38f410
commit 66e1d44642
12 changed files with 239 additions and 75 deletions

View file

@ -467,40 +467,47 @@ USAGE_LICENSE
;
const char sh_optcommand[] =
"[-1c?\n@(#)$Id: command (AT&T Research/ksh93) 2020-09-09 $\n]"
"[-1c?\n@(#)$Id: command (AT&T Research/ksh93) 2021-01-30 $\n]"
USAGE_LICENSE
"[+NAME?command - execute a simple command disabling special properties]"
"[+DESCRIPTION?Without \b-v\b or \b-V\b, \bcommand\b executes \acommand\a "
"[+DESCRIPTION?Without \b-v\b or \b-V\b, \bcommand\b executes \acmd\a "
"with arguments given by \aarg\a, suppressing the shell function lookup "
"that normally occurs. If \acommand\a is a special built-in command, "
"that normally occurs. If \acmd\a is a special built-in command, "
"then the special properties are removed so that failures will not "
"cause the script that executes it to terminate and preceding "
"assignments will not persist beyond the command invocation. "
"If \acommand\a is a declaration built-in command and the "
"If \acmd\a is a declaration built-in command and the "
"\b-o posix\b shell option is on, then the declaration properties are "
"removed so that arguments containing \b=\b are not treated specially.]"
"[+?With the \b-v\b or \b-V\b options, \bcommand\b is equivalent to the "
"\bwhence\b(1) command.]"
"[p?Instead of \b$PATH\b, search the OS's default utility path as output by "
"\bgetconf PATH\b.]"
"[v?Equivalent to \bwhence\b \acommand\a [\aarg\a ...]].]"
"[x?If \acommand\a fails because there are too many \aarg\as, it will be "
"invoked multiple times with a subset of the arguments on each "
"invocation. Arguments that occur prior to the first word that expand "
"to multiple arguments and arguments that occur after the last word "
"that expands to multiple arguments will be passed on each invocation. "
"The exit status will be the maximum invocation exit status.]"
"[V?Equivalent to \bwhence \b-v\b \acommand\a [\aarg\a ...]].]"
"[v?Equivalent to \bwhence\b \acmd\a [\aarg\a ...]].]"
"[V?Equivalent to \bwhence \b-v\b \acmd\a [\aarg\a ...]].]"
"[x?Search \acmd\a as an external command, bypassing built-ins. "
"If the \aarg\as include a word "
"such as \b\"$@\"\b or \b\"${array[@]]}\"\b "
"that expands to multiple arguments, "
"and the size of the expanded \aarg\a list "
"exceeds \bgetconf ARG_MAX\b bytes, "
"then \acmd\a will be run multiple times, "
"dividing the \aarg\as over the invocations. "
"Any \aarg\as that come before the first \b\"$@\"\b or similar, "
"as well as any that follow the last such word, "
"are considered static and will be repeated for each invocation "
"so as to allow all invocations to use the same command options. "
"The exit status will be the highest returned by the invocations.]"
"\n"
"\n[command [arg ...]]\n"
"\n[cmd [arg ...]]\n"
"\n"
"[+EXIT STATUS?If \acommand\a is invoked, the exit status of \bcommand\b "
"will be that of \acommand\a. Otherwise, it will be one of "
"[+EXIT STATUS?If \acmd\a is invoked, the exit status of \bcommand\b "
"will be that of \acmd\a. Otherwise, it will be one of "
"the following:]{"
"[+0?\bcommand\b completed successfully.]"
"[+>0?\b-v\b or \b-V\b has been specified and an error occurred.]"
"[+126?\acommand\a was found but could not be invoked.]"
"[+127?\acommand\a could not be found.]"
"[+126?\acmd\a was found but could not be invoked.]"
"[+127?\acmd\a could not be found.]"
"}"
"[+SEE ALSO?\bwhence\b(1), \bgetconf\b(1)]"