aboutsummaryrefslogtreecommitdiff
path: root/findutils/xargs.c
diff options
context:
space:
mode:
Diffstat (limited to 'findutils/xargs.c')
-rw-r--r--findutils/xargs.c167
1 files changed, 164 insertions, 3 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 890c37534..37064be9d 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
198static 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
227static 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
237check_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,43 @@ static int xargs_exec(void)
240 } 333 }
241 } 334 }
242#endif 335#endif
336#endif
337
338#if ENABLE_PLATFORM_MINGW32
339# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
340 if (G.max_procs == 1) {
341# endif
342# if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1)
343 int applet = find_applet_by_name(G.args[0]);
344 if (applet >= 0 && APPLET_IS_NOFORK(applet)) {
345 status = run_nofork_applet(applet, G.args);
346 } else
347# endif
348 {
349 G.pid = spawn(G.args);
350 status = G.pid < 0 ? -1 : wait4pid(G.pid);
351 }
352# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
353 }
354 else {
355 int idx;
356 status = !G.running_procs && !G.max_procs ? 0 : wait_for_slot(&idx);
357 if (G.max_procs) {
358 HANDLE p = (HANDLE)mingw_spawn_proc((const char **)G.args);
359 if (p < 0)
360 status = -1;
361 else
362 G.procs[idx] = p;
363 } else {
364 while (G.running_procs) {
365 int status2 = wait_for_slot(&idx);
366 if (status2 && !status)
367 status = status2;
368 }
369 }
370 }
371# endif
372#endif
243 /* Manpage: 373 /* Manpage:
244 * """xargs exits with the following status: 374 * """xargs exits with the following status:
245 * 0 if it succeeds 375 * 0 if it succeeds
@@ -278,8 +408,10 @@ static int xargs_exec(void)
278 ret: 408 ret:
279 if (status != 0) 409 if (status != 0)
280 G.xargs_exitcode = status; 410 G.xargs_exitcode = status;
411#if !ENABLE_PLATFORM_MINGW32
281 if (option_mask32 & OPT_STDIN_TTY) 412 if (option_mask32 & OPT_STDIN_TTY)
282 xdup2(G.fd_stdin, STDIN_FILENO); 413 xdup2(G.fd_stdin, STDIN_FILENO);
414#endif
283 return status; 415 return status;
284} 416}
285 417
@@ -559,6 +691,7 @@ static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg
559 */ 691 */
560static int xargs_ask_confirmation(void) 692static int xargs_ask_confirmation(void)
561{ 693{
694#if !ENABLE_PLATFORM_MINGW32
562 FILE *tty_stream; 695 FILE *tty_stream;
563 int r; 696 int r;
564 697
@@ -568,6 +701,18 @@ static int xargs_ask_confirmation(void)
568 r = bb_ask_y_confirmation_FILE(tty_stream); 701 r = bb_ask_y_confirmation_FILE(tty_stream);
569 702
570 fclose(tty_stream); 703 fclose(tty_stream);
704#else
705 int r, c, savec;
706
707 fputs(" ?...", stderr);
708 fflush_all();
709 c = savec = getche();
710 while (c != EOF && c != '\r')
711 c = getche();
712 fputs("\n", stderr);
713 fflush_all();
714 r = (savec == 'y' || savec == 'Y');
715#endif
571 716
572 return r; 717 return r;
573} 718}
@@ -585,7 +730,9 @@ static int xargs_ask_confirmation(void)
585//usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( 730//usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE(
586//usage: "\n -a FILE Read from FILE instead of stdin" 731//usage: "\n -a FILE Read from FILE instead of stdin"
587//usage: ) 732//usage: )
733//usage: IF_NOT_PLATFORM_MINGW32(
588//usage: "\n -o Reopen stdin as /dev/tty" 734//usage: "\n -o Reopen stdin as /dev/tty"
735//usage: )
589//usage: "\n -r Don't run command if input is empty" 736//usage: "\n -r Don't run command if input is empty"
590//usage: "\n -t Print the command on stderr before execution" 737//usage: "\n -t Print the command on stderr before execution"
591//usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( 738//usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(
@@ -628,6 +775,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
628 775
629 INIT_G(); 776 INIT_G();
630 777
778#if ENABLE_PLATFORM_MINGW32
779 SetConsoleCtrlHandler(ctrl_handler, TRUE);
780#endif
631 opt = getopt32long(argv, OPTION_STR, 781 opt = getopt32long(argv, OPTION_STR,
632 "no-run-if-empty\0" No_argument "r", 782 "no-run-if-empty\0" No_argument "r",
633 &max_args, &max_chars, &G.eof_str, &G.eof_str 783 &max_args, &max_chars, &G.eof_str, &G.eof_str
@@ -638,7 +788,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
638 788
639#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL 789#if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
640 if (G.max_procs <= 0) /* -P0 means "run lots of them" */ 790 if (G.max_procs <= 0) /* -P0 means "run lots of them" */
791#if !ENABLE_PLATFORM_MINGW32
641 G.max_procs = 100; /* let's not go crazy high */ 792 G.max_procs = 100; /* let's not go crazy high */
793#else
794 G.max_procs = MAXIMUM_WAIT_OBJECTS;
795 G.procs = xmalloc(sizeof(G.procs[0]) * G.max_procs);
796#endif
642#endif 797#endif
643 798
644#if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE 799#if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE
@@ -736,12 +891,14 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
736 store_param(argv[i]); 891 store_param(argv[i]);
737 } 892 }
738 893
894#if !ENABLE_PLATFORM_MINGW32
739 if (opt & OPT_STDIN_TTY) { 895 if (opt & OPT_STDIN_TTY) {
740 G.fd_tty = xopen(CURRENT_TTY, O_RDONLY); 896 G.fd_tty = xopen(CURRENT_TTY, O_RDONLY);
741 close_on_exec_on(G.fd_tty); 897 close_on_exec_on(G.fd_tty);
742 G.fd_stdin = dup(STDIN_FILENO); 898 G.fd_stdin = dup(STDIN_FILENO);
743 close_on_exec_on(G.fd_stdin); 899 close_on_exec_on(G.fd_stdin);
744 } 900 }
901#endif
745 902
746 initial_idx = G.idx; 903 initial_idx = G.idx;
747 while (1) { 904 while (1) {
@@ -767,7 +924,11 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
767 fmt = " %s"; 924 fmt = " %s";
768 } 925 }
769 if (!(opt & OPT_INTERACTIVE)) 926 if (!(opt & OPT_INTERACTIVE))
927#if !ENABLE_PLATFORM_MINGW32
770 bb_putchar_stderr('\n'); 928 bb_putchar_stderr('\n');
929#else
930 fprintf(stderr, "\n");
931#endif
771 } 932 }
772 933
773 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { 934 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {