This patch implements the missing feature in find. It's configurable and doesn't add any bloat when configured out.
With new feature compiled: function old new delta scheduled_exec - 237 +237 parse_params 1561 1647 +86 .rodata 150765 150842 +77 func_exec 187 235 +48 packed_usage 29441 29484 +43 llist_size - 16 +16 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 4/0 up/down: 507/0) Total: 507 bytes text data bss dec hex filename 815295 4123 9504 828922 ca5fa busybox_old 815759 4123 9504 829386 ca7ca busybox_unstripped without it: function old new delta parse_params 1561 1556 -5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-5) Total: -5 bytes text data bss dec hex filename 815295 4123 9504 828922 ca5fa busybox_old 815290 4123 9504 828917 ca5f5 busybox_unstripped Signed-off-by: Bartosz Golaszewski <[email protected]> --- findutils/find.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 112 insertions(+), 20 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index 6d34f4d..fa24dea 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -137,6 +137,14 @@ //config: Support the 'find -exec' option for executing commands based upon //config: the files matched. //config: +//config:config FEATURE_FIND_EXEC_PLUS +//config: bool "Enable -exec ... {} +" +//config: default y +//config: depends on FEATURE_FIND_EXEC +//config: help +//config: Support the 'find -exec ... {} +' option for executing commands +//config: for all matched files at once. +//config: //config:config FEATURE_FIND_USER //config: bool "Enable -user: username/uid matching" //config: default y @@ -319,6 +327,10 @@ //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" //usage: "\n file name. Fails if CMD exits with nonzero" //usage: ) +//usage: IF_FEATURE_FIND_EXEC_PLUS( +//usage: "\n -exec CMD ARG + Same as above except that all file names are appended" +//usage: "\n at the end of the exec action" +//usage: ) //usage: IF_FEATURE_FIND_DELETE( //usage: "\n -delete Delete current file/directory. Turns on -depth option" //usage: ) @@ -375,7 +387,12 @@ IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) IF_FEATURE_FIND_PRUNE( ACTS(prune)) IF_FEATURE_FIND_DELETE( ACTS(delete)) -IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) +IF_FEATURE_FIND_EXEC( ACTS(exec, + char **exec_argv; + unsigned *subst_count; + int exec_argc; + IF_FEATURE_FIND_EXEC_PLUS(int all_at_once;) + )) IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) @@ -389,6 +406,10 @@ struct globals { smallint need_print; smallint xdev_on; recurse_flags_t recurse_flags; +#if ENABLE_FEATURE_FIND_EXEC_PLUS + llist_t *exec_all_acts; + llist_t *found_files; +#endif } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ @@ -452,6 +473,48 @@ static int exec_actions(action ***appp, const char *fileName, const struct stat return rc ^ TRUE; /* restore TRUE bit */ } +#if ENABLE_FEATURE_FIND_EXEC_PLUS +static int scheduled_exec(void) +{ + /* Execute all scheduled '-exec +' actions. Expect + * the {} to be at the end of the command. + */ + llist_t *actlist = G.exec_all_acts; + int rc = 0; + + while (actlist) { + action_exec *ap; + llist_t *filelist; + size_t num_files; + char **argv; + int i; + + ap = (action_exec*)actlist->data; + filelist = G.found_files; + num_files = llist_size(filelist); + if (num_files == 0) + return 0; + + argv = alloca((ap->exec_argc + num_files) * sizeof(char*)); + for (i = 0; i < (ap->exec_argc - 1); i++) + argv[i] = ap->exec_argv[i]; + while (filelist) { + argv[i++] = filelist->data; + filelist = filelist->link; + } + argv[i] = NULL; + + rc = spawn_and_wait(argv); + if (rc < 0) + bb_simple_perror_msg(argv[0]); + + actlist = actlist->link; + } + + /* Return 1 if spawn_and_wait() failed. */ + return rc != 0; +} +#endif /* ENABLE_FEATURE_FIND_EXEC_PLUS */ #if !FNM_CASEFOLD static char *strcpy_upcase(char *dst, const char *src) @@ -578,24 +641,33 @@ ACTF(inum) #if ENABLE_FEATURE_FIND_EXEC ACTF(exec) { - int i, rc; +#if ENABLE_FEATURE_FIND_EXEC_PLUS + if (ap->all_at_once) { + llist_add_to_end(&G.found_files, xstrdup(fileName)); + return 0; + } else { +#endif /* ENABLE_FEATURE_FIND_EXEC_PLUS */ + int i, rc; #if ENABLE_USE_PORTABLE_CODE - char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1)); + char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1)); #else /* gcc 4.3.1 generates smaller code: */ - char *argv[ap->exec_argc + 1]; + char *argv[ap->exec_argc + 1]; #endif - for (i = 0; i < ap->exec_argc; i++) - argv[i] = xmalloc_substitute_string(ap->exec_argv[i], ap->subst_count[i], "{}", fileName); - argv[i] = NULL; /* terminate the list */ + for (i = 0; i < ap->exec_argc; i++) + argv[i] = xmalloc_substitute_string(ap->exec_argv[i], ap->subst_count[i], "{}", fileName); + argv[i] = NULL; /* terminate the list */ - rc = spawn_and_wait(argv); - if (rc < 0) - bb_simple_perror_msg(argv[0]); + rc = spawn_and_wait(argv); + if (rc < 0) + bb_simple_perror_msg(argv[0]); - i = 0; - while (argv[i]) - free(argv[i++]); - return rc == 0; /* return 1 if exitcode 0 */ + i = 0; + while (argv[i]) + free(argv[i++]); + return rc == 0; /* return 1 if exitcode 0 */ +#if ENABLE_FEATURE_FIND_EXEC_PLUS + } +#endif /* ENABLE_FEATURE_FIND_EXEC_PLUS */ } #endif #if ENABLE_FEATURE_FIND_USER @@ -1037,6 +1109,7 @@ static action*** parse_params(char **argv) else if (parm == PARM_exec) { int i; action_exec *ap; + IF_FEATURE_FIND_EXEC_PLUS(int all_subst = 0;) dbg("%d", __LINE__); G.need_print = 0; ap = ALLOC_ACTION(exec); @@ -1049,10 +1122,11 @@ static action*** parse_params(char **argv) // executes "echo Foo >FILENAME<", // find -exec echo Foo ">{}<" "+" // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". - // TODO (so far we treat "+" just like ";") - if ((argv[0][0] == ';' || argv[0][0] == '+') - && argv[0][1] == '\0' - ) { + if ((argv[0][0] == ';' + IF_FEATURE_FIND_EXEC_PLUS(|| argv[0][0] == '+') + ) && argv[0][1] == '\0' ) { + IF_FEATURE_FIND_EXEC_PLUS( + ap->all_at_once = (argv[0][0] == '+' ? 1 : 0);) break; } argv++; @@ -1062,8 +1136,22 @@ static action*** parse_params(char **argv) bb_error_msg_and_die(bb_msg_requires_arg, arg); ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); i = ap->exec_argc; - while (i--) - ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}"); + while (i--) { + IF_FEATURE_FIND_EXEC_PLUS(all_subst +=) + ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}"); + } +#if ENABLE_FEATURE_FIND_EXEC_PLUS + /* coreutils expects {} to apear only once at the end of the + * '-exec +' command. + */ + if (ap->all_at_once && all_subst > 1) + bb_error_msg_and_die("only one '{}' allowed for -exec +"); + if (ap->subst_count[ap->exec_argc-1] != 1) + bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); + /* Schedule execution of '-exec +' for later. */ + if (ap->all_at_once) + llist_add_to_end(&G.exec_all_acts, ap); +#endif /* ENABLE_FEATURE_FIND_EXEC_PLUS */ } #endif #if ENABLE_FEATURE_FIND_PAREN @@ -1335,8 +1423,12 @@ int find_main(int argc UNUSED_PARAM, char **argv) 0) /* depth */ ) { status = EXIT_FAILURE; + goto out; } } + IF_FEATURE_FIND_EXEC_PLUS(status = scheduled_exec();) + +out: return status; } -- 1.9.1 _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
