aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/xargs.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/posix/xargs.c')
-rw-r--r--toys/posix/xargs.c98
1 files changed, 42 insertions, 56 deletions
diff --git a/toys/posix/xargs.c b/toys/posix/xargs.c
index 6ba5fb07..f76a5fce 100644
--- a/toys/posix/xargs.c
+++ b/toys/posix/xargs.c
@@ -10,7 +10,7 @@
* TODO: -x Exit if can't fit everything in one command
* TODO: -P NUM Run up to NUM processes at once
-USE_XARGS(NEWTOY(xargs, "^E:optrn#<1(max-args)s#0[!0E]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_XARGS(NEWTOY(xargs, "^E:P#optrn#<1(max-args)s#0[!0E]", TOYFLAG_USR|TOYFLAG_BIN))
config XARGS
bool "xargs"
@@ -36,7 +36,7 @@ config XARGS
#include "toys.h"
GLOBALS(
- long s, n;
+ long s, n, P;
char *E;
long entries, bytes;
@@ -44,7 +44,7 @@ GLOBALS(
FILE *tty;
)
-// If entry==NULL count TT.bytes and TT.entries, stopping at max.
+// If !entry count TT.bytes and TT.entries, stopping at max.
// Otherwise, fill out entry[].
// Returning NULL means need more data.
@@ -55,12 +55,10 @@ GLOBALS(
static char *handle_entries(char *data, char **entry)
{
if (TT.delim) {
- char *s = data;
+ char *save, *s = data;
// Chop up whitespace delimited string into args
while (*s) {
- char *save;
-
while (isspace(*s)) {
if (entry) *s = 0;
s++;
@@ -80,11 +78,7 @@ static char *handle_entries(char *data, char **entry)
if (!*s || isspace(*s)) break;
s++;
}
- if (TT.E) {
- int len = s-save;
- if (len == strlen(TT.E) && !strncmp(save, TT.E, len))
- return (char *)2;
- }
+ if (TT.E && strstart(&save, TT.E)) return (char *)2;
if (entry) entry[TT.entries] = save;
++TT.entries;
}
@@ -92,32 +86,30 @@ static char *handle_entries(char *data, char **entry)
// -0 support
} else {
TT.bytes += sizeof(char *)+strlen(data)+1;
- if (TT.s && TT.bytes >= TT.s) return data;
- if (TT.n && TT.entries >= TT.n) return data;
+ if ((TT.s && TT.bytes >= TT.s) || (TT.n && TT.entries >= TT.n)) return data;
if (entry) entry[TT.entries] = data;
TT.entries++;
}
- return NULL;
+ return 0;
}
void xargs_main(void)
{
- struct double_list *dlist = NULL, *dtemp;
+ struct double_list *dlist = 0, *dtemp;
int entries, bytes, done = 0, ran_once = 0, status;
- char *data = NULL, **out;
+ char *data = 0, **out;
pid_t pid;
- long posix_max_bytes;
// POSIX requires that we never hit the ARG_MAX limit, even if we try to
// with -s. POSIX also says we have to reserve 2048 bytes "to guarantee
// 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.
- posix_max_bytes = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048;
- if (!TT.s || TT.s > posix_max_bytes) TT.s = posix_max_bytes;
+ bytes = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048;
+ if (!TT.s || TT.s > bytes) TT.s = bytes;
- if (!FLAG(0)) TT.delim = '\n';
+ TT.delim = '\n'*!FLAG(0);
// If no optargs, call echo.
if (!toys.optc) {
@@ -126,15 +118,13 @@ void xargs_main(void)
toys.optc = 1;
}
+ // count entries
for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++)
bytes += strlen(toys.optargs[entries]);
-
- if (bytes >= TT.s) error_exit("can't fit single argument");
+ if (bytes >= TT.s) error_exit("argument too long");
// Loop through exec chunks.
while (data || !done) {
- int doit = 1;
-
TT.entries = 0;
TT.bytes = bytes;
@@ -144,19 +134,17 @@ void xargs_main(void)
// Read line
if (!data) {
ssize_t l = 0;
- l = getdelim(&data, (size_t *)&l, TT.delim, stdin);
-
- if (l<0) {
+ if (getdelim(&data, (size_t *)&l, TT.delim, stdin)<0) {
data = 0;
done++;
+
break;
}
}
dlist_add(&dlist, data);
// Count data used
- data = handle_entries(data, NULL);
- if (!data) continue;
+ if (!(data = handle_entries(data, 0))) continue;
if (data == (char *)2) done++;
if ((unsigned long)data <= 2) data = 0;
else data = xstrdup(data);
@@ -164,9 +152,9 @@ void xargs_main(void)
break;
}
- if (TT.entries == 0) {
+ if (!TT.entries) {
if (data) error_exit("argument too long");
- else if (ran_once) xexit();
+ else if (ran_once) return;
else if (FLAG(r)) continue;
}
@@ -186,37 +174,35 @@ void xargs_main(void)
if (FLAG(p)) {
fprintf(stderr, "?");
if (!TT.tty) TT.tty = xfopen("/dev/tty", "re");
- doit = fyesno(TT.tty, 0);
+ if (!fyesno(TT.tty, 0)) goto skip;
} else fprintf(stderr, "\n");
}
- if (doit) {
- if (!(pid = XVFORK())) {
- xclose(0);
- if (open(FLAG(o) ? "/dev/tty" : "/dev/null", O_RDONLY) != 0)
- perror_exit("child stdin open");
- xexec(out);
- }
- waitpid(pid, &status, 0);
-
- // xargs is yet another weird collection of exit value special cases,
- // different to all the others.
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) == 126 || WEXITSTATUS(status) == 127) {
- toys.exitval = WEXITSTATUS(status);
- xexit();
- } else if (WEXITSTATUS(status) >= 1 && WEXITSTATUS(status) <= 125) {
- toys.exitval = 123;
- } else if (WEXITSTATUS(status) == 255) {
- error_msg("%s: exited with status 255; aborting", out[0]);
- toys.exitval = 124;
- xexit();
- }
- } else toys.exitval = 127;
+ if (!(pid = XVFORK())) {
+ close(0);
+ xopen_stdio(FLAG(o) ? "/dev/tty" : "/dev/null", O_RDONLY);
+ xexec(out);
}
- ran_once = 1;
+ waitpid(pid, &status, 0);
+
+ // xargs is yet another weird collection of exit value special cases,
+ // different from all the others.
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 126 || WEXITSTATUS(status) == 127) {
+ toys.exitval = WEXITSTATUS(status);
+ return;
+ } else if (WEXITSTATUS(status) >= 1 && WEXITSTATUS(status) <= 125) {
+ toys.exitval = 123;
+ } else if (WEXITSTATUS(status) == 255) {
+ error_msg("%s: exited with status 255; aborting", out[0]);
+ toys.exitval = 124;
+ return;
+ }
+ } else toys.exitval = 127;
// Abritrary number of execs, can't just leak memory each time...
+skip:
+ ran_once = 1;
while (dlist) {
struct double_list *dtemp = dlist->next;