diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2003-10-10 12:10:18 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2003-10-10 12:10:18 +0000 |
commit | 61796945e37a6cd9dd230e8e7a86536ad58fcd14 (patch) | |
tree | 1ba1c408f3aa907e46a90d1a3b453e222699091d /findutils/xargs.c | |
parent | 75a5684793da59f8ed4c7fc6b05bc2bf148d06b1 (diff) | |
download | busybox-w32-61796945e37a6cd9dd230e8e7a86536ad58fcd14.tar.gz busybox-w32-61796945e37a6cd9dd230e8e7a86536ad58fcd14.tar.bz2 busybox-w32-61796945e37a6cd9dd230e8e7a86536ad58fcd14.zip |
Vods versions of xargs
Diffstat (limited to 'findutils/xargs.c')
-rw-r--r-- | findutils/xargs.c | 701 |
1 files changed, 510 insertions, 191 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c index 1af42384b..8bab44623 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -1,11 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * Mini xargs implementation for busybox | 2 | * Mini xargs implementation for busybox |
3 | * Only "-prt" options are supported in this version of xargs. | 3 | * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]" |
4 | * | 4 | * |
5 | * (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru> | 5 | * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru> |
6 | * (C) 2003 by Glenn McGrath <bug1@optushome.com.au> | ||
7 | * | 6 | * |
8 | * Special thanks Mark Whitley for stimul to rewrote :) | 7 | * Special thanks |
8 | * - Mark Whitley and Glenn McGrath for stimul to rewrote :) | ||
9 | * - Mike Rendell <michael@cs.mun.ca> | ||
10 | * and David MacKenzie <djm@gnu.ai.mit.edu>. | ||
9 | * | 11 | * |
10 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -21,15 +23,6 @@ | |||
21 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 25 | * |
24 | * | ||
25 | * Reference: | ||
26 | * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html | ||
27 | * | ||
28 | * | ||
29 | * BUGS: | ||
30 | * - E option doesnt allow spaces before argument | ||
31 | * - exit value of isnt correct | ||
32 | * - doesnt print quoted string properly | ||
33 | */ | 26 | */ |
34 | 27 | ||
35 | #include <stdio.h> | 28 | #include <stdio.h> |
@@ -38,224 +31,550 @@ | |||
38 | #include <unistd.h> | 31 | #include <unistd.h> |
39 | #include <getopt.h> | 32 | #include <getopt.h> |
40 | #include <errno.h> | 33 | #include <errno.h> |
34 | #include <fcntl.h> | ||
41 | #include <sys/types.h> | 35 | #include <sys/types.h> |
42 | #include <sys/wait.h> | 36 | #include <sys/wait.h> |
43 | |||
44 | #include "busybox.h" | 37 | #include "busybox.h" |
45 | 38 | ||
39 | /* COMPAT: SYSV version defaults size (and has a max value of) to 470. | ||
40 | We try to make it as large as possible. */ | ||
41 | #if !defined(ARG_MAX) && defined(_SC_ARG_MAX) | ||
42 | #define ARG_MAX sysconf (_SC_ARG_MAX) | ||
43 | #endif | ||
44 | #ifndef ARG_MAX | ||
45 | #define ARG_MAX 470 | ||
46 | #endif | ||
47 | |||
48 | |||
49 | #ifdef TEST | ||
50 | # ifndef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
51 | # define CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
52 | # endif | ||
53 | # ifndef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES | ||
54 | # define CONFIG_FEATURE_XARGS_SUPPORT_QUOTES | ||
55 | # endif | ||
56 | # ifndef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT | ||
57 | # define CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT | ||
58 | # endif | ||
59 | # ifndef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
60 | # define CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
61 | # endif | ||
62 | #endif | ||
63 | |||
46 | /* | 64 | /* |
47 | This function have special algorithm. | 65 | This function have special algorithm. |
48 | Don`t use fork and include to main! | 66 | Don`t use fork and include to main! |
49 | */ | 67 | */ |
50 | static int xargs_exec(char **args) | 68 | static int |
69 | xargs_exec (char *const *args) | ||
51 | { | 70 | { |
52 | pid_t p; | 71 | pid_t p; |
53 | volatile int exec_errno; /* shared vfork stack */ | 72 | volatile int exec_errno = 0; /* shared vfork stack */ |
54 | 73 | ||
55 | exec_errno = 0; | 74 | if ((p = vfork ()) >= 0) { |
56 | p = vfork(); | 75 | if (p == 0) { |
57 | if (p < 0) { | 76 | /* vfork -- child */ |
58 | bb_perror_msg_and_die("vfork"); | 77 | execvp (args[0], args); |
59 | } else if (p == 0) { | 78 | exec_errno = errno; /* set error to shared stack */ |
60 | /* vfork -- child */ | 79 | _exit (1); |
61 | execvp(args[0], args); | ||
62 | exec_errno = errno; /* set error to shared stack */ | ||
63 | _exit(1); | ||
64 | } else { | 80 | } else { |
65 | /* vfork -- parent */ | 81 | /* vfork -- parent */ |
66 | int status; | 82 | int status; |
67 | 83 | ||
68 | while (wait(&status) == (pid_t) - 1) { | 84 | while (wait (&status) == (pid_t) - 1) |
69 | if (errno != EINTR) { | 85 | if (errno != EINTR) |
70 | break; | 86 | break; |
71 | } | 87 | if (exec_errno) { |
88 | errno = exec_errno; | ||
89 | bb_perror_msg ("%s", args[0]); | ||
90 | return exec_errno == ENOENT ? 127 : 126; | ||
91 | } else { | ||
92 | if (WEXITSTATUS (status) == 255) { | ||
93 | bb_error_msg ("%s: exited with status 255; aborting", args[0]); | ||
94 | return 124; | ||
72 | } | 95 | } |
73 | 96 | if (WIFSTOPPED (status)) { | |
74 | if (exec_errno) { | 97 | bb_error_msg ("%s: stopped by signal %d", args[0], |
75 | errno = exec_errno; | 98 | WSTOPSIG (status)); |
76 | bb_perror_msg("%s", args[0]); | 99 | return 125; |
77 | return exec_errno == ENOENT ? 127 : 126; | 100 | } |
78 | } else if (WEXITSTATUS(status) == 255) { | 101 | if (WIFSIGNALED (status)) { |
79 | bb_error_msg("%s: exited with status 255; aborting", args[0]); | 102 | bb_error_msg ("%s: terminated by signal %d", args[0], |
80 | return 124; | 103 | WTERMSIG (status)); |
81 | } else if (WIFSTOPPED(status)) { | 104 | return 125; |
82 | bb_error_msg("%s: stopped by signal %d", args[0], | ||
83 | WSTOPSIG(status)); | ||
84 | return 125; | ||
85 | } else if (WIFSIGNALED(status)) { | ||
86 | bb_error_msg("%s: terminated by signal %d", args[0], | ||
87 | WTERMSIG(status)); | ||
88 | return 125; | ||
89 | } else if (WEXITSTATUS(status)) { | ||
90 | return 123; | ||
91 | } else { | ||
92 | return 0; | ||
93 | } | 105 | } |
106 | if (WEXITSTATUS (status) != 0) | ||
107 | return 123; | ||
108 | return 0; | ||
109 | } | ||
94 | } | 110 | } |
111 | } else { | ||
112 | bb_perror_msg_and_die ("vfork"); | ||
113 | } | ||
95 | } | 114 | } |
96 | 115 | ||
97 | #define OPT_VERBOSE 0x1 | ||
98 | #define OPT_TERMINATE 0x2 | ||
99 | #define OPT_UPTO_NUMBER 0x4 | ||
100 | #define OPT_UPTO_SIZE 0x8 | ||
101 | #define OPT_EOF_STRING 0x10 | ||
102 | 116 | ||
103 | int xargs_main(int argc, char **argv) | 117 | typedef struct xlist_s { |
118 | char *data; | ||
119 | size_t lenght; | ||
120 | struct xlist_s *link; | ||
121 | } xlist_t; | ||
122 | |||
123 | static int eof_stdin_detected; | ||
124 | |||
125 | #define ISBLANK(c) ((c) == ' ' || (c) == '\t') | ||
126 | #define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \ | ||
127 | || (c) == '\f' || (c) == '\v') | ||
128 | |||
129 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES | ||
130 | static xlist_t * | ||
131 | process_stdin (xlist_t *list_arg, const char *eof_str, size_t mc, char *buf) | ||
104 | { | 132 | { |
105 | #ifdef CONFIG_FEATURE_XARGS_FANCY | 133 | #define NORM 0 |
106 | char *s_max_args = NULL; | 134 | #define QUOTE 1 |
107 | char *s_line_size = NULL; | 135 | #define BACKSLASH 2 |
108 | #endif | 136 | #define SPACE 4 |
109 | char *eof_string = "_"; | 137 | |
110 | unsigned long flg; | 138 | char *s = NULL; /* start word */ |
139 | char *p = NULL; /* pointer to end word */ | ||
140 | char q = 0; /* quote char */ | ||
141 | char state = NORM; | ||
142 | char eof_str_detected = 0; | ||
143 | size_t line_l = 0; /* size loaded args line */ | ||
144 | int c; /* current char */ | ||
145 | xlist_t *cur; | ||
146 | xlist_t *prev; | ||
147 | |||
148 | for(prev = cur = list_arg; cur; cur = cur->link) { | ||
149 | line_l += cur->lenght; /* previous allocated */ | ||
150 | if(prev != cur) | ||
151 | prev = prev->link; | ||
152 | } | ||
153 | |||
154 | while(!eof_stdin_detected) { | ||
155 | c = getchar(); | ||
156 | if(c == EOF) { | ||
157 | eof_stdin_detected++; | ||
158 | if(s) | ||
159 | goto unexpected_eof; | ||
160 | break; | ||
161 | } | ||
162 | if(eof_str_detected) | ||
163 | continue; | ||
164 | if (state == BACKSLASH) { | ||
165 | state = NORM; | ||
166 | goto set; | ||
167 | } else if (state == QUOTE) { | ||
168 | if (c == q) { | ||
169 | q = 0; | ||
170 | state = NORM; | ||
171 | } else { | ||
172 | goto set; | ||
173 | } | ||
174 | } else /* if(state == NORM) */ { | ||
175 | if (ISSPACE (c)) { | ||
176 | if (s) { | ||
177 | unexpected_eof: | ||
178 | state = SPACE; | ||
179 | c = 0; | ||
180 | goto set; | ||
181 | } | ||
182 | } else { | ||
183 | if (s == NULL) | ||
184 | s = p = buf; | ||
185 | if (c == '\\') { | ||
186 | state = BACKSLASH; | ||
187 | } else if (c == '\'' || c == '"') { | ||
188 | q = c; | ||
189 | state = QUOTE; | ||
190 | } else { | ||
191 | set: | ||
192 | if( (p-buf) >= mc) | ||
193 | bb_error_msg_and_die ("argument line too long"); | ||
194 | *p++ = c; | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | if (state == SPACE) { /* word's delimiter or EOF detected */ | ||
199 | if (q) | ||
200 | bb_error_msg_and_die ("unmatched %s quote", | ||
201 | q == '\'' ? "single" : "double"); | ||
202 | /* word loaded */ | ||
203 | if(eof_str) { | ||
204 | eof_str_detected = strcmp(s, eof_str) == 0; | ||
205 | } | ||
206 | if(!eof_str_detected) { | ||
207 | size_t lenght = (p-buf); | ||
111 | 208 | ||
112 | int line_size; | 209 | cur = xmalloc(sizeof(xlist_t) + lenght); |
113 | unsigned int max_args = LINE_MAX; | 210 | cur->data = memcpy(cur + 1, s, lenght); |
211 | cur->lenght = lenght; | ||
212 | cur->link = NULL; | ||
213 | if(prev == NULL) { | ||
214 | list_arg = cur; | ||
215 | } else { | ||
216 | prev->link = cur; | ||
217 | } | ||
218 | prev = cur; | ||
219 | line_l += lenght; | ||
220 | if(line_l > mc) { | ||
221 | /* stop memory usage :-) */ | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | s = NULL; | ||
226 | state = NORM; | ||
227 | } | ||
228 | } | ||
229 | return list_arg; | ||
230 | } | ||
231 | #else | ||
232 | /* The variant is unsupport single, double quotes and backslash */ | ||
233 | static xlist_t * | ||
234 | process_stdin (xlist_t *list_arg, const char *eof_str, size_t mc, char *buf) | ||
235 | { | ||
114 | 236 | ||
115 | char *line_buffer = NULL; | 237 | int c; /* current char */ |
116 | char *line_buffer_ptr_ptr; | 238 | int eof_str_detected = 0; |
117 | char *old_arg = NULL; | 239 | char *s = NULL; /* start word */ |
240 | char *p = NULL; /* pointer to end word */ | ||
241 | size_t line_l = 0; /* size loaded args line */ | ||
242 | xlist_t *cur; | ||
243 | xlist_t *prev; | ||
118 | 244 | ||
119 | char **args; | 245 | for(prev = cur = list_arg; cur; cur = cur->link) { |
120 | char *args_entry_ptr; | 246 | line_l += cur->lenght; /* previous allocated */ |
247 | if(prev != cur) | ||
248 | prev = prev->link; | ||
249 | } | ||
121 | 250 | ||
122 | int i; | 251 | while(!eof_stdin_detected) { |
123 | int a; | 252 | c = getchar(); |
253 | if(c == EOF) { | ||
254 | eof_stdin_detected++; | ||
255 | } | ||
256 | if(eof_str_detected) | ||
257 | continue; | ||
258 | if (c == EOF || ISSPACE (c)) { | ||
259 | if(s == NULL) | ||
260 | continue; | ||
261 | c = EOF; | ||
262 | } | ||
263 | if (s == NULL) | ||
264 | s = p = buf; | ||
265 | if( (p-buf) >= mc) | ||
266 | bb_error_msg_and_die ("argument line too long"); | ||
267 | *p++ = c == EOF ? 0 : c; | ||
268 | if (c == EOF) { /* word's delimiter or EOF detected */ | ||
269 | /* word loaded */ | ||
270 | if(eof_str) { | ||
271 | eof_str_detected = strcmp(s, eof_str) == 0; | ||
272 | } | ||
273 | if(!eof_str_detected) { | ||
274 | size_t lenght = (p-buf); | ||
124 | 275 | ||
125 | #if 0 | 276 | cur = xmalloc(sizeof(xlist_t) + lenght); |
126 | /* Default to maximum line length */ | 277 | cur->data = memcpy(cur + 1, s, lenght); |
127 | if (LINE_MAX > ARG_MAX - 2048) { | 278 | cur->lenght = lenght; |
128 | /* Minimum command line length */ | 279 | cur->link = NULL; |
129 | line_size = LINE_MAX; | 280 | if(prev == NULL) { |
130 | } else { | 281 | list_arg = cur; |
131 | /* Maximum command line length */ | 282 | } else { |
132 | line_size = ARG_MAX = 2048; | 283 | prev->link = cur; |
284 | } | ||
285 | prev = cur; | ||
286 | line_l += lenght; | ||
287 | if(line_l > mc) { | ||
288 | /* stop memory usage :-) */ | ||
289 | break; | ||
290 | } | ||
291 | s = NULL; | ||
292 | } | ||
133 | } | 293 | } |
294 | } | ||
295 | return list_arg; | ||
296 | } | ||
297 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_QUOTES */ | ||
298 | |||
299 | |||
300 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
301 | /* Prompt the user for a response, and | ||
302 | if the user responds affirmatively, return true; | ||
303 | otherwise, return false. Used "/dev/tty", not stdin. */ | ||
304 | static int | ||
305 | xargs_ask_confirmation (void) | ||
306 | { | ||
307 | static FILE *tty_stream; | ||
308 | int c, savec; | ||
309 | |||
310 | if (!tty_stream) { | ||
311 | tty_stream = fopen ("/dev/tty", "r"); | ||
312 | if (!tty_stream) | ||
313 | bb_perror_msg_and_die ("/dev/tty"); | ||
314 | /* pranoidal security by vodz */ | ||
315 | fcntl(fileno(tty_stream), F_SETFD, FD_CLOEXEC); | ||
316 | } | ||
317 | fputs (" ?...", stderr); | ||
318 | fflush (stderr); | ||
319 | c = savec = getc (tty_stream); | ||
320 | while (c != EOF && c != '\n') | ||
321 | c = getc (tty_stream); | ||
322 | if (savec == 'y' || savec == 'Y') | ||
323 | return 1; | ||
324 | return 0; | ||
325 | } | ||
326 | # define OPT_INC_P 1 | ||
134 | #else | 327 | #else |
135 | line_size = LINE_MAX; | 328 | # define OPT_INC_P 0 |
136 | #endif | 329 | # define xargs_ask_confirmation() 1 |
137 | 330 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */ | |
138 | #ifndef CONFIG_FEATURE_XARGS_FANCY | 331 | |
139 | flg = bb_getopt_ulflags(argc, argv, "+t"); | 332 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT |
333 | # define OPT_INC_X 1 | ||
140 | #else | 334 | #else |
141 | flg = bb_getopt_ulflags(argc, argv, "+txn:s:E::", &s_max_args, &s_line_size, &eof_string); | 335 | # define OPT_INC_X 0 |
336 | #endif | ||
142 | 337 | ||
143 | if (s_line_size) { | 338 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM |
144 | line_size = bb_xgetularg10_bnd(s_max_args, 1, line_size); | 339 | static xlist_t * |
340 | process0_stdin (xlist_t *list_arg, const char *eof_str, size_t mc, char *buf) | ||
341 | { | ||
342 | int c; /* current char */ | ||
343 | char *s = NULL; /* start word */ | ||
344 | char *p = NULL; /* pointer to end word */ | ||
345 | size_t line_l = 0; /* size loaded args line */ | ||
346 | xlist_t *cur; | ||
347 | xlist_t *prev; | ||
348 | |||
349 | for(prev = cur = list_arg; cur; cur = cur->link) { | ||
350 | line_l += cur->lenght; /* previous allocated */ | ||
351 | if(prev != cur) | ||
352 | prev = prev->link; | ||
353 | } | ||
354 | |||
355 | while(!eof_stdin_detected) { | ||
356 | c = getchar(); | ||
357 | if(c == EOF) { | ||
358 | eof_stdin_detected++; | ||
359 | if(s == NULL) | ||
360 | break; | ||
361 | c = 0; | ||
145 | } | 362 | } |
146 | if (s_max_args) { | 363 | if (s == NULL) |
147 | max_args = bb_xgetularg10(s_max_args); | 364 | s = p = buf; |
365 | if( (p-buf) >= mc) | ||
366 | bb_error_msg_and_die ("argument line too long"); | ||
367 | *p++ = c; | ||
368 | if (c == 0) { /* word's delimiter or EOF detected */ | ||
369 | /* word loaded */ | ||
370 | size_t lenght = (p-buf); | ||
371 | |||
372 | cur = xmalloc(sizeof(xlist_t) + lenght); | ||
373 | cur->data = memcpy(cur + 1, s, lenght); | ||
374 | cur->lenght = lenght; | ||
375 | cur->link = NULL; | ||
376 | if(prev == NULL) { | ||
377 | list_arg = cur; | ||
378 | } else { | ||
379 | prev->link = cur; | ||
380 | } | ||
381 | prev = cur; | ||
382 | line_l += lenght; | ||
383 | if(line_l > mc) { | ||
384 | /* stop memory usage :-) */ | ||
385 | break; | ||
386 | } | ||
387 | s = NULL; | ||
148 | } | 388 | } |
389 | } | ||
390 | return list_arg; | ||
391 | } | ||
392 | # define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc) | ||
393 | # define OPT_INC_0 1 /* future use */ | ||
394 | #else | ||
395 | # define OPT_INC_0 0 /* future use */ | ||
396 | # define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc) | ||
397 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */ | ||
398 | |||
399 | |||
400 | #define OPT_VERBOSE (1<<0) | ||
401 | #define OPT_NO_EMPTY (1<<1) | ||
402 | #define OPT_UPTO_NUMBER (1<<2) | ||
403 | #define OPT_UPTO_SIZE (1<<3) | ||
404 | #define OPT_EOF_STRING (1<<4) | ||
405 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
406 | #define OPT_INTERACTIVE (1<<5) | ||
407 | #else | ||
408 | #define OPT_INTERACTIVE (0) /* require for algorithm &| */ | ||
149 | #endif | 409 | #endif |
410 | #define OPT_TERMINATE (1<<(5+OPT_INC_P)) | ||
411 | #define OPT_ZEROTERM (1<<(5+OPT_INC_P+OPT_INC_X)) | ||
412 | /* next future | ||
413 | #define OPT_NEXT_OTHER (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0)) | ||
414 | */ | ||
150 | 415 | ||
151 | a = argc - optind; | 416 | int |
152 | argv += optind; | 417 | xargs_main (int argc, char **argv) |
153 | if (a == 0) { | 418 | { |
154 | /* default behavior is to echo all the filenames */ | 419 | char **args; |
155 | *argv = "echo"; | 420 | int i, a, n; |
156 | a++; | 421 | xlist_t *list = NULL; |
157 | } | 422 | xlist_t *cur; |
158 | /* allocating pointers for execvp: a*arg, arg from stdin, NULL */ | 423 | int child_error = 0; |
159 | args = xcalloc(a + 2, sizeof(char *)); | 424 | char *max_args, *max_chars; |
425 | int n_max_arg; | ||
426 | size_t n_chars = 0; | ||
427 | long orig_arg_max; | ||
428 | const char *eof_str = "_"; | ||
429 | unsigned long opt; | ||
430 | size_t n_max_chars; | ||
431 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
432 | xlist_t * (*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin; | ||
433 | #endif | ||
160 | 434 | ||
161 | /* Store the command to be executed (taken from the command line) */ | 435 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION |
436 | bb_opt_complementaly = "pt"; | ||
437 | #endif | ||
438 | |||
439 | opt = bb_getopt_ulflags (argc, argv, "+trn:s:e::" | ||
440 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
441 | "p" | ||
442 | #endif | ||
443 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT | ||
444 | "x" | ||
445 | #endif | ||
446 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
447 | "0" | ||
448 | #endif | ||
449 | , &max_args, &max_chars, &eof_str); | ||
450 | |||
451 | a = argc - optind; | ||
452 | argv += optind; | ||
453 | if (a == 0) { | ||
454 | /* default behavior is to echo all the filenames */ | ||
455 | *argv = "echo"; | ||
456 | a++; | ||
457 | } | ||
458 | |||
459 | orig_arg_max = ARG_MAX; | ||
460 | if (orig_arg_max == -1) | ||
461 | orig_arg_max = LONG_MAX; | ||
462 | orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */ | ||
463 | if ((opt & OPT_UPTO_SIZE)) { | ||
464 | n_max_chars = bb_xgetularg10_bnd (max_chars, 1, orig_arg_max); | ||
162 | for (i = 0; i < a; i++) { | 465 | for (i = 0; i < a; i++) { |
163 | line_size -= strlen(*argv) + 1; | 466 | n_chars += strlen (*argv) + 1; |
164 | args[i] = *argv++; | ||
165 | } | 467 | } |
166 | if (line_size < 1) { | 468 | if (n_max_chars < n_chars) { |
167 | bb_error_msg_and_die("can not fit single argument within argument list size limit"); | 469 | bb_error_msg_and_die |
470 | ("can not fit single argument within argument list size limit"); | ||
168 | } | 471 | } |
472 | n_max_chars -= n_chars; | ||
473 | } else { | ||
474 | /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which | ||
475 | have it at 1 meg). Things will work fine with a large ARG_MAX but it | ||
476 | will probably hurt the system more than it needs to; an array of this | ||
477 | size is allocated. */ | ||
478 | if (orig_arg_max > 20 * 1024) | ||
479 | orig_arg_max = 20 * 1024; | ||
480 | n_max_chars = orig_arg_max; | ||
481 | } | ||
482 | max_chars = xmalloc(n_max_chars); | ||
169 | 483 | ||
170 | args[i] = xmalloc(line_size); | 484 | if ((opt & OPT_UPTO_NUMBER)) { |
171 | args_entry_ptr = args[i]; | 485 | n_max_arg = bb_xgetularg10_bnd (max_args, 1, INT_MAX); |
172 | 486 | } else { | |
173 | /* Now, read in one line at a time from stdin, and store this | 487 | n_max_arg = n_max_chars; |
174 | * line to be used later as an argument to the command */ | 488 | } |
175 | do { | 489 | |
176 | char *line_buffer_ptr = NULL; | 490 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM |
177 | unsigned int arg_count = 0; | 491 | if(opt & OPT_ZEROTERM) |
178 | unsigned int arg_size = 0; | 492 | read_args = process0_stdin; |
179 | |||
180 | *args_entry_ptr = '\0'; | ||
181 | |||
182 | /* Get the required number of entries from stdin */ | ||
183 | do { | ||
184 | /* (Re)fill the line buffer */ | ||
185 | if (line_buffer == NULL) { | ||
186 | line_buffer = bb_get_chomped_line_from_file(stdin); | ||
187 | if (line_buffer == NULL) { | ||
188 | /* EOF, exit outer loop */ | ||
189 | break; | ||
190 | } | ||
191 | line_buffer_ptr = | ||
192 | strtok_r(line_buffer, " \t", &line_buffer_ptr_ptr); | ||
193 | } else { | ||
194 | if (old_arg) { | ||
195 | line_buffer_ptr = old_arg; | ||
196 | old_arg = NULL; | ||
197 | } else { | ||
198 | line_buffer_ptr = | ||
199 | strtok_r(NULL, " \t", &line_buffer_ptr_ptr); | ||
200 | } | ||
201 | } | ||
202 | /* If no arguments left go back and get another line */ | ||
203 | if (line_buffer_ptr == NULL) { | ||
204 | free(line_buffer); | ||
205 | line_buffer = NULL; | ||
206 | continue; | ||
207 | } | ||
208 | |||
209 | #ifdef CONFIG_FEATURE_XARGS_FANCY | ||
210 | if (eof_string && (strcmp(line_buffer_ptr, eof_string) == 0)) { | ||
211 | #else | ||
212 | if (strcmp(line_buffer_ptr, eof_string) == 0) { | ||
213 | #endif | 493 | #endif |
214 | /* logical EOF, exit outer loop */ | 494 | |
215 | line_buffer = NULL; | 495 | while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL |
216 | break; | 496 | || (opt & OPT_NO_EMPTY) == 0) { |
217 | } | 497 | opt |= OPT_NO_EMPTY; |
218 | 498 | n = 0; | |
219 | /* Check the next argument will fit */ | 499 | n_chars = 0; |
220 | arg_size += 1 + strlen(line_buffer_ptr); | 500 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT |
221 | if (arg_size > line_size) { | 501 | for (cur = list; cur; ) { |
222 | if ((arg_count == 0) | 502 | n_chars += cur->lenght; |
223 | #ifdef CONFIG_FEATURE_XARGS_FANCY | 503 | n++; |
224 | || ((flg & OPT_TERMINATE) && (arg_count != max_args))) { | 504 | cur = cur->link; |
505 | if (n_chars > n_max_chars || (n == n_max_arg && cur)) { | ||
506 | if (opt & OPT_TERMINATE) | ||
507 | bb_error_msg_and_die ("argument list too long"); | ||
508 | break; | ||
509 | } | ||
510 | } | ||
225 | #else | 511 | #else |
226 | ) { | 512 | for (cur = list; cur; cur = cur->link) { |
227 | #endif | 513 | n_chars += cur->lenght; |
228 | bb_error_msg_and_die("argument line too long"); | 514 | n++; |
229 | } | 515 | if (n_chars > n_max_chars || n == n_max_arg) { |
230 | old_arg = line_buffer_ptr; | 516 | break; |
231 | break; | 517 | } |
232 | } | 518 | } |
233 | 519 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */ | |
234 | /* Add the entry to our pre-allocated space */ | 520 | |
235 | strcat(args_entry_ptr, line_buffer_ptr); | 521 | /* allocating pointers for execvp: |
236 | strcat(args_entry_ptr, " "); | 522 | a*arg, n*arg from stdin, NULL */ |
237 | arg_count++; | 523 | args = xcalloc (n + a + 1, sizeof (char *)); |
238 | } while (arg_count < max_args); | 524 | |
239 | 525 | /* Store the command to be executed | |
240 | /* Remove the last space */ | 526 | (taken from the command line) */ |
241 | args_entry_ptr[arg_size - 1] = '\0'; | 527 | for (i = 0; i < a; i++) |
242 | 528 | args[i] = argv[i]; | |
243 | if (*args_entry_ptr != '\0') { | 529 | /* (taken from stdin) */ |
244 | if (flg & OPT_VERBOSE) { | 530 | for (cur = list; n; cur = cur->link) { |
245 | for (i = 0; args[i]; i++) { | 531 | args[i++] = cur->data; |
246 | if (i) { | 532 | n--; |
247 | fputc(' ', stderr); | 533 | } |
248 | } | 534 | |
249 | fputs(args[i], stderr); | 535 | if ((opt & (OPT_INTERACTIVE|OPT_VERBOSE))) { |
250 | } | 536 | for (i = 0; args[i]; i++) { |
251 | fputc('\n', stderr); | 537 | if (i) |
252 | } | 538 | fputc (' ', stderr); |
253 | xargs_exec(args); | 539 | fputs (args[i], stderr); |
254 | } | 540 | } |
255 | } while (line_buffer); | 541 | if((opt & OPT_INTERACTIVE) == 0) |
542 | fputc ('\n', stderr); | ||
543 | } | ||
544 | if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation () != 0) { | ||
545 | child_error = xargs_exec (args); | ||
546 | } | ||
256 | 547 | ||
548 | /* clean up */ | ||
549 | for (i = a; args[i]; i++) { | ||
550 | cur = list; | ||
551 | list = list->link; | ||
552 | free (cur); | ||
553 | } | ||
554 | free (args); | ||
555 | if (child_error > 0 && child_error != 123) { | ||
556 | break; | ||
557 | } | ||
558 | } | ||
257 | #ifdef CONFIG_FEATURE_CLEAN_UP | 559 | #ifdef CONFIG_FEATURE_CLEAN_UP |
258 | free(args); | 560 | free(max_chars); |
259 | #endif | 561 | #endif |
260 | return 0; | 562 | return child_error; |
563 | } | ||
564 | |||
565 | |||
566 | #ifdef TEST | ||
567 | |||
568 | const char *bb_applet_name = "debug stuff usage"; | ||
569 | |||
570 | void bb_show_usage(void) | ||
571 | { | ||
572 | fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n", bb_applet_name); | ||
573 | exit(1); | ||
574 | } | ||
575 | |||
576 | int main(int argc, char **argv) | ||
577 | { | ||
578 | return xargs_main(argc, argv); | ||
261 | } | 579 | } |
580 | #endif /* TEST */ | ||