mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 19:52:20 +00:00
command -x: tweak args list size detection (re: 9ddb45b1
)
src/cmd/ksh93/features/externs: ARG_EXTRA_BYTES detection: - Improve detection of extra bytes per argument: on every loop iteration, recalculate the size of the environment while taking the amount extra bytes we're currently trying into account. Also count arguments (argv[]) as they are stored in the same buffer. On 64-bit Linux with glibc, this now detects 9 extra bytes per argument instead of 8. An odd number (literally and figuratively) but apparently it needs it; I do think my method is correct now. On 64-bit Solaris and macOS, this still detects 8 extra bytes. (On 64-bit Linux with musl C library, it detects 0 bytes. Nice.) src/cmd/ksh93/sh/path.c: path_xargs(): - Remove the kludge subtracting twice the size of the environment. With the feature test fixed, this should no longer fail on Linux. - Take into account the size of the final null element in the argument and environment lists. src/cmd/ksh93/tests/path.sh: - Do not use awk for the test due to breakage in the system awks on Solaris/Illumos (hangs) and AIX & UnixWare (drops arguments). Instead, use (wait for it...) ksh. It's a bit slower, but works.
This commit is contained in:
parent
8c1e9971a7
commit
6f6b22016a
3 changed files with 31 additions and 22 deletions
|
@ -17,8 +17,8 @@ tst note{ determining extra bytes per argument for arguments list }end output{
|
||||||
* Figure out if this OS requires extra bytes per argument
|
* Figure out if this OS requires extra bytes per argument
|
||||||
* in the arguments list of a process.
|
* in the arguments list of a process.
|
||||||
* Outputs an appropriate #define ARG_EXTRA_BYTES.
|
* Outputs an appropriate #define ARG_EXTRA_BYTES.
|
||||||
* Without this, 'command -x' failed with E2BIG on macOS and Linux even
|
* Without this, 'command -x' failed with E2BIG on macOS, Linux and Solaris
|
||||||
* if all the arguments should fit in ARG_MAX based on their length.
|
* even if all the arguments should fit in ARG_MAX based on their length.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* AST includes */
|
/* AST includes */
|
||||||
|
@ -43,20 +43,25 @@ tst note{ determining extra bytes per argument for arguments list }end output{
|
||||||
|
|
||||||
int main(int argc,char *argv[])
|
int main(int argc,char *argv[])
|
||||||
{
|
{
|
||||||
int extra_bytes = 0, envlen = 0, argmax, i;
|
int extra_bytes = 0, envlen, argmax, i;
|
||||||
pid_t childpid;
|
pid_t childpid;
|
||||||
|
|
||||||
error_info.id="ARG_EXTRA_BYTES test (parent)";
|
error_info.id="ARG_EXTRA_BYTES test (parent)";
|
||||||
for(i=0; environ[i]; i++)
|
|
||||||
envlen += strlen(environ[i]) + 1;
|
|
||||||
argmax = strtoimax(astconf("ARG_MAX",NiL,NiL),NiL,0) - 2 * envlen;
|
|
||||||
if (argmax < 2048)
|
|
||||||
{
|
|
||||||
error(ERROR_ERROR|2, "argmax too small");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
envlen = 0;
|
||||||
|
for(i=0; argv[i]; i++)
|
||||||
|
envlen += strlen(argv[i]) + 1 + extra_bytes;
|
||||||
|
envlen += 1 + extra_bytes; /* final null element */
|
||||||
|
for(i=0; environ[i]; i++)
|
||||||
|
envlen += strlen(environ[i]) + 1 + extra_bytes;
|
||||||
|
envlen += 1 + extra_bytes; /* final null element */
|
||||||
|
argmax = strtoimax(astconf("ARG_MAX",NiL,NiL),NiL,0) - envlen;
|
||||||
|
if (argmax < 2048)
|
||||||
|
{
|
||||||
|
error(ERROR_ERROR|2, "argmax too small");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if(!(childpid = fork()))
|
if(!(childpid = fork()))
|
||||||
{
|
{
|
||||||
/* child */
|
/* child */
|
||||||
|
@ -122,5 +127,5 @@ tst note{ determining extra bytes per argument for arguments list }end output{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}end fail{
|
}end fail{
|
||||||
echo "#define ARG_EXTRA_BYTES 8 /* BUG: test failed; assuming 8 */"
|
echo "#define ARG_EXTRA_BYTES 16 /* BUG: test failed; assuming 16 */"
|
||||||
}end
|
}end
|
||||||
|
|
|
@ -164,11 +164,12 @@ static pid_t path_xargs(Shell_t *shp,const char *path, char *argv[],char *const
|
||||||
return((pid_t)-1);
|
return((pid_t)-1);
|
||||||
size = shp->gd->lim.arg_max - (ARG_EXTRA_BYTES > 2 ? 1024*ARG_EXTRA_BYTES : 2048);
|
size = shp->gd->lim.arg_max - (ARG_EXTRA_BYTES > 2 ? 1024*ARG_EXTRA_BYTES : 2048);
|
||||||
for(ev=envp; cp= *ev; ev++)
|
for(ev=envp; cp= *ev; ev++)
|
||||||
size -= 2 * (strlen(cp) + 1 + ARG_EXTRA_BYTES);
|
size -= strlen(cp) + 1 + ARG_EXTRA_BYTES;
|
||||||
for(av=argv; (cp= *av) && av< &argv[shp->xargmin]; av++)
|
for(av=argv; (cp= *av) && av< &argv[shp->xargmin]; av++)
|
||||||
size -= strlen(cp) + 1 + ARG_EXTRA_BYTES;
|
size -= strlen(cp) + 1 + ARG_EXTRA_BYTES;
|
||||||
for(av=avlast; cp= *av; av++,nlast++)
|
for(av=avlast; cp= *av; av++,nlast++)
|
||||||
size -= strlen(cp) + 1 + ARG_EXTRA_BYTES;
|
size -= strlen(cp) + 1 + ARG_EXTRA_BYTES;
|
||||||
|
size -= 2 + 2 * ARG_EXTRA_BYTES; /* final null env and arg elements */
|
||||||
av = &argv[shp->xargmin];
|
av = &argv[shp->xargmin];
|
||||||
if(!spawn)
|
if(!spawn)
|
||||||
job_clear();
|
job_clear();
|
||||||
|
|
|
@ -542,7 +542,7 @@ fi
|
||||||
ofile=$tmp/command_x_chunks.sh
|
ofile=$tmp/command_x_chunks.sh
|
||||||
trap 'sleep_pid=; while kill -9 $pid; do :; done 2>/dev/null; err_exit "'\''command -x'\'' hung"' TERM
|
trap 'sleep_pid=; while kill -9 $pid; do :; done 2>/dev/null; err_exit "'\''command -x'\'' hung"' TERM
|
||||||
trap 'kill $sleep_pid; while kill -9 $pid; do :; done 2>/dev/null; trap - INT; kill -s INT $$"' INT
|
trap 'kill $sleep_pid; while kill -9 $pid; do :; done 2>/dev/null; trap - INT; kill -s INT $$"' INT
|
||||||
{ sleep 15; kill $$; } &
|
{ sleep 60; kill $$; } &
|
||||||
sleep_pid=$!
|
sleep_pid=$!
|
||||||
(
|
(
|
||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
|
@ -558,14 +558,17 @@ sleep_pid=$!
|
||||||
done
|
done
|
||||||
print "chunks=0 expargs=$# args=0 expsize=$((${#args}+1)) size=0"
|
print "chunks=0 expargs=$# args=0 expsize=$((${#args}+1)) size=0"
|
||||||
unset args
|
unset args
|
||||||
command -px awk 'BEGIN {
|
command -x "$SHELL" -c '
|
||||||
ARGC -= 2; # final static args
|
integer i size=0 numargs=${#}-2
|
||||||
for (i=1; i<ARGC; i++)
|
for ((i=numargs; i; i--))
|
||||||
size += length(ARGV[i]) + 1;
|
do let "size += ${#1} + 1"
|
||||||
print ("let chunks++ args+=")(ARGC - 1)(" size+=")(size);
|
shift
|
||||||
if(ARGV[ARGC] != "static_arg_1" || ARGV[ARGC+1] != "final_static_arg_2")
|
done
|
||||||
print "err_exit \"'\''command -x'\'': static final arguments for chunk $chunks incorrect\"";
|
print "let chunks++ args+=$numargs size+=$size"
|
||||||
}' "$@" static_arg_1 final_static_arg_2
|
if [[ $0 != static_argzero || $1 != final_static_arg_1 || $2 != final_static_arg_2 ]]
|
||||||
|
then print "err_exit \"'\''command -x'\'': static arguments for chunk \$chunks incorrect\""
|
||||||
|
fi
|
||||||
|
' static_argzero "$@" final_static_arg_1 final_static_arg_2
|
||||||
) >$ofile &
|
) >$ofile &
|
||||||
pid=$!
|
pid=$!
|
||||||
wait $pid
|
wait $pid
|
||||||
|
|
Loading…
Reference in a new issue