[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