[PATCH 2/2] find: implement 'find -exec ... {} +' option
walter harms
wharms at bfs.de
Thu Jun 12 08:05:52 UTC 2014
hi,
could you give a few word why you need that feature ?
btw:
Why you choose a linked list ? It seems more simple to make a strin for all
re,
wh
Am 11.06.2014 23:07, schrieb Bartosz Golaszewski:
> 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 <bartekgola at gmail.com>
> ---
> 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;
> }
More information about the busybox
mailing list