3
0

xargs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini xargs implementation for busybox
  4. *
  5. * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru>
  6. *
  7. * Special thanks
  8. * - Mark Whitley and Glenn McGrath for stimulus to rewrite :)
  9. * - Mike Rendell <michael@cs.mun.ca>
  10. * and David MacKenzie <djm@gnu.ai.mit.edu>.
  11. *
  12. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  13. *
  14. * xargs is described in the Single Unix Specification v3 at
  15. * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html
  16. */
  17. //config:config XARGS
  18. //config: bool "xargs"
  19. //config: default y
  20. //config: help
  21. //config: xargs is used to execute a specified command for
  22. //config: every item from standard input.
  23. //config:
  24. //config:config FEATURE_XARGS_SUPPORT_CONFIRMATION
  25. //config: bool "Enable -p: prompt and confirmation"
  26. //config: default y
  27. //config: depends on XARGS
  28. //config: help
  29. //config: Support -p: prompt the user whether to run each command
  30. //config: line and read a line from the terminal.
  31. //config:
  32. //config:config FEATURE_XARGS_SUPPORT_QUOTES
  33. //config: bool "Enable single and double quotes and backslash"
  34. //config: default y
  35. //config: depends on XARGS
  36. //config: help
  37. //config: Support quoting in the input.
  38. //config:
  39. //config:config FEATURE_XARGS_SUPPORT_TERMOPT
  40. //config: bool "Enable -x: exit if -s or -n is exceeded"
  41. //config: default y
  42. //config: depends on XARGS
  43. //config: help
  44. //config: Support -x: exit if the command size (see the -s or -n option)
  45. //config: is exceeded.
  46. //config:
  47. //config:config FEATURE_XARGS_SUPPORT_ZERO_TERM
  48. //config: bool "Enable -0: NUL-terminated input"
  49. //config: default y
  50. //config: depends on XARGS
  51. //config: help
  52. //config: Support -0: input items are terminated by a NUL character
  53. //config: instead of whitespace, and the quotes and backslash
  54. //config: are not special.
  55. //applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs))
  56. //kbuild:lib-$(CONFIG_XARGS) += xargs.o
  57. #include "libbb.h"
  58. /* This is a NOEXEC applet. Be very careful! */
  59. //#define dbg_msg(...) bb_error_msg(__VA_ARGS__)
  60. #define dbg_msg(...) ((void)0)
  61. #ifdef TEST
  62. # ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
  63. # define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1
  64. # endif
  65. # ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
  66. # define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1
  67. # endif
  68. # ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
  69. # define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1
  70. # endif
  71. # ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
  72. # define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1
  73. # endif
  74. #endif
  75. struct globals {
  76. char **args;
  77. const char *eof_str;
  78. int idx;
  79. } FIX_ALIASING;
  80. #define G (*(struct globals*)&bb_common_bufsiz1)
  81. #define INIT_G() do { \
  82. G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \
  83. } while (0)
  84. /*
  85. * This function has special algorithm.
  86. * Don't use fork and include to main!
  87. */
  88. static int xargs_exec(void)
  89. {
  90. int status;
  91. status = spawn_and_wait(G.args);
  92. if (status < 0) {
  93. bb_simple_perror_msg(G.args[0]);
  94. return errno == ENOENT ? 127 : 126;
  95. }
  96. if (status == 255) {
  97. bb_error_msg("%s: exited with status 255; aborting", G.args[0]);
  98. return 124;
  99. }
  100. if (status >= 0x180) {
  101. bb_error_msg("%s: terminated by signal %d",
  102. G.args[0], status - 0x180);
  103. return 125;
  104. }
  105. if (status)
  106. return 123;
  107. return 0;
  108. }
  109. /* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space.
  110. * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
  111. */
  112. #define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); })
  113. static void store_param(char *s)
  114. {
  115. /* Grow by 256 elements at once */
  116. if (!(G.idx & 0xff)) { /* G.idx == N*256 */
  117. /* Enlarge, make G.args[(N+1)*256 - 1] last valid idx */
  118. G.args = xrealloc(G.args, sizeof(G.args[0]) * (G.idx + 0x100));
  119. }
  120. G.args[G.idx++] = s;
  121. }
  122. /* process[0]_stdin:
  123. * Read characters into buf[n_max_chars+1], and when parameter delimiter
  124. * is seen, store the address of a new parameter to args[].
  125. * If reading discovers that last chars do not form the complete
  126. * parameter, the pointer to the first such "tail character" is returned.
  127. * (buf has extra byte at the end to accomodate terminating NUL
  128. * of "tail characters" string).
  129. * Otherwise, the returned pointer points to NUL byte.
  130. * On entry, buf[] may contain some "seed chars" which are to become
  131. * the beginning of the first parameter.
  132. */
  133. #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
  134. static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
  135. {
  136. #define NORM 0
  137. #define QUOTE 1
  138. #define BACKSLASH 2
  139. #define SPACE 4
  140. char q = '\0'; /* quote char */
  141. char state = NORM;
  142. char *s = buf; /* start of the word */
  143. char *p = s + strlen(buf); /* end of the word */
  144. buf += n_max_chars; /* past buffer's end */
  145. /* "goto ret" is used instead of "break" to make control flow
  146. * more obvious: */
  147. while (1) {
  148. int c = getchar();
  149. if (c == EOF) {
  150. if (p != s)
  151. goto close_word;
  152. goto ret;
  153. }
  154. if (state == BACKSLASH) {
  155. state = NORM;
  156. goto set;
  157. }
  158. if (state == QUOTE) {
  159. if (c != q)
  160. goto set;
  161. q = '\0';
  162. state = NORM;
  163. } else { /* if (state == NORM) */
  164. if (ISSPACE(c)) {
  165. if (p != s) {
  166. close_word:
  167. state = SPACE;
  168. c = '\0';
  169. goto set;
  170. }
  171. } else {
  172. if (c == '\\') {
  173. state = BACKSLASH;
  174. } else if (c == '\'' || c == '"') {
  175. q = c;
  176. state = QUOTE;
  177. } else {
  178. set:
  179. *p++ = c;
  180. }
  181. }
  182. }
  183. if (state == SPACE) { /* word's delimiter or EOF detected */
  184. if (q) {
  185. bb_error_msg_and_die("unmatched %s quote",
  186. q == '\'' ? "single" : "double");
  187. }
  188. /* A full word is loaded */
  189. if (G.eof_str) {
  190. if (strcmp(s, G.eof_str) == 0) {
  191. while (getchar() != EOF)
  192. continue;
  193. p = s;
  194. goto ret;
  195. }
  196. }
  197. store_param(s);
  198. dbg_msg("args[]:'%s'", s);
  199. s = p;
  200. n_max_arg--;
  201. if (n_max_arg == 0) {
  202. goto ret;
  203. }
  204. state = NORM;
  205. }
  206. if (p == buf) {
  207. goto ret;
  208. }
  209. }
  210. ret:
  211. *p = '\0';
  212. /* store_param(NULL) - caller will do it */
  213. dbg_msg("return:'%s'", s);
  214. return s;
  215. }
  216. #else
  217. /* The variant does not support single quotes, double quotes or backslash */
  218. static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
  219. {
  220. char *s = buf; /* start of the word */
  221. char *p = s + strlen(buf); /* end of the word */
  222. buf += n_max_chars; /* past buffer's end */
  223. while (1) {
  224. int c = getchar();
  225. if (c == EOF) {
  226. if (p == s)
  227. goto ret;
  228. }
  229. if (c == EOF || ISSPACE(c)) {
  230. if (p == s)
  231. continue;
  232. c = EOF;
  233. }
  234. *p++ = (c == EOF ? '\0' : c);
  235. if (c == EOF) { /* word's delimiter or EOF detected */
  236. /* A full word is loaded */
  237. if (G.eof_str) {
  238. if (strcmp(s, G.eof_str) == 0) {
  239. while (getchar() != EOF)
  240. continue;
  241. p = s;
  242. goto ret;
  243. }
  244. }
  245. store_param(s);
  246. dbg_msg("args[]:'%s'", s);
  247. s = p;
  248. n_max_arg--;
  249. if (n_max_arg == 0) {
  250. goto ret;
  251. }
  252. }
  253. if (p == buf) {
  254. goto ret;
  255. }
  256. }
  257. ret:
  258. *p = '\0';
  259. /* store_param(NULL) - caller will do it */
  260. dbg_msg("return:'%s'", s);
  261. return s;
  262. }
  263. #endif /* FEATURE_XARGS_SUPPORT_QUOTES */
  264. #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
  265. static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf)
  266. {
  267. char *s = buf; /* start of the word */
  268. char *p = s + strlen(buf); /* end of the word */
  269. buf += n_max_chars; /* past buffer's end */
  270. while (1) {
  271. int c = getchar();
  272. if (c == EOF) {
  273. if (p == s)
  274. goto ret;
  275. c = '\0';
  276. }
  277. *p++ = c;
  278. if (c == '\0') { /* word's delimiter or EOF detected */
  279. /* A full word is loaded */
  280. store_param(s);
  281. dbg_msg("args[]:'%s'", s);
  282. s = p;
  283. n_max_arg--;
  284. if (n_max_arg == 0) {
  285. goto ret;
  286. }
  287. }
  288. if (p == buf) {
  289. goto ret;
  290. }
  291. }
  292. ret:
  293. *p = '\0';
  294. /* store_param(NULL) - caller will do it */
  295. dbg_msg("return:'%s'", s);
  296. return s;
  297. }
  298. #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
  299. #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
  300. /* Prompt the user for a response, and
  301. if the user responds affirmatively, return true;
  302. otherwise, return false. Uses "/dev/tty", not stdin. */
  303. static int xargs_ask_confirmation(void)
  304. {
  305. FILE *tty_stream;
  306. int c, savec;
  307. tty_stream = xfopen_for_read(CURRENT_TTY);
  308. fputs(" ?...", stderr);
  309. fflush_all();
  310. c = savec = getc(tty_stream);
  311. while (c != EOF && c != '\n')
  312. c = getc(tty_stream);
  313. fclose(tty_stream);
  314. return (savec == 'y' || savec == 'Y');
  315. }
  316. #else
  317. # define xargs_ask_confirmation() 1
  318. #endif
  319. //usage:#define xargs_trivial_usage
  320. //usage: "[OPTIONS] [PROG ARGS]"
  321. //usage:#define xargs_full_usage "\n\n"
  322. //usage: "Run PROG on every item given by stdin\n"
  323. //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(
  324. //usage: "\n -p Ask user whether to run each command"
  325. //usage: )
  326. //usage: "\n -r Don't run command if input is empty"
  327. //usage: IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(
  328. //usage: "\n -0 Input is separated by NUL characters"
  329. //usage: )
  330. //usage: "\n -t Print the command on stderr before execution"
  331. //usage: "\n -e[STR] STR stops input processing"
  332. //usage: "\n -n N Pass no more than N args to PROG"
  333. //usage: "\n -s N Pass command line of no more than N bytes"
  334. //usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT(
  335. //usage: "\n -x Exit if size is exceeded"
  336. //usage: )
  337. //usage:#define xargs_example_usage
  338. //usage: "$ ls | xargs gzip\n"
  339. //usage: "$ find . -name '*.c' -print | xargs rm\n"
  340. /* Correct regardless of combination of CONFIG_xxx */
  341. enum {
  342. OPTBIT_VERBOSE = 0,
  343. OPTBIT_NO_EMPTY,
  344. OPTBIT_UPTO_NUMBER,
  345. OPTBIT_UPTO_SIZE,
  346. OPTBIT_EOF_STRING,
  347. OPTBIT_EOF_STRING1,
  348. IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
  349. IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
  350. IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
  351. OPT_VERBOSE = 1 << OPTBIT_VERBOSE ,
  352. OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY ,
  353. OPT_UPTO_NUMBER = 1 << OPTBIT_UPTO_NUMBER,
  354. OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE ,
  355. OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */
  356. OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */
  357. OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
  358. OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0,
  359. OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0,
  360. };
  361. #define OPTION_STR "+trn:s:e::E:" \
  362. IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
  363. IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
  364. IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0")
  365. int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  366. int xargs_main(int argc, char **argv)
  367. {
  368. int i;
  369. int child_error = 0;
  370. char *max_args;
  371. char *max_chars;
  372. char *buf;
  373. unsigned opt;
  374. int n_max_chars;
  375. int n_max_arg;
  376. #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
  377. char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
  378. #else
  379. #define read_args process_stdin
  380. #endif
  381. INIT_G();
  382. #if ENABLE_DESKTOP && ENABLE_LONG_OPTS
  383. /* For example, Fedora's build system uses --no-run-if-empty */
  384. applet_long_options =
  385. "no-run-if-empty\0" No_argument "r"
  386. ;
  387. #endif
  388. opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str);
  389. /* -E ""? You may wonder why not just omit -E?
  390. * This is used for portability:
  391. * old xargs was using "_" as default for -E / -e */
  392. if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0')
  393. G.eof_str = NULL;
  394. if (opt & OPT_ZEROTERM)
  395. IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
  396. argv += optind;
  397. argc -= optind;
  398. if (!argv[0]) {
  399. /* default behavior is to echo all the filenames */
  400. *--argv = (char*)"echo";
  401. argc++;
  402. }
  403. /* -s NUM default. fileutils-4.4.2 uses 128k, but I heasitate
  404. * to use such a big value - first need to change code to use
  405. * growable buffer instead of fixed one.
  406. */
  407. n_max_chars = 32 * 1024;
  408. /* Make smaller if system does not allow our default value.
  409. * The Open Group Base Specifications Issue 6:
  410. * "The xargs utility shall limit the command line length such that
  411. * when the command line is invoked, the combined argument
  412. * and environment lists (see the exec family of functions
  413. * in the System Interfaces volume of IEEE Std 1003.1-2001)
  414. * shall not exceed {ARG_MAX}-2048 bytes".
  415. */
  416. {
  417. long arg_max = 0;
  418. #if defined _SC_ARG_MAX
  419. arg_max = sysconf(_SC_ARG_MAX) - 2048;
  420. #elif defined ARG_MAX
  421. arg_max = ARG_MAX - 2048;
  422. #endif
  423. if (arg_max > 0 && n_max_chars > arg_max)
  424. n_max_chars = arg_max;
  425. }
  426. if (opt & OPT_UPTO_SIZE) {
  427. n_max_chars = xatou_range(max_chars, 1, INT_MAX);
  428. }
  429. /* Account for prepended fixed arguments */
  430. {
  431. size_t n_chars = 0;
  432. for (i = 0; argv[i]; i++) {
  433. n_chars += strlen(argv[i]) + 1;
  434. }
  435. n_max_chars -= n_chars;
  436. }
  437. /* Sanity check */
  438. if (n_max_chars <= 0) {
  439. bb_error_msg_and_die("can't fit single argument within argument list size limit");
  440. }
  441. buf = xzalloc(n_max_chars + 1);
  442. n_max_arg = n_max_chars;
  443. if (opt & OPT_UPTO_NUMBER) {
  444. n_max_arg = xatou_range(max_args, 1, INT_MAX);
  445. /* Not necessary, we use growable args[]: */
  446. /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */
  447. }
  448. /* Allocate pointers for execvp */
  449. /* We can statically allocate (argc + n_max_arg + 1) elements
  450. * and do not bother with resizing args[], but on 64-bit machines
  451. * this results in args[] vector which is ~8 times bigger
  452. * than n_max_chars! That is, with n_max_chars == 20k,
  453. * args[] will take 160k (!), which will most likely be
  454. * almost entirely unused.
  455. */
  456. /* See store_param() for matching 256-step growth logic */
  457. G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
  458. /* Store the command to be executed, part 1 */
  459. for (i = 0; argv[i]; i++)
  460. G.args[i] = argv[i];
  461. while (1) {
  462. char *rem;
  463. G.idx = argc;
  464. rem = read_args(n_max_chars, n_max_arg, buf);
  465. store_param(NULL);
  466. if (!G.args[argc]) {
  467. if (*rem != '\0')
  468. bb_error_msg_and_die("argument line too long");
  469. if (opt & OPT_NO_EMPTY)
  470. break;
  471. }
  472. opt |= OPT_NO_EMPTY;
  473. if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
  474. const char *fmt = " %s" + 1;
  475. char **args = G.args;
  476. for (i = 0; args[i]; i++) {
  477. fprintf(stderr, fmt, args[i]);
  478. fmt = " %s";
  479. }
  480. if (!(opt & OPT_INTERACTIVE))
  481. bb_putchar_stderr('\n');
  482. }
  483. if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
  484. child_error = xargs_exec();
  485. }
  486. if (child_error > 0 && child_error != 123) {
  487. break;
  488. }
  489. overlapping_strcpy(buf, rem);
  490. } /* while */
  491. if (ENABLE_FEATURE_CLEAN_UP) {
  492. free(G.args);
  493. free(buf);
  494. }
  495. return child_error;
  496. }
  497. #ifdef TEST
  498. const char *applet_name = "debug stuff usage";
  499. void bb_show_usage(void)
  500. {
  501. fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
  502. applet_name);
  503. exit(EXIT_FAILURE);
  504. }
  505. int main(int argc, char **argv)
  506. {
  507. return xargs_main(argc, argv);
  508. }
  509. #endif /* TEST */