+int xargs_main(int argc, char **argv)
+{
+ char **args;
+ int i, a, n;
+ xlist_t *list = NULL;
+ xlist_t *cur;
+ int child_error = 0;
+ char *max_args, *max_chars;
+ int n_max_arg;
+ size_t n_chars = 0;
+ long orig_arg_max;
+ const char *eof_str = "_";
+ unsigned long opt;
+ size_t n_max_chars;
+
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
+ xlist_t *(*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin;
+#endif
+
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
+ bb_opt_complementally = "pt";
+#endif
+
+ opt = bb_getopt_ulflags(argc, argv, "+trn:s:e::"
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
+ "p"
+#endif
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
+ "x"
+#endif
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
+ "0"
+#endif
+ ,&max_args, &max_chars, &eof_str);
+
+ a = argc - optind;
+ argv += optind;
+ if (a == 0) {
+ /* default behavior is to echo all the filenames */
+ *argv = "echo";
+ a++;
+ }
+
+ 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 = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max);
+ for (i = 0; i < a; i++) {
+ n_chars += strlen(*argv) + 1;
+ }
+ if (n_max_chars < n_chars) {
+ bb_error_msg_and_die("can not 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 = bb_xgetularg10_bnd(max_args, 1, INT_MAX);
+ } else {
+ n_max_arg = n_max_chars;
+ }
+
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
+ if (opt & OPT_ZEROTERM)
+ read_args = process0_stdin;
+#endif
+
+ while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL ||
+ (opt & OPT_NO_EMPTY) == 0)
+ {
+ opt |= OPT_NO_EMPTY;
+ n = 0;
+ n_chars = 0;
+#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
+ for (cur = list; cur;) {
+ n_chars += cur->lenght;
+ 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->lenght;
+ n++;
+ if (n_chars > n_max_chars || n == n_max_arg) {
+ break;
+ }
+ }
+#endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */
+
+ /* allocating pointers for execvp:
+ a*arg, n*arg from stdin, NULL */
+ args = xcalloc(n + a + 1, sizeof(char *));
+
+ /* Store the command to be executed
+ (taken from the command line) */
+ for (i = 0; i < a; i++)
+ args[i] = argv[i];
+ /* (taken from stdin) */
+ for (cur = list; n; cur = cur->link) {
+ args[i++] = cur->data;
+ 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) == 0)
+ fputc('\n', stderr);
+ }
+ if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) {
+ child_error = xargs_exec(args);
+ }
+
+ /* clean up */
+ for (i = a; args[i]; i++) {
+ cur = list;
+ list = list->link;
+ free(cur);
+ }
+ free(args);
+ if (child_error > 0 && child_error != 123) {
+ break;
+ }
+ }
+#ifdef CONFIG_FEATURE_CLEAN_UP
+ free(max_chars);
+#endif
+ return child_error;
+}
+
+
+#ifdef TEST
+
+const char *bb_applet_name = "debug stuff usage";
+
+void bb_show_usage(void)
+{
+ fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
+ bb_applet_name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ return xargs_main(argc, argv);
+}
+#endif /* TEST */