+ opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str, &eof_str);
+
+ /* -E ""? You may wonder why not just omit -E?
+ * This is used for portability:
+ * old xargs was using "_" as default for -E / -e */
+ if ((opt & OPT_EOF_STRING1) && eof_str[0] == '\0')
+ eof_str = NULL;
+
+ if (opt & OPT_ZEROTERM)
+ IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
+
+ argv += optind;
+ argc -= optind;
+ if (!argc) {
+ /* default behavior is to echo all the filenames */
+ *argv = (char*)"echo";
+ argc++;
+ }
+
+ orig_arg_max = ARG_MAX;
+ if (orig_arg_max == -1)
+ orig_arg_max = LONG_MAX;
+ orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */
+
+ if (opt & OPT_UPTO_SIZE) {
+ n_max_chars = xatoul_range(max_chars, 1, orig_arg_max);
+ for (i = 0; i < argc; i++) {
+ n_chars += strlen(*argv) + 1;
+ }
+ if (n_max_chars < n_chars) {
+ bb_error_msg_and_die("cannot fit single argument within argument list size limit");
+ }
+ n_max_chars -= n_chars;
+ } else {
+ /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
+ have it at 1 meg). Things will work fine with a large ARG_MAX but it
+ will probably hurt the system more than it needs to; an array of this
+ size is allocated. */
+ if (orig_arg_max > 20 * 1024)
+ orig_arg_max = 20 * 1024;
+ n_max_chars = orig_arg_max;
+ }
+ max_chars = xmalloc(n_max_chars);
+
+ if (opt & OPT_UPTO_NUMBER) {
+ n_max_arg = xatoul_range(max_args, 1, INT_MAX);
+ } else {
+ n_max_arg = n_max_chars;
+ }
+
+ while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL ||
+ !(opt & OPT_NO_EMPTY))
+ {
+ opt |= OPT_NO_EMPTY;
+ n = 0;
+ n_chars = 0;
+#if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
+ for (cur = list; cur;) {
+ n_chars += cur->length;
+ n++;
+ cur = cur->link;
+ if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
+ if (opt & OPT_TERMINATE)
+ bb_error_msg_and_die("argument list too long");
+ break;
+ }
+ }
+#else
+ for (cur = list; cur; cur = cur->link) {
+ n_chars += cur->length;
+ n++;
+ if (n_chars > n_max_chars || n == n_max_arg) {
+ break;
+ }
+ }
+#endif /* FEATURE_XARGS_SUPPORT_TERMOPT */
+
+ /* allocate pointers for execvp:
+ argc*arg, n*arg from stdin, NULL */
+ args = xzalloc((n + argc + 1) * sizeof(char *));
+
+ /* store the command to be executed
+ (taken from the command line) */
+ for (i = 0; i < argc; i++)
+ args[i] = argv[i];
+ /* (taken from stdin) */
+ for (cur = list; n; cur = cur->link) {
+ args[i++] = cur->xstr;
+ n--;
+ }
+
+ if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
+ for (i = 0; args[i]; i++) {
+ if (i)
+ fputc(' ', stderr);
+ fputs(args[i], stderr);
+ }
+ if (!(opt & OPT_INTERACTIVE))
+ fputc('\n', stderr);
+ }
+ if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
+ child_error = xargs_exec(args);
+ }
+
+ /* clean up */
+ for (i = argc; args[i]; i++) {
+ cur = list;
+ list = list->link;
+ free(cur);
+ }
+ free(args);
+ if (child_error > 0 && child_error != 123) {
+ break;
+ }
+ } /* while */
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(max_chars);
+ return child_error;