diff options
Diffstat (limited to 'findutils/xargs.c')
-rw-r--r-- | findutils/xargs.c | 268 |
1 files changed, 263 insertions, 5 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c index 890c37534..f0abf1a23 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -74,6 +74,11 @@ | |||
74 | 74 | ||
75 | //kbuild:lib-$(CONFIG_XARGS) += xargs.o | 75 | //kbuild:lib-$(CONFIG_XARGS) += xargs.o |
76 | 76 | ||
77 | #if ENABLE_PLATFORM_MINGW32 | ||
78 | #include <conio.h> | ||
79 | #include "busybox.h" | ||
80 | #include "NUM_APPLETS.h" | ||
81 | #endif | ||
77 | #include "libbb.h" | 82 | #include "libbb.h" |
78 | #include "common_bufsiz.h" | 83 | #include "common_bufsiz.h" |
79 | 84 | ||
@@ -111,11 +116,19 @@ struct globals { | |||
111 | #endif | 116 | #endif |
112 | const char *eof_str; | 117 | const char *eof_str; |
113 | int idx; | 118 | int idx; |
119 | #if !ENABLE_PLATFORM_MINGW32 | ||
114 | int fd_tty; | 120 | int fd_tty; |
115 | int fd_stdin; | 121 | int fd_stdin; |
122 | #endif | ||
116 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 123 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
117 | int running_procs; | 124 | int running_procs; |
118 | int max_procs; | 125 | int max_procs; |
126 | # if ENABLE_PLATFORM_MINGW32 | ||
127 | HANDLE *procs; | ||
128 | # endif | ||
129 | #endif | ||
130 | #if ENABLE_PLATFORM_MINGW32 | ||
131 | pid_t pid; | ||
119 | #endif | 132 | #endif |
120 | smalluint xargs_exitcode; | 133 | smalluint xargs_exitcode; |
121 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES | 134 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES |
@@ -137,6 +150,7 @@ struct globals { | |||
137 | G.idx = 0; \ | 150 | G.idx = 0; \ |
138 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ | 151 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ |
139 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ | 152 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ |
153 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(IF_PLATFORM_MINGW32(G.procs = NULL;)) \ | ||
140 | G.xargs_exitcode = 0; \ | 154 | G.xargs_exitcode = 0; \ |
141 | IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \ | 155 | IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \ |
142 | IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \ | 156 | IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \ |
@@ -150,7 +164,7 @@ enum { | |||
150 | OPTBIT_UPTO_SIZE, | 164 | OPTBIT_UPTO_SIZE, |
151 | OPTBIT_EOF_STRING, | 165 | OPTBIT_EOF_STRING, |
152 | OPTBIT_EOF_STRING1, | 166 | OPTBIT_EOF_STRING1, |
153 | OPTBIT_STDIN_TTY, | 167 | IF_NOT_PLATFORM_MINGW32( OPTBIT_STDIN_TTY ,) |
154 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) | 168 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) |
155 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) | 169 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) |
156 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) | 170 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) |
@@ -163,14 +177,15 @@ enum { | |||
163 | OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE , | 177 | OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE , |
164 | OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */ | 178 | OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */ |
165 | OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */ | 179 | OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */ |
166 | OPT_STDIN_TTY = 1 << OPTBIT_STDIN_TTY, | 180 | OPT_STDIN_TTY = IF_NOT_PLATFORM_MINGW32( (1 << OPTBIT_STDIN_TTY )) + 0, |
167 | OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, | 181 | OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, |
168 | OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, | 182 | OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, |
169 | OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, | 183 | OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, |
170 | OPT_REPLSTR = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR )) + 0, | 184 | OPT_REPLSTR = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR )) + 0, |
171 | OPT_REPLSTR1 = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR1 )) + 0, | 185 | OPT_REPLSTR1 = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR1 )) + 0, |
172 | }; | 186 | }; |
173 | #define OPTION_STR "+trn:s:e::E:o" \ | 187 | #define OPTION_STR "+trn:s:e::E:" \ |
188 | IF_NOT_PLATFORM_MINGW32( "o") \ | ||
174 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ | 189 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ |
175 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ | 190 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ |
176 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") \ | 191 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") \ |
@@ -179,6 +194,83 @@ enum { | |||
179 | IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( "a:") | 194 | IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( "a:") |
180 | 195 | ||
181 | 196 | ||
197 | #if ENABLE_PLATFORM_MINGW32 | ||
198 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | ||
199 | { | ||
200 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | ||
201 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
202 | if (G.max_procs == 1) | ||
203 | # endif | ||
204 | { | ||
205 | if (G.pid > 0) | ||
206 | kill(-G.pid, SIGTERM); | ||
207 | } | ||
208 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
209 | else { | ||
210 | int i; | ||
211 | |||
212 | for (i = 0; i < G.running_procs; ++i) { | ||
213 | pid_t pid = GetProcessId(G.procs[i]); | ||
214 | if (pid > 0) | ||
215 | kill(-pid, SIGTERM); | ||
216 | } | ||
217 | } | ||
218 | # endif | ||
219 | exit(SIGINT << 24); | ||
220 | return TRUE; | ||
221 | } | ||
222 | return FALSE; | ||
223 | } | ||
224 | #endif | ||
225 | |||
226 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL && ENABLE_PLATFORM_MINGW32 | ||
227 | static int wait_for_slot(int *idx) | ||
228 | { | ||
229 | int i; | ||
230 | |||
231 | /* if less than max_procs running, set status to 0, return next free slot */ | ||
232 | if (G.running_procs < G.max_procs) { | ||
233 | *idx = G.running_procs++; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | check_exit_codes: | ||
238 | for (i = G.running_procs - 1; i >= 0; i--) { | ||
239 | DWORD status = 0; | ||
240 | if (!GetExitCodeProcess(G.procs[i], &status) || | ||
241 | status != STILL_ACTIVE) { | ||
242 | CloseHandle(G.procs[i]); | ||
243 | if (i + 1 < G.running_procs) | ||
244 | G.procs[i] = G.procs[G.running_procs - 1]; | ||
245 | *idx = G.running_procs - 1; | ||
246 | if (!G.max_procs) | ||
247 | G.running_procs--; | ||
248 | return status; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | if (G.running_procs < MAXIMUM_WAIT_OBJECTS) | ||
253 | WaitForMultipleObjects((DWORD)G.running_procs, G.procs, FALSE, | ||
254 | INFINITE); | ||
255 | else { | ||
256 | /* Fall back to polling */ | ||
257 | for (;;) { | ||
258 | DWORD nr = i + MAXIMUM_WAIT_OBJECTS > G.running_procs ? | ||
259 | MAXIMUM_WAIT_OBJECTS : (DWORD)(G.running_procs - i); | ||
260 | DWORD ret = WaitForMultipleObjects(nr, G.procs + i, FALSE, 100); | ||
261 | |||
262 | if (ret != WAIT_TIMEOUT) | ||
263 | break; | ||
264 | i += MAXIMUM_WAIT_OBJECTS; | ||
265 | if (i > G.running_procs) | ||
266 | i = 0; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | goto check_exit_codes; | ||
271 | } | ||
272 | #endif /* SUPPORT_PARALLEL && PLATFORM_MINGW32 */ | ||
273 | |||
182 | /* | 274 | /* |
183 | * Returns 0 if xargs should continue (but may set G.xargs_exitcode to 123). | 275 | * Returns 0 if xargs should continue (but may set G.xargs_exitcode to 123). |
184 | * Else sets G.xargs_exitcode to error code and returns nonzero. | 276 | * Else sets G.xargs_exitcode to error code and returns nonzero. |
@@ -189,6 +281,7 @@ static int xargs_exec(void) | |||
189 | { | 281 | { |
190 | int status; | 282 | int status; |
191 | 283 | ||
284 | #if !ENABLE_PLATFORM_MINGW32 | ||
192 | if (option_mask32 & OPT_STDIN_TTY) | 285 | if (option_mask32 & OPT_STDIN_TTY) |
193 | xdup2(G.fd_tty, STDIN_FILENO); | 286 | xdup2(G.fd_tty, STDIN_FILENO); |
194 | 287 | ||
@@ -240,6 +333,45 @@ static int xargs_exec(void) | |||
240 | } | 333 | } |
241 | } | 334 | } |
242 | #endif | 335 | #endif |
336 | #endif | ||
337 | |||
338 | #if ENABLE_PLATFORM_MINGW32 | ||
339 | /* Any change to the logic for NOFORK applets must be duplicated | ||
340 | * in xargs_main() below. */ | ||
341 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
342 | if (G.max_procs == 1) { | ||
343 | # endif | ||
344 | # if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1) | ||
345 | int applet = find_applet_by_name(G.args[0]); | ||
346 | if (applet >= 0 && APPLET_IS_NOFORK(applet)) { | ||
347 | status = run_nofork_applet(applet, G.args); | ||
348 | } else | ||
349 | # endif | ||
350 | { | ||
351 | G.pid = spawn(G.args); | ||
352 | status = G.pid < 0 ? -1 : wait4pid(G.pid); | ||
353 | } | ||
354 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
355 | } | ||
356 | else { | ||
357 | int idx; | ||
358 | status = !G.running_procs && !G.max_procs ? 0 : wait_for_slot(&idx); | ||
359 | if (G.max_procs) { | ||
360 | HANDLE p = (HANDLE)mingw_spawn_proc((const char **)G.args); | ||
361 | if (p < 0) | ||
362 | status = -1; | ||
363 | else | ||
364 | G.procs[idx] = p; | ||
365 | } else { | ||
366 | while (G.running_procs) { | ||
367 | int status2 = wait_for_slot(&idx); | ||
368 | if (status2 && !status) | ||
369 | status = status2; | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | # endif | ||
374 | #endif | ||
243 | /* Manpage: | 375 | /* Manpage: |
244 | * """xargs exits with the following status: | 376 | * """xargs exits with the following status: |
245 | * 0 if it succeeds | 377 | * 0 if it succeeds |
@@ -278,8 +410,10 @@ static int xargs_exec(void) | |||
278 | ret: | 410 | ret: |
279 | if (status != 0) | 411 | if (status != 0) |
280 | G.xargs_exitcode = status; | 412 | G.xargs_exitcode = status; |
413 | #if !ENABLE_PLATFORM_MINGW32 | ||
281 | if (option_mask32 & OPT_STDIN_TTY) | 414 | if (option_mask32 & OPT_STDIN_TTY) |
282 | xdup2(G.fd_stdin, STDIN_FILENO); | 415 | xdup2(G.fd_stdin, STDIN_FILENO); |
416 | #endif | ||
283 | return status; | 417 | return status; |
284 | } | 418 | } |
285 | 419 | ||
@@ -559,6 +693,7 @@ static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg | |||
559 | */ | 693 | */ |
560 | static int xargs_ask_confirmation(void) | 694 | static int xargs_ask_confirmation(void) |
561 | { | 695 | { |
696 | #if !ENABLE_PLATFORM_MINGW32 | ||
562 | FILE *tty_stream; | 697 | FILE *tty_stream; |
563 | int r; | 698 | int r; |
564 | 699 | ||
@@ -568,6 +703,18 @@ static int xargs_ask_confirmation(void) | |||
568 | r = bb_ask_y_confirmation_FILE(tty_stream); | 703 | r = bb_ask_y_confirmation_FILE(tty_stream); |
569 | 704 | ||
570 | fclose(tty_stream); | 705 | fclose(tty_stream); |
706 | #else | ||
707 | int r, c, savec; | ||
708 | |||
709 | fputs(" ?...", stderr); | ||
710 | fflush_all(); | ||
711 | c = savec = getche(); | ||
712 | while (c != EOF && c != '\r') | ||
713 | c = getche(); | ||
714 | fputs("\n", stderr); | ||
715 | fflush_all(); | ||
716 | r = (savec == 'y' || savec == 'Y'); | ||
717 | #endif | ||
571 | 718 | ||
572 | return r; | 719 | return r; |
573 | } | 720 | } |
@@ -575,6 +722,20 @@ static int xargs_ask_confirmation(void) | |||
575 | # define xargs_ask_confirmation() 1 | 722 | # define xargs_ask_confirmation() 1 |
576 | #endif | 723 | #endif |
577 | 724 | ||
725 | #if ENABLE_PLATFORM_MINGW32 | ||
726 | // Maximum command length (less a few bytes) | ||
727 | # define WIN32_MAX_CHARS (32750) | ||
728 | |||
729 | static size_t quote_len(const char *arg) | ||
730 | { | ||
731 | char *s = quote_arg(arg); | ||
732 | size_t len = strlen(s); | ||
733 | |||
734 | free(s); | ||
735 | return len; | ||
736 | } | ||
737 | #endif | ||
738 | |||
578 | //usage:#define xargs_trivial_usage | 739 | //usage:#define xargs_trivial_usage |
579 | //usage: "[OPTIONS] [PROG ARGS]" | 740 | //usage: "[OPTIONS] [PROG ARGS]" |
580 | //usage:#define xargs_full_usage "\n\n" | 741 | //usage:#define xargs_full_usage "\n\n" |
@@ -585,7 +746,9 @@ static int xargs_ask_confirmation(void) | |||
585 | //usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( | 746 | //usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( |
586 | //usage: "\n -a FILE Read from FILE instead of stdin" | 747 | //usage: "\n -a FILE Read from FILE instead of stdin" |
587 | //usage: ) | 748 | //usage: ) |
749 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
588 | //usage: "\n -o Reopen stdin as /dev/tty" | 750 | //usage: "\n -o Reopen stdin as /dev/tty" |
751 | //usage: ) | ||
589 | //usage: "\n -r Don't run command if input is empty" | 752 | //usage: "\n -r Don't run command if input is empty" |
590 | //usage: "\n -t Print the command on stderr before execution" | 753 | //usage: "\n -t Print the command on stderr before execution" |
591 | //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( | 754 | //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( |
@@ -618,6 +781,11 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
618 | unsigned opt; | 781 | unsigned opt; |
619 | int n_max_chars; | 782 | int n_max_chars; |
620 | int n_max_arg; | 783 | int n_max_arg; |
784 | #if ENABLE_PLATFORM_MINGW32 | ||
785 | int delta = 0; | ||
786 | int quote = TRUE; | ||
787 | char *old_buf = NULL; | ||
788 | #endif | ||
621 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \ | 789 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \ |
622 | || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR | 790 | || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR |
623 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; | 791 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; |
@@ -628,6 +796,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
628 | 796 | ||
629 | INIT_G(); | 797 | INIT_G(); |
630 | 798 | ||
799 | #if ENABLE_PLATFORM_MINGW32 | ||
800 | SetConsoleCtrlHandler(ctrl_handler, TRUE); | ||
801 | #endif | ||
631 | opt = getopt32long(argv, OPTION_STR, | 802 | opt = getopt32long(argv, OPTION_STR, |
632 | "no-run-if-empty\0" No_argument "r", | 803 | "no-run-if-empty\0" No_argument "r", |
633 | &max_args, &max_chars, &G.eof_str, &G.eof_str | 804 | &max_args, &max_chars, &G.eof_str, &G.eof_str |
@@ -638,7 +809,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
638 | 809 | ||
639 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 810 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
640 | if (G.max_procs <= 0) /* -P0 means "run lots of them" */ | 811 | if (G.max_procs <= 0) /* -P0 means "run lots of them" */ |
812 | #if !ENABLE_PLATFORM_MINGW32 | ||
641 | G.max_procs = 100; /* let's not go crazy high */ | 813 | G.max_procs = 100; /* let's not go crazy high */ |
814 | #else | ||
815 | G.max_procs = MAXIMUM_WAIT_OBJECTS; | ||
816 | G.procs = xmalloc(sizeof(G.procs[0]) * G.max_procs); | ||
817 | #endif | ||
642 | #endif | 818 | #endif |
643 | 819 | ||
644 | #if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE | 820 | #if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE |
@@ -665,6 +841,24 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
665 | //argc++; | 841 | //argc++; |
666 | } | 842 | } |
667 | 843 | ||
844 | #if ENABLE_PLATFORM_MINGW32 | ||
845 | /* On Windows the command line may be expanded by the need to quote | ||
846 | * arguments, but not if the command is a NOFORK applet. If the rules | ||
847 | * to detect this situation change xargs_exec() above will also need | ||
848 | * to be updated. */ | ||
849 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
850 | if (G.max_procs == 1) | ||
851 | # endif | ||
852 | { | ||
853 | # if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1) | ||
854 | int applet = find_applet_by_name(argv[0]); | ||
855 | if (applet >= 0 && APPLET_IS_NOFORK(applet)) { | ||
856 | quote = FALSE; | ||
857 | } | ||
858 | } | ||
859 | # endif | ||
860 | #endif | ||
861 | |||
668 | /* | 862 | /* |
669 | * The Open Group Base Specifications Issue 6: | 863 | * The Open Group Base Specifications Issue 6: |
670 | * "The xargs utility shall limit the command line length such that | 864 | * "The xargs utility shall limit the command line length such that |
@@ -689,7 +883,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
689 | { | 883 | { |
690 | size_t n_chars = 0; | 884 | size_t n_chars = 0; |
691 | for (i = 0; argv[i]; i++) { | 885 | for (i = 0; argv[i]; i++) { |
692 | n_chars += strlen(argv[i]) + 1; | 886 | #if ENABLE_PLATFORM_MINGW32 |
887 | if (quote) | ||
888 | n_chars += quote_len(argv[i]) + 1; | ||
889 | else | ||
890 | #endif | ||
891 | n_chars += strlen(argv[i]) + 1; | ||
693 | } | 892 | } |
694 | n_max_chars -= n_chars; | 893 | n_max_chars -= n_chars; |
695 | } | 894 | } |
@@ -736,21 +935,48 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
736 | store_param(argv[i]); | 935 | store_param(argv[i]); |
737 | } | 936 | } |
738 | 937 | ||
938 | #if !ENABLE_PLATFORM_MINGW32 | ||
739 | if (opt & OPT_STDIN_TTY) { | 939 | if (opt & OPT_STDIN_TTY) { |
740 | G.fd_tty = xopen(CURRENT_TTY, O_RDONLY); | 940 | G.fd_tty = xopen(CURRENT_TTY, O_RDONLY); |
741 | close_on_exec_on(G.fd_tty); | 941 | close_on_exec_on(G.fd_tty); |
742 | G.fd_stdin = dup(STDIN_FILENO); | 942 | G.fd_stdin = dup(STDIN_FILENO); |
743 | close_on_exec_on(G.fd_stdin); | 943 | close_on_exec_on(G.fd_stdin); |
744 | } | 944 | } |
945 | #endif | ||
745 | 946 | ||
746 | initial_idx = G.idx; | 947 | initial_idx = G.idx; |
747 | while (1) { | 948 | while (1) { |
748 | char *rem; | 949 | char *rem; |
950 | #if ENABLE_PLATFORM_MINGW32 | ||
951 | char **args; | ||
952 | char **tail = NULL; | ||
953 | char *saved_arg = NULL; | ||
954 | size_t n_chars; | ||
955 | #endif | ||
749 | 956 | ||
750 | G.idx = initial_idx; | 957 | G.idx = initial_idx IF_PLATFORM_MINGW32(+ delta); |
751 | rem = read_args(n_max_chars, n_max_arg, buf); | 958 | rem = read_args(n_max_chars, n_max_arg, buf); |
752 | store_param(NULL); | 959 | store_param(NULL); |
753 | 960 | ||
961 | #if ENABLE_PLATFORM_MINGW32 | ||
962 | /* Check if quoting expands the command line. If it does we | ||
963 | * truncate args[] and preserve the tail for processing later. */ | ||
964 | args = G.args; | ||
965 | if (quote) { | ||
966 | skip_read: | ||
967 | n_chars = 0; | ||
968 | for (i = initial_idx; args[i]; i++) { | ||
969 | n_chars += quote_len(args[i]) + 1; | ||
970 | if (n_chars > WIN32_MAX_CHARS) { | ||
971 | tail = args + i; | ||
972 | saved_arg = *tail; | ||
973 | *tail = NULL; | ||
974 | break; | ||
975 | } | ||
976 | } | ||
977 | } | ||
978 | #endif | ||
979 | |||
754 | if (!G.args[initial_idx]) { /* not even one ARG was added? */ | 980 | if (!G.args[initial_idx]) { /* not even one ARG was added? */ |
755 | if (*rem != '\0') | 981 | if (*rem != '\0') |
756 | bb_simple_error_msg_and_die("argument line too long"); | 982 | bb_simple_error_msg_and_die("argument line too long"); |
@@ -761,7 +987,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
761 | 987 | ||
762 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { | 988 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { |
763 | const char *fmt = " %s" + 1; | 989 | const char *fmt = " %s" + 1; |
990 | #if !ENABLE_PLATFORM_MINGW32 | ||
764 | char **args = G.args; | 991 | char **args = G.args; |
992 | #endif | ||
765 | for (i = 0; args[i]; i++) { | 993 | for (i = 0; args[i]; i++) { |
766 | fprintf(stderr, fmt, args[i]); | 994 | fprintf(stderr, fmt, args[i]); |
767 | fmt = " %s"; | 995 | fmt = " %s"; |
@@ -775,6 +1003,33 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
775 | break; /* G.xargs_exitcode is set by xargs_exec() */ | 1003 | break; /* G.xargs_exitcode is set by xargs_exec() */ |
776 | } | 1004 | } |
777 | 1005 | ||
1006 | #if ENABLE_PLATFORM_MINGW32 | ||
1007 | delta = 0; | ||
1008 | if (quote && tail) { | ||
1009 | /* The command line was truncated. Preload args[] with | ||
1010 | * the tail we saved earlier. */ | ||
1011 | *tail = saved_arg; | ||
1012 | n_chars = 0; | ||
1013 | for (i = 0; tail[i]; i++) { | ||
1014 | args[initial_idx + i] = tail[i]; | ||
1015 | n_chars += quote_len(tail[i]) + 1; | ||
1016 | } | ||
1017 | args[initial_idx + i] = NULL; | ||
1018 | delta = i; | ||
1019 | |||
1020 | /* The command line still overflows after quoting. | ||
1021 | * Truncate the new args[] and exec it. */ | ||
1022 | if (n_chars > WIN32_MAX_CHARS) | ||
1023 | goto skip_read; | ||
1024 | |||
1025 | /* The first elements of args[] point to strings in the | ||
1026 | * current buf, so we need to preserve it. Allocate a | ||
1027 | * new buf for future use. */ | ||
1028 | free(old_buf); | ||
1029 | old_buf = buf; | ||
1030 | buf = xzalloc(n_max_chars + 1); | ||
1031 | } | ||
1032 | #endif | ||
778 | overlapping_strcpy(buf, rem); | 1033 | overlapping_strcpy(buf, rem); |
779 | } /* while */ | 1034 | } /* while */ |
780 | 1035 | ||
@@ -782,6 +1037,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
782 | free(G.args); | 1037 | free(G.args); |
783 | free(buf); | 1038 | free(buf); |
784 | } | 1039 | } |
1040 | #if ENABLE_FEATURE_CLEAN_UP && ENABLE_PLATFORM_MINGW32 | ||
1041 | free(old_buf); | ||
1042 | #endif | ||
785 | 1043 | ||
786 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 1044 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
787 | G.max_procs = 0; | 1045 | G.max_procs = 0; |