xargs: simplify option parsing
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -45,54 +45,52 @@ | |
| #endif | |
| /* | |
| - | This function have special algorithm. |
| - | Don`t use fork and include to main! |
| + | This function has special algorithm. |
| + | Don't use fork and include to main! |
| */ | |
| static int xargs_exec(char *const *args) | |
| { | |
| pid_t p; | |
| volatile int exec_errno = 0; /* shared vfork stack */ | |
| + | int status; |
| - | if ((p = vfork()) >= 0) { |
| - | if (p == 0) { |
| - | /* vfork -- child */ |
| - | execvp(args[0], args); |
| - | exec_errno = errno; /* set error to shared stack */ |
| - | _exit(1); |
| - | } else { |
| - | /* vfork -- parent */ |
| - | int status; |
| - | |
| - | while (wait(&status) == (pid_t) - 1) |
| - | if (errno != EINTR) |
| - | break; |
| - | if (exec_errno) { |
| - | errno = exec_errno; |
| - | bb_perror_msg("%s", args[0]); |
| - | return exec_errno == ENOENT ? 127 : 126; |
| - | } else { |
| - | if (WEXITSTATUS(status) == 255) { |
| - | bb_error_msg("%s: exited with status 255; aborting", args[0]); |
| - | return 124; |
| - | } |
| - | if (WIFSTOPPED(status)) { |
| - | bb_error_msg("%s: stopped by signal %d", |
| - | args[0], WSTOPSIG(status)); |
| - | return 125; |
| - | } |
| - | if (WIFSIGNALED(status)) { |
| - | bb_error_msg("%s: terminated by signal %d", |
| - | args[0], WTERMSIG(status)); |
| - | return 125; |
| - | } |
| - | if (WEXITSTATUS(status) != 0) |
| - | return 123; |
| - | return 0; |
| - | } |
| - | } |
| - | } else { |
| + | p = vfork(); |
| + | if (p < 0) |
| bb_perror_msg_and_die("vfork"); | |
| + | |
| + | if (p == 0) { |
| + | /* vfork -- child */ |
| + | execvp(args[0], args); |
| + | exec_errno = errno; /* set error to shared stack */ |
| + | _exit(1); |
| + | } |
| + | |
| + | /* vfork -- parent */ |
| + | while (wait(&status) == (pid_t) -1) |
| + | if (errno != EINTR) |
| + | break; |
| + | if (exec_errno) { |
| + | errno = exec_errno; |
| + | bb_perror_msg("%s", args[0]); |
| + | return exec_errno == ENOENT ? 127 : 126; |
| } | |
| + | if (WEXITSTATUS(status) == 255) { |
| + | bb_error_msg("%s: exited with status 255; aborting", args[0]); |
| + | return 124; |
| + | } |
| + | if (WIFSTOPPED(status)) { |
| + | bb_error_msg("%s: stopped by signal %d", |
| + | args[0], WSTOPSIG(status)); |
| + | return 125; |
| + | } |
| + | if (WIFSIGNALED(status)) { |
| + | bb_error_msg("%s: terminated by signal %d", |
| + | args[0], WTERMSIG(status)); |
| + | return 125; |
| + | } |
| + | if (WEXITSTATUS(status)) |
| + | return 123; |
| + | return 0; |
| } | |
| @@ -105,7 +103,7 @@ typedef struct xlist_s { | |
| static int eof_stdin_detected; | |
| #define ISBLANK(c) ((c) == ' ' || (c) == '\t') | |
| - | #define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \ |
| + | #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ |
| || (c) == '\f' || (c) == '\v') | |
| #ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES | |
| @@ -304,19 +302,10 @@ static int xargs_ask_confirmation(void) | |
| return 1; | |
| return 0; | |
| } | |
| - | |
| - | # define OPT_INC_P 1 |
| #else | |
| - | # define OPT_INC_P 0 |
| # define xargs_ask_confirmation() 1 | |
| #endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */ | |
| - | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT |
| - | # define OPT_INC_X 1 |
| - | #else |
| - | # define OPT_INC_X 0 |
| - | #endif |
| - | |
| #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM | |
| static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED, | |
| size_t mc, char *buf) | |
| @@ -371,35 +360,37 @@ static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE | |
| } | |
| return list_arg; | |
| } | |
| - | |
| - | # define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc) |
| - | # define OPT_INC_0 1 /* future use */ |
| - | #else |
| - | # define OPT_INC_0 0 /* future use */ |
| - | # define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc) |
| #endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */ | |
| - | |
| - | #define OPT_VERBOSE (1<<0) |
| - | #define OPT_NO_EMPTY (1<<1) |
| - | #define OPT_UPTO_NUMBER (1<<2) |
| - | #define OPT_UPTO_SIZE (1<<3) |
| - | #define OPT_EOF_STRING (1<<4) |
| - | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION |
| - | #define OPT_INTERACTIVE (1<<5) |
| - | #else |
| - | #define OPT_INTERACTIVE (0) /* require for algorithm &| */ |
| - | #endif |
| - | #define OPT_TERMINATE (1<<(5+OPT_INC_P)) |
| - | #define OPT_ZEROTERM (1<<(5+OPT_INC_P+OPT_INC_X)) |
| - | /* next future |
| - | #define OPT_NEXT_OTHER (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0)) |
| - | */ |
| + | /* Correct regardless of combination of CONFIG_xxx */ |
| + | enum { |
| + | OPTBIT_VERBOSE = 0, |
| + | OPTBIT_NO_EMPTY, |
| + | OPTBIT_UPTO_NUMBER, |
| + | OPTBIT_UPTO_SIZE, |
| + | OPTBIT_EOF_STRING, |
| + | USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) |
| + | USE_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) |
| + | USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) |
| + | |
| + | OPT_VERBOSE = 1<<OPTBIT_VERBOSE , |
| + | OPT_NO_EMPTY = 1<<OPTBIT_NO_EMPTY , |
| + | OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER, |
| + | OPT_UPTO_SIZE = 1<<OPTBIT_UPTO_SIZE , |
| + | OPT_EOF_STRING = 1<<OPTBIT_EOF_STRING , |
| + | OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0, |
| + | OPT_TERMINATE = USE_FEATURE_XARGS_SUPPORT_TERMOPT( (1<<OPTBIT_TERMINATE )) + 0, |
| + | OPT_ZEROTERM = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1<<OPTBIT_ZEROTERM )) + 0, |
| + | }; |
| + | #define OPTION_STR "+trn:s:e::" \ |
| + | USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ |
| + | USE_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ |
| + | USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") |
| int xargs_main(int argc, char **argv) | |
| { | |
| char **args; | |
| - | int i, a, n; |
| + | int i, n; |
| xlist_t *list = NULL; | |
| xlist_t *cur; | |
| int child_error = 0; | |
| @@ -410,42 +401,33 @@ int xargs_main(int argc, char **argv) | |
| 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; |
| + | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM |
| + | xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin; |
| + | #else |
| + | #define read_args process_stdin |
| #endif | |
| - | #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION |
| - | bb_opt_complementally = "pt"; |
| - | #endif |
| + | opt = bb_getopt_ulflags(argc, argv, OPTION_STR, &max_args, &max_chars, &eof_str); |
| - | 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); |
| + | if (opt & OPT_ZEROTERM) |
| + | USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); |
| - | a = argc - optind; |
| + | argc -= optind; |
| argv += optind; | |
| - | if (a == 0) { |
| + | if (!argc) { |
| /* default behavior is to echo all the filenames */ | |
| *argv = "echo"; | |
| - | a++; |
| + | argc++; |
| } | |
| 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)) { |
| + | 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++) { |
| + | for (i = 0; i < argc; i++) { |
| n_chars += strlen(*argv) + 1; | |
| } | |
| if (n_max_chars < n_chars) { | |
| @@ -463,19 +445,14 @@ int xargs_main(int argc, char **argv) | |
| } | |
| max_chars = xmalloc(n_max_chars); | |
| - | if ((opt & OPT_UPTO_NUMBER)) { |
| + | 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) |
| + | while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || |
| + | !(opt & OPT_NO_EMPTY)) |
| { | |
| opt |= OPT_NO_EMPTY; | |
| n = 0; | |
| @@ -501,13 +478,13 @@ int xargs_main(int argc, char **argv) | |
| } | |
| #endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */ | |
| - | /* allocating pointers for execvp: |
| - | a*arg, n*arg from stdin, NULL */ |
| - | args = xzalloc((n + a + 1) * sizeof(char *)); |
| + | /* allocate pointers for execvp: |
| + | argc*arg, n*arg from stdin, NULL */ |
| + | args = xzalloc((n + argc + 1) * sizeof(char *)); |
| - | /* Store the command to be executed |
| + | /* store the command to be executed |
| (taken from the command line) */ | |
| - | for (i = 0; i < a; i++) |
| + | for (i = 0; i < argc; i++) |
| args[i] = argv[i]; | |
| /* (taken from stdin) */ | |
| for (cur = list; n; cur = cur->link) { | |
| @@ -515,21 +492,21 @@ int xargs_main(int argc, char **argv) | |
| n--; | |
| } | |
| - | if ((opt & (OPT_INTERACTIVE | OPT_VERBOSE))) { |
| + | 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) |
| + | if (!(opt & OPT_INTERACTIVE)) |
| fputc('\n', stderr); | |
| } | |
| - | if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) { |
| + | if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { |
| child_error = xargs_exec(args); | |
| } | |
| /* clean up */ | |
| - | for (i = a; args[i]; i++) { |
| + | for (i = argc; args[i]; i++) { |
| cur = list; | |
| list = list->link; | |
| free(cur); | |
| @@ -539,9 +516,7 @@ int xargs_main(int argc, char **argv) | |
| break; | |
| } | |
| } | |
| - | #ifdef CONFIG_FEATURE_CLEAN_UP |
| - | free(max_chars); |
| - | #endif |
| + | if (ENABLE_FEATURE_CLEAN_UP) free(max_chars); |
| return child_error; | |
| } | |
| @@ -91,6 +91,7 @@ const struct option *bb_applet_long_options | |
| is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. | |
| const char *bb_opt_complementally | |
| + | |
| this should be bb_opt_complementary, but we'll just keep it as | |
| bb_opt_complementally due to the Russian origins | |