aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2019-10-24 19:41:09 -0500
committerRob Landley <rob@landley.net>2019-10-24 19:41:09 -0500
commit1f5f147a9ec048897c43e2358223430098493497 (patch)
treea8bebfb7fe4dd008d7420a9d609eb304d26c4eed
parent69efea9cc568b3906340ddf45df66db811d4f204 (diff)
downloadtoybox-1f5f147a9ec048897c43e2358223430098493497.tar.gz
Fix the xargs argument too long problem by putting the proper accounting
back when they haven't specified -s, add tests.
-rw-r--r--tests/xargs.test9
-rw-r--r--toys/posix/xargs.c12
2 files changed, 14 insertions, 7 deletions
diff --git a/tests/xargs.test b/tests/xargs.test
index e2eec036..afed8a17 100644
--- a/tests/xargs.test
+++ b/tests/xargs.test
@@ -52,6 +52,15 @@ testing "false" "xargs false; echo \$?" "123\n" "" ""
testing "exit 255" "xargs sh -c 'exit 255' 2>&1; echo \$?" \
"xargs: sh: exited with status 255; aborting\n124\n" "" ""
+# findutils maxes out at 131066 (they do the math wrong), kernel takes 131071.
+toyonly testing "max argument size" \
+ "head -c 131071 /dev/zero | tr '\0' x | xargs | wc -c" "131072\n" "" ""
+X=$(head -c 131066 /dev/zero | tr '\0' x)
+# This goes over the kernel's 10 meg limit
+testing "big input forces split" \
+ 'for i in $(seq 1 100);do echo $X;done|{ xargs >/dev/null && echo yes;}' \
+ "yes\n" "" ""
+
# TODO: what exactly is -x supposed to do? why does coreutils output "one"?
#testing "-x" "xargs -x -s 9 || echo expected" "one\nexpected\n" "" "one\ntwo\nthree"
diff --git a/toys/posix/xargs.c b/toys/posix/xargs.c
index a8ecd4d6..725eb593 100644
--- a/toys/posix/xargs.c
+++ b/toys/posix/xargs.c
@@ -64,11 +64,10 @@ static char *handle_entries(char *data, char **entry)
if (!*s) break;
save = ss = s;
- // We ought to add sizeof(char *) to TT.bytes to be correct, but we don't
- // for bug compatibility with busybox 1.30.1 and findutils 4.7.0.
-
+ // Specifying -s can cause "argument too long" errors.
+ if (!FLAG(s)) TT.bytes += sizeof(void *)+1;
for (;;) {
- if (++TT.bytes >= TT.s && TT.s) return save;
+ if (++TT.bytes >= TT.s) return save;
if (!*s || isspace(*s)) break;
s++;
}
@@ -102,8 +101,7 @@ void xargs_main(void)
// that the invoked utility has room to modify its environment variables
// and command line arguments and still be able to invoke another utility",
// though obviously that's not really something you can guarantee.
- bytes = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048;
- if (!TT.s || TT.s > bytes) TT.s = bytes;
+ if (!FLAG(s)) TT.s = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048;
TT.delim = '\n'*!FLAG(0);
@@ -116,7 +114,7 @@ void xargs_main(void)
// count entries
for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++)
- bytes += strlen(toys.optargs[entries]);
+ bytes += strlen(toys.optargs[entries]) + sizeof(char *)*!FLAG(s);
if (bytes >= TT.s) error_exit("argument too long");
// Loop through exec chunks.