diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-29 08:20:30 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-29 08:20:30 +0000 |
commit | 6248a734e2d59ebe95aeb39189326d90f018804e (patch) | |
tree | 89e5415774982c6293dc40f684543732d2378abb /findutils/xargs.c | |
parent | 981b24db5e7ccc289c2e39a2954cf1ff261442b9 (diff) | |
download | busybox-w32-6248a734e2d59ebe95aeb39189326d90f018804e.tar.gz busybox-w32-6248a734e2d59ebe95aeb39189326d90f018804e.tar.bz2 busybox-w32-6248a734e2d59ebe95aeb39189326d90f018804e.zip |
xargs: simplify option parsing
Diffstat (limited to 'findutils/xargs.c')
-rw-r--r-- | findutils/xargs.c | 207 |
1 files changed, 91 insertions, 116 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c index d067a3f48..b6a154f15 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -45,54 +45,52 @@ | |||
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | /* | 47 | /* |
48 | This function have special algorithm. | 48 | This function has special algorithm. |
49 | Don`t use fork and include to main! | 49 | Don't use fork and include to main! |
50 | */ | 50 | */ |
51 | static int xargs_exec(char *const *args) | 51 | static int xargs_exec(char *const *args) |
52 | { | 52 | { |
53 | pid_t p; | 53 | pid_t p; |
54 | volatile int exec_errno = 0; /* shared vfork stack */ | 54 | volatile int exec_errno = 0; /* shared vfork stack */ |
55 | int status; | ||
55 | 56 | ||
56 | if ((p = vfork()) >= 0) { | 57 | p = vfork(); |
57 | if (p == 0) { | 58 | if (p < 0) |
58 | /* vfork -- child */ | ||
59 | execvp(args[0], args); | ||
60 | exec_errno = errno; /* set error to shared stack */ | ||
61 | _exit(1); | ||
62 | } else { | ||
63 | /* vfork -- parent */ | ||
64 | int status; | ||
65 | |||
66 | while (wait(&status) == (pid_t) - 1) | ||
67 | if (errno != EINTR) | ||
68 | break; | ||
69 | if (exec_errno) { | ||
70 | errno = exec_errno; | ||
71 | bb_perror_msg("%s", args[0]); | ||
72 | return exec_errno == ENOENT ? 127 : 126; | ||
73 | } else { | ||
74 | if (WEXITSTATUS(status) == 255) { | ||
75 | bb_error_msg("%s: exited with status 255; aborting", args[0]); | ||
76 | return 124; | ||
77 | } | ||
78 | if (WIFSTOPPED(status)) { | ||
79 | bb_error_msg("%s: stopped by signal %d", | ||
80 | args[0], WSTOPSIG(status)); | ||
81 | return 125; | ||
82 | } | ||
83 | if (WIFSIGNALED(status)) { | ||
84 | bb_error_msg("%s: terminated by signal %d", | ||
85 | args[0], WTERMSIG(status)); | ||
86 | return 125; | ||
87 | } | ||
88 | if (WEXITSTATUS(status) != 0) | ||
89 | return 123; | ||
90 | return 0; | ||
91 | } | ||
92 | } | ||
93 | } else { | ||
94 | bb_perror_msg_and_die("vfork"); | 59 | bb_perror_msg_and_die("vfork"); |
60 | |||
61 | if (p == 0) { | ||
62 | /* vfork -- child */ | ||
63 | execvp(args[0], args); | ||
64 | exec_errno = errno; /* set error to shared stack */ | ||
65 | _exit(1); | ||
66 | } | ||
67 | |||
68 | /* vfork -- parent */ | ||
69 | while (wait(&status) == (pid_t) -1) | ||
70 | if (errno != EINTR) | ||
71 | break; | ||
72 | if (exec_errno) { | ||
73 | errno = exec_errno; | ||
74 | bb_perror_msg("%s", args[0]); | ||
75 | return exec_errno == ENOENT ? 127 : 126; | ||
95 | } | 76 | } |
77 | if (WEXITSTATUS(status) == 255) { | ||
78 | bb_error_msg("%s: exited with status 255; aborting", args[0]); | ||
79 | return 124; | ||
80 | } | ||
81 | if (WIFSTOPPED(status)) { | ||
82 | bb_error_msg("%s: stopped by signal %d", | ||
83 | args[0], WSTOPSIG(status)); | ||
84 | return 125; | ||
85 | } | ||
86 | if (WIFSIGNALED(status)) { | ||
87 | bb_error_msg("%s: terminated by signal %d", | ||
88 | args[0], WTERMSIG(status)); | ||
89 | return 125; | ||
90 | } | ||
91 | if (WEXITSTATUS(status)) | ||
92 | return 123; | ||
93 | return 0; | ||
96 | } | 94 | } |
97 | 95 | ||
98 | 96 | ||
@@ -105,7 +103,7 @@ typedef struct xlist_s { | |||
105 | static int eof_stdin_detected; | 103 | static int eof_stdin_detected; |
106 | 104 | ||
107 | #define ISBLANK(c) ((c) == ' ' || (c) == '\t') | 105 | #define ISBLANK(c) ((c) == ' ' || (c) == '\t') |
108 | #define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \ | 106 | #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ |
109 | || (c) == '\f' || (c) == '\v') | 107 | || (c) == '\f' || (c) == '\v') |
110 | 108 | ||
111 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES | 109 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES |
@@ -304,19 +302,10 @@ static int xargs_ask_confirmation(void) | |||
304 | return 1; | 302 | return 1; |
305 | return 0; | 303 | return 0; |
306 | } | 304 | } |
307 | |||
308 | # define OPT_INC_P 1 | ||
309 | #else | 305 | #else |
310 | # define OPT_INC_P 0 | ||
311 | # define xargs_ask_confirmation() 1 | 306 | # define xargs_ask_confirmation() 1 |
312 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */ | 307 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */ |
313 | 308 | ||
314 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT | ||
315 | # define OPT_INC_X 1 | ||
316 | #else | ||
317 | # define OPT_INC_X 0 | ||
318 | #endif | ||
319 | |||
320 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | 309 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM |
321 | static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED, | 310 | static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED, |
322 | size_t mc, char *buf) | 311 | size_t mc, char *buf) |
@@ -371,35 +360,37 @@ static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE | |||
371 | } | 360 | } |
372 | return list_arg; | 361 | return list_arg; |
373 | } | 362 | } |
374 | |||
375 | # define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc) | ||
376 | # define OPT_INC_0 1 /* future use */ | ||
377 | #else | ||
378 | # define OPT_INC_0 0 /* future use */ | ||
379 | # define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc) | ||
380 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */ | 363 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */ |
381 | 364 | ||
382 | 365 | /* Correct regardless of combination of CONFIG_xxx */ | |
383 | #define OPT_VERBOSE (1<<0) | 366 | enum { |
384 | #define OPT_NO_EMPTY (1<<1) | 367 | OPTBIT_VERBOSE = 0, |
385 | #define OPT_UPTO_NUMBER (1<<2) | 368 | OPTBIT_NO_EMPTY, |
386 | #define OPT_UPTO_SIZE (1<<3) | 369 | OPTBIT_UPTO_NUMBER, |
387 | #define OPT_EOF_STRING (1<<4) | 370 | OPTBIT_UPTO_SIZE, |
388 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | 371 | OPTBIT_EOF_STRING, |
389 | #define OPT_INTERACTIVE (1<<5) | 372 | USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) |
390 | #else | 373 | USE_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) |
391 | #define OPT_INTERACTIVE (0) /* require for algorithm &| */ | 374 | USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) |
392 | #endif | 375 | |
393 | #define OPT_TERMINATE (1<<(5+OPT_INC_P)) | 376 | OPT_VERBOSE = 1<<OPTBIT_VERBOSE , |
394 | #define OPT_ZEROTERM (1<<(5+OPT_INC_P+OPT_INC_X)) | 377 | OPT_NO_EMPTY = 1<<OPTBIT_NO_EMPTY , |
395 | /* next future | 378 | OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER, |
396 | #define OPT_NEXT_OTHER (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0)) | 379 | OPT_UPTO_SIZE = 1<<OPTBIT_UPTO_SIZE , |
397 | */ | 380 | OPT_EOF_STRING = 1<<OPTBIT_EOF_STRING , |
381 | OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0, | ||
382 | OPT_TERMINATE = USE_FEATURE_XARGS_SUPPORT_TERMOPT( (1<<OPTBIT_TERMINATE )) + 0, | ||
383 | OPT_ZEROTERM = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1<<OPTBIT_ZEROTERM )) + 0, | ||
384 | }; | ||
385 | #define OPTION_STR "+trn:s:e::" \ | ||
386 | USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ | ||
387 | USE_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ | ||
388 | USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") | ||
398 | 389 | ||
399 | int xargs_main(int argc, char **argv) | 390 | int xargs_main(int argc, char **argv) |
400 | { | 391 | { |
401 | char **args; | 392 | char **args; |
402 | int i, a, n; | 393 | int i, n; |
403 | xlist_t *list = NULL; | 394 | xlist_t *list = NULL; |
404 | xlist_t *cur; | 395 | xlist_t *cur; |
405 | int child_error = 0; | 396 | int child_error = 0; |
@@ -410,42 +401,33 @@ int xargs_main(int argc, char **argv) | |||
410 | const char *eof_str = "_"; | 401 | const char *eof_str = "_"; |
411 | unsigned long opt; | 402 | unsigned long opt; |
412 | size_t n_max_chars; | 403 | size_t n_max_chars; |
413 | 404 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | |
414 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | 405 | xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin; |
415 | xlist_t *(*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin; | 406 | #else |
407 | #define read_args process_stdin | ||
416 | #endif | 408 | #endif |
417 | 409 | ||
418 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | 410 | opt = bb_getopt_ulflags(argc, argv, OPTION_STR, &max_args, &max_chars, &eof_str); |
419 | bb_opt_complementally = "pt"; | ||
420 | #endif | ||
421 | 411 | ||
422 | opt = bb_getopt_ulflags(argc, argv, "+trn:s:e::" | 412 | if (opt & OPT_ZEROTERM) |
423 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION | 413 | USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); |
424 | "p" | ||
425 | #endif | ||
426 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT | ||
427 | "x" | ||
428 | #endif | ||
429 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
430 | "0" | ||
431 | #endif | ||
432 | ,&max_args, &max_chars, &eof_str); | ||
433 | 414 | ||
434 | a = argc - optind; | 415 | argc -= optind; |
435 | argv += optind; | 416 | argv += optind; |
436 | if (a == 0) { | 417 | if (!argc) { |
437 | /* default behavior is to echo all the filenames */ | 418 | /* default behavior is to echo all the filenames */ |
438 | *argv = "echo"; | 419 | *argv = "echo"; |
439 | a++; | 420 | argc++; |
440 | } | 421 | } |
441 | 422 | ||
442 | orig_arg_max = ARG_MAX; | 423 | orig_arg_max = ARG_MAX; |
443 | if (orig_arg_max == -1) | 424 | if (orig_arg_max == -1) |
444 | orig_arg_max = LONG_MAX; | 425 | orig_arg_max = LONG_MAX; |
445 | orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */ | 426 | orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */ |
446 | if ((opt & OPT_UPTO_SIZE)) { | 427 | |
428 | if (opt & OPT_UPTO_SIZE) { | ||
447 | n_max_chars = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max); | 429 | n_max_chars = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max); |
448 | for (i = 0; i < a; i++) { | 430 | for (i = 0; i < argc; i++) { |
449 | n_chars += strlen(*argv) + 1; | 431 | n_chars += strlen(*argv) + 1; |
450 | } | 432 | } |
451 | if (n_max_chars < n_chars) { | 433 | if (n_max_chars < n_chars) { |
@@ -463,19 +445,14 @@ int xargs_main(int argc, char **argv) | |||
463 | } | 445 | } |
464 | max_chars = xmalloc(n_max_chars); | 446 | max_chars = xmalloc(n_max_chars); |
465 | 447 | ||
466 | if ((opt & OPT_UPTO_NUMBER)) { | 448 | if (opt & OPT_UPTO_NUMBER) { |
467 | n_max_arg = bb_xgetularg10_bnd(max_args, 1, INT_MAX); | 449 | n_max_arg = bb_xgetularg10_bnd(max_args, 1, INT_MAX); |
468 | } else { | 450 | } else { |
469 | n_max_arg = n_max_chars; | 451 | n_max_arg = n_max_chars; |
470 | } | 452 | } |
471 | 453 | ||
472 | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | 454 | while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || |
473 | if (opt & OPT_ZEROTERM) | 455 | !(opt & OPT_NO_EMPTY)) |
474 | read_args = process0_stdin; | ||
475 | #endif | ||
476 | |||
477 | while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL || | ||
478 | (opt & OPT_NO_EMPTY) == 0) | ||
479 | { | 456 | { |
480 | opt |= OPT_NO_EMPTY; | 457 | opt |= OPT_NO_EMPTY; |
481 | n = 0; | 458 | n = 0; |
@@ -501,13 +478,13 @@ int xargs_main(int argc, char **argv) | |||
501 | } | 478 | } |
502 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */ | 479 | #endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */ |
503 | 480 | ||
504 | /* allocating pointers for execvp: | 481 | /* allocate pointers for execvp: |
505 | a*arg, n*arg from stdin, NULL */ | 482 | argc*arg, n*arg from stdin, NULL */ |
506 | args = xzalloc((n + a + 1) * sizeof(char *)); | 483 | args = xzalloc((n + argc + 1) * sizeof(char *)); |
507 | 484 | ||
508 | /* Store the command to be executed | 485 | /* store the command to be executed |
509 | (taken from the command line) */ | 486 | (taken from the command line) */ |
510 | for (i = 0; i < a; i++) | 487 | for (i = 0; i < argc; i++) |
511 | args[i] = argv[i]; | 488 | args[i] = argv[i]; |
512 | /* (taken from stdin) */ | 489 | /* (taken from stdin) */ |
513 | for (cur = list; n; cur = cur->link) { | 490 | for (cur = list; n; cur = cur->link) { |
@@ -515,21 +492,21 @@ int xargs_main(int argc, char **argv) | |||
515 | n--; | 492 | n--; |
516 | } | 493 | } |
517 | 494 | ||
518 | if ((opt & (OPT_INTERACTIVE | OPT_VERBOSE))) { | 495 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { |
519 | for (i = 0; args[i]; i++) { | 496 | for (i = 0; args[i]; i++) { |
520 | if (i) | 497 | if (i) |
521 | fputc(' ', stderr); | 498 | fputc(' ', stderr); |
522 | fputs(args[i], stderr); | 499 | fputs(args[i], stderr); |
523 | } | 500 | } |
524 | if ((opt & OPT_INTERACTIVE) == 0) | 501 | if (!(opt & OPT_INTERACTIVE)) |
525 | fputc('\n', stderr); | 502 | fputc('\n', stderr); |
526 | } | 503 | } |
527 | if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) { | 504 | if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { |
528 | child_error = xargs_exec(args); | 505 | child_error = xargs_exec(args); |
529 | } | 506 | } |
530 | 507 | ||
531 | /* clean up */ | 508 | /* clean up */ |
532 | for (i = a; args[i]; i++) { | 509 | for (i = argc; args[i]; i++) { |
533 | cur = list; | 510 | cur = list; |
534 | list = list->link; | 511 | list = list->link; |
535 | free(cur); | 512 | free(cur); |
@@ -539,9 +516,7 @@ int xargs_main(int argc, char **argv) | |||
539 | break; | 516 | break; |
540 | } | 517 | } |
541 | } | 518 | } |
542 | #ifdef CONFIG_FEATURE_CLEAN_UP | 519 | if (ENABLE_FEATURE_CLEAN_UP) free(max_chars); |
543 | free(max_chars); | ||
544 | #endif | ||
545 | return child_error; | 520 | return child_error; |
546 | } | 521 | } |
547 | 522 | ||