10f66f451Sopenharmony_ci/* xargs.c - Run command with arguments taken from stdin. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2011 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * TODO: Rich's whitespace objection, env size isn't fixed anymore. 80f66f451Sopenharmony_ci * TODO: -I Insert mode 90f66f451Sopenharmony_ci * TODO: -L Max number of lines of input per command 100f66f451Sopenharmony_ci * TODO: -x Exit if can't fit everything in one command 110f66f451Sopenharmony_ci * TODO: -P NUM Run up to NUM processes at once 120f66f451Sopenharmony_ci 130f66f451Sopenharmony_ciUSE_XARGS(NEWTOY(xargs, "^E:P#optrn#<1(max-args)s#0[!0E]", TOYFLAG_USR|TOYFLAG_BIN)) 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ciconfig XARGS 160f66f451Sopenharmony_ci bool "xargs" 170f66f451Sopenharmony_ci default y 180f66f451Sopenharmony_ci help 190f66f451Sopenharmony_ci usage: xargs [-0prt] [-s NUM] [-n NUM] [-E STR] COMMAND... 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci Run command line one or more times, appending arguments from stdin. 220f66f451Sopenharmony_ci 230f66f451Sopenharmony_ci If COMMAND exits with 255, don't launch another even if arguments remain. 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci -0 Each argument is NULL terminated, no whitespace or quote processing 260f66f451Sopenharmony_ci -E Stop at line matching string 270f66f451Sopenharmony_ci -n Max number of arguments per command 280f66f451Sopenharmony_ci -o Open tty for COMMAND's stdin (default /dev/null) 290f66f451Sopenharmony_ci -p Prompt for y/n from tty before running each command 300f66f451Sopenharmony_ci -r Don't run command with empty input (otherwise always run command once) 310f66f451Sopenharmony_ci -s Size in bytes per command line 320f66f451Sopenharmony_ci -t Trace, print command line to stderr 330f66f451Sopenharmony_ci*/ 340f66f451Sopenharmony_ci 350f66f451Sopenharmony_ci#define FOR_xargs 360f66f451Sopenharmony_ci#include "toys.h" 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ciGLOBALS( 390f66f451Sopenharmony_ci long s, n, P; 400f66f451Sopenharmony_ci char *E; 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci long entries, bytes; 430f66f451Sopenharmony_ci char delim; 440f66f451Sopenharmony_ci FILE *tty; 450f66f451Sopenharmony_ci) 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_ci// If !entry count TT.bytes and TT.entries, stopping at max. 480f66f451Sopenharmony_ci// Otherwise, fill out entry[]. 490f66f451Sopenharmony_ci 500f66f451Sopenharmony_ci// Returning NULL means need more data. 510f66f451Sopenharmony_ci// Returning char * means hit data limits, start of data left over 520f66f451Sopenharmony_ci// Returning 1 means hit data limits, but consumed all data 530f66f451Sopenharmony_ci// Returning 2 means hit -E STR 540f66f451Sopenharmony_ci 550f66f451Sopenharmony_cistatic char *handle_entries(char *data, char **entry) 560f66f451Sopenharmony_ci{ 570f66f451Sopenharmony_ci if (TT.delim) { 580f66f451Sopenharmony_ci char *save, *s = data; 590f66f451Sopenharmony_ci 600f66f451Sopenharmony_ci // Chop up whitespace delimited string into args 610f66f451Sopenharmony_ci while (*s) { 620f66f451Sopenharmony_ci while (isspace(*s)) { 630f66f451Sopenharmony_ci if (entry) *s = 0; 640f66f451Sopenharmony_ci s++; 650f66f451Sopenharmony_ci } 660f66f451Sopenharmony_ci 670f66f451Sopenharmony_ci if (TT.n && TT.entries >= TT.n) 680f66f451Sopenharmony_ci return *s ? s : (char *)1; 690f66f451Sopenharmony_ci 700f66f451Sopenharmony_ci if (!*s) break; 710f66f451Sopenharmony_ci save = s; 720f66f451Sopenharmony_ci 730f66f451Sopenharmony_ci // We ought to add sizeof(char *) to TT.bytes to be correct, but we don't 740f66f451Sopenharmony_ci // for bug compatibility with busybox 1.30.1 and findutils 4.7.0. 750f66f451Sopenharmony_ci 760f66f451Sopenharmony_ci for (;;) { 770f66f451Sopenharmony_ci if (++TT.bytes >= TT.s && TT.s) return save; 780f66f451Sopenharmony_ci if (!*s || isspace(*s)) break; 790f66f451Sopenharmony_ci s++; 800f66f451Sopenharmony_ci } 810f66f451Sopenharmony_ci if (TT.E && strstart(&save, TT.E)) return (char *)2; 820f66f451Sopenharmony_ci if (entry) entry[TT.entries] = save; 830f66f451Sopenharmony_ci ++TT.entries; 840f66f451Sopenharmony_ci } 850f66f451Sopenharmony_ci 860f66f451Sopenharmony_ci // -0 support 870f66f451Sopenharmony_ci } else { 880f66f451Sopenharmony_ci TT.bytes += sizeof(char *)+strlen(data)+1; 890f66f451Sopenharmony_ci if ((TT.s && TT.bytes >= TT.s) || (TT.n && TT.entries >= TT.n)) return data; 900f66f451Sopenharmony_ci if (entry) entry[TT.entries] = data; 910f66f451Sopenharmony_ci TT.entries++; 920f66f451Sopenharmony_ci } 930f66f451Sopenharmony_ci 940f66f451Sopenharmony_ci return 0; 950f66f451Sopenharmony_ci} 960f66f451Sopenharmony_ci 970f66f451Sopenharmony_civoid xargs_main(void) 980f66f451Sopenharmony_ci{ 990f66f451Sopenharmony_ci struct double_list *dlist = 0, *dtemp; 1000f66f451Sopenharmony_ci int entries, bytes, done = 0, ran_once = 0, status; 1010f66f451Sopenharmony_ci char *data = 0, **out; 1020f66f451Sopenharmony_ci pid_t pid; 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci // POSIX requires that we never hit the ARG_MAX limit, even if we try to 1050f66f451Sopenharmony_ci // with -s. POSIX also says we have to reserve 2048 bytes "to guarantee 1060f66f451Sopenharmony_ci // that the invoked utility has room to modify its environment variables 1070f66f451Sopenharmony_ci // and command line arguments and still be able to invoke another utility", 1080f66f451Sopenharmony_ci // though obviously that's not really something you can guarantee. 1090f66f451Sopenharmony_ci bytes = sysconf(_SC_ARG_MAX) - environ_bytes() - 2048; 1100f66f451Sopenharmony_ci if (!TT.s || TT.s > bytes) TT.s = bytes; 1110f66f451Sopenharmony_ci 1120f66f451Sopenharmony_ci TT.delim = '\n'*!FLAG(0); 1130f66f451Sopenharmony_ci 1140f66f451Sopenharmony_ci // If no optargs, call echo. 1150f66f451Sopenharmony_ci if (!toys.optc) { 1160f66f451Sopenharmony_ci free(toys.optargs); 1170f66f451Sopenharmony_ci *(toys.optargs = xzalloc(2*sizeof(char *)))="echo"; 1180f66f451Sopenharmony_ci toys.optc = 1; 1190f66f451Sopenharmony_ci } 1200f66f451Sopenharmony_ci 1210f66f451Sopenharmony_ci // count entries 1220f66f451Sopenharmony_ci for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++) 1230f66f451Sopenharmony_ci bytes += strlen(toys.optargs[entries]); 1240f66f451Sopenharmony_ci if (bytes >= TT.s) error_exit("argument too long"); 1250f66f451Sopenharmony_ci 1260f66f451Sopenharmony_ci // Loop through exec chunks. 1270f66f451Sopenharmony_ci while (data || !done) { 1280f66f451Sopenharmony_ci TT.entries = 0; 1290f66f451Sopenharmony_ci TT.bytes = bytes; 1300f66f451Sopenharmony_ci 1310f66f451Sopenharmony_ci // Loop reading input 1320f66f451Sopenharmony_ci for (;;) { 1330f66f451Sopenharmony_ci 1340f66f451Sopenharmony_ci // Read line 1350f66f451Sopenharmony_ci if (!data) { 1360f66f451Sopenharmony_ci ssize_t l = 0; 1370f66f451Sopenharmony_ci if (getdelim(&data, (size_t *)&l, TT.delim, stdin)<0) { 1380f66f451Sopenharmony_ci data = 0; 1390f66f451Sopenharmony_ci done++; 1400f66f451Sopenharmony_ci 1410f66f451Sopenharmony_ci break; 1420f66f451Sopenharmony_ci } 1430f66f451Sopenharmony_ci } 1440f66f451Sopenharmony_ci dlist_add(&dlist, data); 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci // Count data used 1470f66f451Sopenharmony_ci if (!(data = handle_entries(data, 0))) continue; 1480f66f451Sopenharmony_ci if (data == (char *)2) done++; 1490f66f451Sopenharmony_ci if ((unsigned long)data <= 2) data = 0; 1500f66f451Sopenharmony_ci else data = xstrdup(data); 1510f66f451Sopenharmony_ci 1520f66f451Sopenharmony_ci break; 1530f66f451Sopenharmony_ci } 1540f66f451Sopenharmony_ci 1550f66f451Sopenharmony_ci if (!TT.entries) { 1560f66f451Sopenharmony_ci if (data) error_exit("argument too long"); 1570f66f451Sopenharmony_ci else if (ran_once) return; 1580f66f451Sopenharmony_ci else if (FLAG(r)) continue; 1590f66f451Sopenharmony_ci } 1600f66f451Sopenharmony_ci 1610f66f451Sopenharmony_ci // Fill out command line to exec 1620f66f451Sopenharmony_ci out = xzalloc((entries+TT.entries+1)*sizeof(char *)); 1630f66f451Sopenharmony_ci memcpy(out, toys.optargs, entries*sizeof(char *)); 1640f66f451Sopenharmony_ci TT.entries = 0; 1650f66f451Sopenharmony_ci TT.bytes = bytes; 1660f66f451Sopenharmony_ci if (dlist) dlist->prev->next = 0; 1670f66f451Sopenharmony_ci for (dtemp = dlist; dtemp; dtemp = dtemp->next) 1680f66f451Sopenharmony_ci handle_entries(dtemp->data, out+entries); 1690f66f451Sopenharmony_ci 1700f66f451Sopenharmony_ci if (FLAG(p) || FLAG(t)) { 1710f66f451Sopenharmony_ci int i; 1720f66f451Sopenharmony_ci 1730f66f451Sopenharmony_ci for (i = 0; out[i]; ++i) fprintf(stderr, "%s ", out[i]); 1740f66f451Sopenharmony_ci if (FLAG(p)) { 1750f66f451Sopenharmony_ci fprintf(stderr, "?"); 1760f66f451Sopenharmony_ci if (!TT.tty) TT.tty = xfopen("/dev/tty", "re"); 1770f66f451Sopenharmony_ci if (!fyesno(TT.tty, 0)) goto skip; 1780f66f451Sopenharmony_ci } else fprintf(stderr, "\n"); 1790f66f451Sopenharmony_ci } 1800f66f451Sopenharmony_ci 1810f66f451Sopenharmony_ci if (!(pid = XVFORK())) { 1820f66f451Sopenharmony_ci close(0); 1830f66f451Sopenharmony_ci xopen_stdio(FLAG(o) ? "/dev/tty" : "/dev/null", O_RDONLY); 1840f66f451Sopenharmony_ci xexec(out); 1850f66f451Sopenharmony_ci } 1860f66f451Sopenharmony_ci waitpid(pid, &status, 0); 1870f66f451Sopenharmony_ci 1880f66f451Sopenharmony_ci // xargs is yet another weird collection of exit value special cases, 1890f66f451Sopenharmony_ci // different from all the others. 1900f66f451Sopenharmony_ci if (WIFEXITED(status)) { 1910f66f451Sopenharmony_ci if (WEXITSTATUS(status) == 126 || WEXITSTATUS(status) == 127) { 1920f66f451Sopenharmony_ci toys.exitval = WEXITSTATUS(status); 1930f66f451Sopenharmony_ci return; 1940f66f451Sopenharmony_ci } else if (WEXITSTATUS(status) >= 1 && WEXITSTATUS(status) <= 125) { 1950f66f451Sopenharmony_ci toys.exitval = 123; 1960f66f451Sopenharmony_ci } else if (WEXITSTATUS(status) == 255) { 1970f66f451Sopenharmony_ci error_msg("%s: exited with status 255; aborting", out[0]); 1980f66f451Sopenharmony_ci toys.exitval = 124; 1990f66f451Sopenharmony_ci return; 2000f66f451Sopenharmony_ci } 2010f66f451Sopenharmony_ci } else toys.exitval = 127; 2020f66f451Sopenharmony_ci 2030f66f451Sopenharmony_ci // Abritrary number of execs, can't just leak memory each time... 2040f66f451Sopenharmony_ciskip: 2050f66f451Sopenharmony_ci ran_once = 1; 2060f66f451Sopenharmony_ci while (dlist) { 2070f66f451Sopenharmony_ci struct double_list *dtemp = dlist->next; 2080f66f451Sopenharmony_ci 2090f66f451Sopenharmony_ci free(dlist->data); 2100f66f451Sopenharmony_ci free(dlist); 2110f66f451Sopenharmony_ci dlist = dtemp; 2120f66f451Sopenharmony_ci } 2130f66f451Sopenharmony_ci free(out); 2140f66f451Sopenharmony_ci } 2150f66f451Sopenharmony_ci if (TT.tty) fclose(TT.tty); 2160f66f451Sopenharmony_ci} 217