Browse Source

find: implement -ok

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html

  -ok  utility_name  [argument ...] ;
    The -ok primary shall be equivalent to -exec, except that the use
    of a <plus-sign> to punctuate the end of the primary expression
    need not be supported, and find shall request affirmation of the
    invocation of utility_name using the current file as an argument
    by writing to standard error as described in the STDERR section. If
    the response on standard input is affirmative, the utility shall be
    invoked. Otherwise, the command shall not be invoked and the value
    of the -ok operand shall be false.

function                                             old     new   delta
do_exec                                              438     517     +79
parse_params                                        1833    1845     +12
static.params                                        288     292      +4
.rodata                                           100771  100775      +4
packed_usage                                       34543   34541      -2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/1 up/down: 99/-2)              Total: 97 bytes

Signed-off-by: David Leonard <d+busybox@adaptive-enterprises.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
David Leonard 1 year ago
parent
commit
d8a3360380
2 changed files with 42 additions and 3 deletions
  1. 36 3
      findutils/find.c
  2. 6 0
      testsuite/find.tests

+ 36 - 3
findutils/find.c

@@ -180,6 +180,13 @@
 //config:	Without this option, -exec + is a synonym for -exec ;
 //config:	(IOW: it works correctly, but without expected speedup)
 //config:
+//config:config FEATURE_FIND_EXEC_OK
+//config:	bool "Enable -ok: execute confirmed commands"
+//config:	default y
+//config:	depends on FEATURE_FIND_EXEC
+//config:	help
+//config:	Support the 'find -ok' option which prompts before executing.
+//config:
 //config:config FEATURE_FIND_USER
 //config:	bool "Enable -user: username/uid matching"
 //config:	default y
@@ -395,6 +402,9 @@
 //usage:	IF_FEATURE_FIND_EXEC_PLUS(
 //usage:     "\n	-exec CMD ARG + Run CMD with {} replaced by list of file names"
 //usage:	)
+//usage:	IF_FEATURE_FIND_EXEC_OK(
+//usage:     "\n	-ok CMD ARG ;   Prompt and run CMD with {} replaced"
+//usage:	)
 //usage:	IF_FEATURE_FIND_DELETE(
 //usage:     "\n	-delete		Delete current file/directory. Turns on -depth option"
 //usage:	)
@@ -467,6 +477,9 @@ IF_FEATURE_FIND_EXEC(   ACTS(exec,
 				char **exec_argv; /* -exec ARGS */
 				unsigned *subst_count;
 				int exec_argc; /* count of ARGS */
+				IF_FEATURE_FIND_EXEC_OK(
+				int ok;		/* -ok */
+				)
 				IF_FEATURE_FIND_EXEC_PLUS(
 					/*
 					 * filelist is NULL if "exec ;"
@@ -802,10 +815,24 @@ static int do_exec(action_exec *ap, const char *fileName)
 	}
 # endif
 
+# if ENABLE_FEATURE_FIND_EXEC_OK
+	if (ap->ok) {
+		for (i = 0; argv[i]; i++)
+			fprintf(stderr, "%s ", argv[i]);
+		fprintf(stderr, "?");
+		if (!bb_ask_y_confirmation()) {
+			rc = 1; /* "false" */
+			goto not_ok;
+		}
+	}
+# endif
 	rc = spawn_and_wait(argv);
 	if (rc < 0)
 		bb_simple_perror_msg(argv[0]);
 
+# if ENABLE_FEATURE_FIND_EXEC_OK
+    not_ok:
+# endif
 	i = 0;
 	while (argv[i])
 		free(argv[i++]);
@@ -1120,6 +1147,7 @@ static action*** parse_params(char **argv)
 	IF_FEATURE_FIND_DELETE( PARM_delete    ,)
 	IF_FEATURE_FIND_EMPTY(	PARM_empty     ,)
 	IF_FEATURE_FIND_EXEC(   PARM_exec      ,)
+	IF_FEATURE_FIND_EXEC_OK(PARM_ok        ,)
 	IF_FEATURE_FIND_EXECUTABLE(PARM_executable,)
 	IF_FEATURE_FIND_PAREN(  PARM_char_brace,)
 	/* All options/actions starting from here require argument */
@@ -1171,6 +1199,7 @@ static action*** parse_params(char **argv)
 	IF_FEATURE_FIND_DELETE( "-delete\0" )
 	IF_FEATURE_FIND_EMPTY(	"-empty\0"  )
 	IF_FEATURE_FIND_EXEC(   "-exec\0"   )
+	IF_FEATURE_FIND_EXEC_OK("-ok\0"     )
 	IF_FEATURE_FIND_EXECUTABLE("-executable\0")
 	IF_FEATURE_FIND_PAREN(  "(\0"       )
 	/* All options/actions starting from here require argument */
@@ -1351,23 +1380,27 @@ static action*** parse_params(char **argv)
 		}
 #endif
 #if ENABLE_FEATURE_FIND_EXEC
-		else if (parm == PARM_exec) {
+		else if (parm == PARM_exec IF_FEATURE_FIND_EXEC_OK(|| parm == PARM_ok)) {
 			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);
+			IF_FEATURE_FIND_EXEC_OK(ap->ok = (parm == PARM_ok);)
 			ap->exec_argv = ++argv; /* first arg after -exec */
 			/*ap->exec_argc = 0; - ALLOC_ACTION did it */
 			while (1) {
 				if (!*argv) /* did not see ';' or '+' until end */
-					bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
+					bb_error_msg_and_die(bb_msg_requires_arg, arg);
 				// find -exec echo Foo ">{}<" ";"
 				// executes "echo Foo >FILENAME<",
 				// find -exec echo Foo ">{}<" "+"
 				// executes "echo Foo FILENAME1 FILENAME2 FILENAME3...".
-				if ((argv[0][0] == ';' || argv[0][0] == '+')
+				if ((argv[0][0] == ';'
+				     || (argv[0][0] == '+' IF_FEATURE_FIND_EXEC_OK(&& parm != PARM_ok))
+						/* -ok CMD + syntax is not accepted, only with ';' */
+				    )
 				 && argv[0][1] == '\0'
 				) {
 # if ENABLE_FEATURE_FIND_EXEC_PLUS

+ 6 - 0
testsuite/find.tests

@@ -28,6 +28,12 @@ testing "find -exec exitcode 2" \
 	"0\n" \
 	"" ""
 SKIP=
+optional FEATURE_FIND_EXEC_OK
+testing "find -ok" \
+	"cd find.tempdir && find testfile -ok true {} ';' 2>&1; echo \$?" \
+	"true testfile ?0\n" \
+	"" "y"
+SKIP=
 # Surprisingly, "-exec false ;" results in exitcode 0! "-exec false +" is different!!!
 optional FEATURE_FIND_EXEC
 testing "find -exec exitcode 3" \