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

@ -218,37 +218,38 @@ typedef struct Fmt
static int
settime(Shbltin_t* context, const char* cmd, Time_t now, int adjust, int network)
{
char* s;
char** argv;
char* args[5];
char* args[7];
char buf[1024];
if (!adjust && !network)
return tmxsettime(now);
argv = args;
s = "/usr/bin/date";
if (!streq(cmd, s) && (!eaccess(s, X_OK) || !eaccess(s+=4, X_OK)))
*argv++ = "command";
*argv++ = "-px";
*argv++ = "date";
if (streq(astconf("UNIVERSE", NiL, NiL), "att"))
{
*argv++ = s;
if (streq(astconf("UNIVERSE", NiL, NiL), "att"))
{
tmxfmt(buf, sizeof(buf), "%m%d%H" "%M%Y.%S", now);
if (adjust)
*argv++ = "-a";
}
else
{
tmxfmt(buf, sizeof(buf), "%Y%m%d%H" "%M.%S", now);
if (network)
*argv++ = "-n";
if (tm_info.flags & TM_UTC)
*argv++ = "-u";
}
*argv++ = buf;
*argv = 0;
if (!sh_run(context, argv - args, args))
return 0;
tmxfmt(buf, sizeof(buf), "%m%d%H" "%M%Y.%S", now);
if (adjust)
*argv++ = "-a";
}
else
{
#if __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __bsdi__ || __DragonFly__
tmxfmt(buf, sizeof(buf), "%Y%m%d%H" "%M.%S", now);
#else
tmxfmt(buf, sizeof(buf), "%m%d%H" "%M%Y.%S", now);
#endif
if (network)
*argv++ = "-n";
if (tm_info.flags & TM_UTC)
*argv++ = "-u";
}
*argv++ = buf;
*argv = 0;
if (!sh_run(context, argv - args, args))
return 0;
return -1;
}

View file

@ -37,7 +37,7 @@ USAGE_LICENSE
" separated, on a single line. When more than one option is specified"
" the output is in the order specified by the \b-A\b option below."
" Unsupported option values are listed as \a[option]]\a. If any unknown"
" options are specified then the local \b/usr/bin/uname\b is called.]"
" options are specified, the OS default \buname\b(1) is called.]"
"[+?If any \aname\a operands are specified then the \bsysinfo\b(2) values"
" for each \aname\a are listed, separated by space, on one line."
" \bgetconf\b(1), a pre-existing \astandard\a interface, provides"
@ -325,14 +325,14 @@ b_uname(int argc, char** argv, Shbltin_t* context)
sethost = opt_info.arg;
continue;
case ':':
s = "/usr/bin/uname";
if (!streq(argv[0], s) && (!eaccess(s, X_OK) || !eaccess(s+=4, X_OK)))
{
argv[0] = s;
return sh_run(context, argc, argv);
char **new_argv = (char **)stakalloc((argc + 3) * sizeof(char*));
new_argv[0] = "command";
new_argv[1] = "-px";
for (n = 0; n <= argc; n++)
new_argv[n + 2] = argv[n];
return sh_run(context, argc + 2, new_argv);
}
error(2, "%s", opt_info.arg);
break;
case '?':
error(ERROR_usage(2), "%s", opt_info.arg);
break;