xargs.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /* xargs.c - Run command with arguments taken from stdin.
  2. *
  3. * Copyright 2011 Rob Landley <rob@landley.net>
  4. *
  5. * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html
  6. *
  7. * TODO: Rich's whitespace objection, env size isn't fixed anymore.
  8. * TODO: -I Insert mode
  9. * TODO: -L Max number of lines of input per command
  10. * TODO: -x Exit if can't fit everything in one command
  11. USE_XARGS(NEWTOY(xargs, "^E:P#<0=1optrn#<1(max-args)s#0[!0E]", TOYFLAG_USR|TOYFLAG_BIN))
  12. config XARGS
  13. bool "xargs"
  14. default y
  15. help
  16. usage: xargs [-0prt] [-snE STR] COMMAND...
  17. Run command line one or more times, appending arguments from stdin.
  18. If COMMAND exits with 255, don't launch another even if arguments remain.
  19. -0 Each argument is NULL terminated, no whitespace or quote processing
  20. -E Stop at line matching string
  21. -n Max number of arguments per command
  22. -o Open tty for COMMAND's stdin (default /dev/null)
  23. -p Prompt for y/n from tty before running each command
  24. -P Parallel processes (default 1)
  25. -r Don't run with empty input (otherwise always run command once)
  26. -s Size in bytes per command line
  27. -t Trace, print command line to stderr
  28. */
  29. #define FOR_xargs
  30. #include "toys.h"
  31. GLOBALS(
  32. long s, n, P;
  33. char *E;
  34. long entries, bytes, np;
  35. char delim;
  36. FILE *tty;
  37. )
  38. // If !entry count TT.bytes and TT.entries, stopping at max.
  39. // Otherwise, fill out entry[].
  40. // Returning NULL means need more data.
  41. // Returning char * means hit data limits, start of data left over
  42. // Returning 1 means hit data limits, but consumed all data
  43. // Returning 2 means hit -E STR
  44. static char *handle_entries(char *data, char **entry)
  45. {
  46. if (TT.delim) {
  47. char *save, *ss, *s;
  48. // Chop up whitespace delimited string into args
  49. for (s = data; *s; TT.entries++) {
  50. while (isspace(*s)) s++;
  51. if (TT.n && TT.entries >= TT.n) return *s ? s : (char *)1;
  52. if (!*s) break;
  53. save = ss = s;
  54. // Specifying -s can cause "argument too long" errors.
  55. if (!FLAG(s)) TT.bytes += sizeof(void *)+1;
  56. for (;;) {
  57. if (++TT.bytes >= TT.s) return save;
  58. if (!*s || isspace(*s)) break;
  59. s++;
  60. }
  61. if (TT.E && strstart(&ss, TT.E) && ss == s) return (char *)2;
  62. if (entry) {
  63. entry[TT.entries] = save;
  64. if (*s) *s++ = 0;
  65. }
  66. }
  67. // -0 support
  68. } else {
  69. long bytes = TT.bytes+sizeof(char *)+strlen(data)+1;
  70. if (bytes >= TT.s || (TT.n && TT.entries >= TT.n)) return data;
  71. TT.bytes = bytes;
  72. if (entry) entry[TT.entries] = data;
  73. TT.entries++;
  74. }
  75. return 0;
  76. }
  77. // Handle SIGUSR1 and SIGUSR2 for -P
  78. static void signal_P(int sig)
  79. {
  80. if (sig == SIGUSR2 && TT.P>1) TT.P--;
  81. else TT.P++;
  82. }
  83. void xargs_main(void)
  84. {
  85. struct double_list *dlist = 0, *dtemp;
  86. int entries, bytes, done = 0, status;
  87. char *data = 0, **out = 0;
  88. pid_t pid = 0;
  89. xsignal_flags(SIGUSR1, signal_P, SA_RESTART);
  90. xsignal_flags(SIGUSR2, signal_P, SA_RESTART);
  91. // POSIX requires that we never hit the ARG_MAX limit, even if we try to
  92. // with -s. POSIX also says we have to reserve 2048 bytes "to guarantee
  93. // that the invoked utility has room to modify its environment variables
  94. // and command line arguments and still be able to invoke another utility",
  95. // though obviously that's not really something you can guarantee.
  96. if (!FLAG(s)) TT.s = sysconf(_SC_ARG_MAX) - environ_bytes() - 4096;
  97. TT.delim = '\n'*!FLAG(0);
  98. // If no optargs, call echo.
  99. if (!toys.optc) {
  100. free(toys.optargs);
  101. *(toys.optargs = xzalloc(2*sizeof(char *)))="echo";
  102. toys.optc = 1;
  103. }
  104. // count entries
  105. for (entries = 0, bytes = -1; entries < toys.optc; entries++)
  106. bytes += strlen(toys.optargs[entries])+1+sizeof(char *)*!FLAG(s);
  107. if (bytes >= TT.s) error_exit("command too long");
  108. // Loop through exec chunks.
  109. while (data || !done) {
  110. TT.entries = 0;
  111. TT.bytes = bytes;
  112. // Loop reading input
  113. for (;;) {
  114. // Read line
  115. if (!data) {
  116. size_t l = 0;
  117. if (getdelim(&data, &l, TT.delim, stdin)<0) {
  118. data = 0;
  119. done++;
  120. break;
  121. }
  122. }
  123. dlist_add(&dlist, data);
  124. // Count data used
  125. if (!(data = handle_entries(data, 0))) continue;
  126. if (data == (char *)2) done++;
  127. if ((unsigned long)data <= 2) data = 0;
  128. else data = xstrdup(data);
  129. break;
  130. }
  131. if (!TT.entries) {
  132. if (data) error_exit("argument too long");
  133. if (pid || FLAG(r)) goto reap_children;
  134. }
  135. // Fill out command line to exec
  136. out = xzalloc((entries+TT.entries+1)*sizeof(char *));
  137. memcpy(out, toys.optargs, entries*sizeof(char *));
  138. TT.entries = 0;
  139. TT.bytes = bytes;
  140. if (dlist) dlist->prev->next = 0;
  141. for (dtemp = dlist; dtemp; dtemp = dtemp->next)
  142. handle_entries(dtemp->data, out+entries);
  143. if (FLAG(p) || FLAG(t)) {
  144. int i;
  145. for (i = 0; out[i]; ++i) fprintf(stderr, "%s ", out[i]);
  146. if (FLAG(p)) {
  147. fprintf(stderr, "?");
  148. if (!TT.tty) TT.tty = xfopen("/dev/tty", "re");
  149. if (!fyesno(TT.tty, 0)) goto reap_children;
  150. } else fprintf(stderr, "\n");
  151. }
  152. if (!(pid = XVFORK())) {
  153. close(0);
  154. xopen_stdio(FLAG(o) ? "/dev/tty" : "/dev/null", O_RDONLY);
  155. xexec(out);
  156. }
  157. TT.np++;
  158. reap_children:
  159. while (TT.np) {
  160. int xv = (TT.np == TT.P) || (!data && done);
  161. if (1>(xv = waitpid(-1, &status, WNOHANG*!xv))) break;
  162. TT.np--;
  163. xv = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+128;
  164. if (xv == 255) {
  165. error_msg("%s: exited with status 255; aborting", *out);
  166. toys.exitval = 124;
  167. break;
  168. } else if ((xv|1)==127) toys.exitval = xv;
  169. else if (xv>127) xv = 125;
  170. else if (xv) toys.exitval = 123;
  171. }
  172. // Abritrary number of execs, can't just leak memory each time...
  173. llist_traverse(dlist, llist_free_double);
  174. dlist = 0;
  175. free(out);
  176. out = 0;
  177. }
  178. while (TT.np && -1 != wait(&status)) TT.np--;
  179. if (TT.tty) fclose(TT.tty);
  180. }