aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-01-12 14:41:45 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-01-12 14:41:45 +0100
commit5700029c65f2218b5fceca77a9140aff6d882aab (patch)
tree39c98b5ad7a7b0eab4ec18e4111b8b6677066f19
parentcca7c611f26d98415c0f986e5a5e731ab5e379ff (diff)
downloadbusybox-w32-5700029c65f2218b5fceca77a9140aff6d882aab.tar.gz
busybox-w32-5700029c65f2218b5fceca77a9140aff6d882aab.tar.bz2
busybox-w32-5700029c65f2218b5fceca77a9140aff6d882aab.zip
hush: implement "command -v -V"
function old new delta pseudo_exec_argv 231 374 +143 if_command_vV_print_and_exit - 127 +127 builtin_set 267 273 +6 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 276/0) Total: 276 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c115
1 files changed, 84 insertions, 31 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 93779ba1e..196bdbe97 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -47,18 +47,13 @@
47 * follow IFS rules more precisely, including update semantics 47 * follow IFS rules more precisely, including update semantics
48 * tilde expansion 48 * tilde expansion
49 * aliases 49 * aliases
50 * builtins mandated by standards we don't support: 50 * "command" missing features:
51 * [un]alias, command, fc: 51 * command -p CMD: run CMD using default $PATH
52 * command -v CMD: print "/path/to/CMD" 52 * (can use this to override standalone shell as well?)
53 * prints "CMD" for builtins
54 * prints "alias ALIAS='EXPANSION'" for aliases
55 * prints nothing and sets $? to 1 if not found
56 * command -V CMD: print "CMD is /path/CMD|a shell builtin|etc"
57 * command [-p] CMD: run CMD, even if a function CMD also exists
58 * (can use this to override standalone shell as well)
59 * -p: use default $PATH
60 * command BLTIN: disables special-ness (e.g. errors do not abort) 53 * command BLTIN: disables special-ness (e.g. errors do not abort)
61 * NB: so far, only naked "command CMD" is implemented. 54 * command -V CMD1 CMD2 CMD3 (multiple args) (not in standard)
55 * builtins mandated by standards we don't support:
56 * [un]alias, fc:
62 * fc -l[nr] [BEG] [END]: list range of commands in history 57 * fc -l[nr] [BEG] [END]: list range of commands in history
63 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands 58 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands
64 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP 59 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP
@@ -7337,6 +7332,30 @@ static void dump_cmd_in_x_mode(char **argv)
7337# define dump_cmd_in_x_mode(argv) ((void)0) 7332# define dump_cmd_in_x_mode(argv) ((void)0)
7338#endif 7333#endif
7339 7334
7335#if ENABLE_HUSH_COMMAND
7336static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *explanation)
7337{
7338 char *to_free;
7339 if (!opt_vV)
7340 return;
7341
7342 to_free = NULL;
7343 if (!explanation) {
7344 char *path = getenv("PATH");
7345 explanation = to_free = find_executable(cmd, &path); /* path == NULL is ok */
7346 if (opt_vV != 'V')
7347 cmd = to_free; /* -v PROG prints "/path/to/PROG" */
7348 }
7349 if (explanation)
7350 printf((opt_vV == 'V') ? "%s is %s\n" : "%s\n", cmd, explanation);
7351 free(to_free);
7352 fflush_all();
7353 _exit(explanation == NULL); /* exit 1 if PROG was not found */
7354}
7355#else
7356# define if_command_vV_print_and_exit(a,b,c) ((void)0)
7357#endif
7358
7340#if BB_MMU 7359#if BB_MMU
7341#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ 7360#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
7342 pseudo_exec_argv(argv, assignment_cnt, argv_expanded) 7361 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
@@ -7357,7 +7376,11 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7357 char **argv, int assignment_cnt, 7376 char **argv, int assignment_cnt,
7358 char **argv_expanded) 7377 char **argv_expanded)
7359{ 7378{
7379 const struct built_in_command *x;
7360 char **new_env; 7380 char **new_env;
7381#if ENABLE_HUSH_COMMAND
7382 char opt_vV = 0;
7383#endif
7361 7384
7362 new_env = expand_assignments(argv, assignment_cnt); 7385 new_env = expand_assignments(argv, assignment_cnt);
7363 dump_cmd_in_x_mode(new_env); 7386 dump_cmd_in_x_mode(new_env);
@@ -7406,30 +7429,58 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7406 } 7429 }
7407#endif 7430#endif
7408 7431
7432#if ENABLE_HUSH_COMMAND
7433 /* "command BAR": run BAR without looking it up among functions
7434 * "command -v BAR": print "BAR" or "/path/to/BAR"; or exit 1
7435 * "command -V BAR": print "BAR is {a function,a shell builtin,/path/to/BAR}"
7436 */
7437 while (strcmp(argv[0], "command") == 0 && argv[1]) {
7438 char *p;
7439
7440 argv++;
7441 p = *argv;
7442 if (p[0] != '-' || !p[1])
7443 continue; /* bash allows "command command command [-OPT] BAR" */
7444
7445 for (;;) {
7446 p++;
7447 switch (*p) {
7448 case '\0':
7449 argv++;
7450 p = *argv;
7451 if (p[0] != '-' || !p[1])
7452 goto after_opts;
7453 continue; /* next arg is also -opts, process it too */
7454 case 'v':
7455 case 'V':
7456 opt_vV = *p;
7457 continue;
7458 default:
7459 bb_error_msg_and_die("%s: %s: invalid option", "command", argv[0]);
7460 }
7461 }
7462 }
7463 after_opts:
7464# if ENABLE_HUSH_FUNCTIONS
7465 if (opt_vV && find_function(argv[0]))
7466 if_command_vV_print_and_exit(opt_vV, argv[0], "a function");
7467# endif
7468#endif
7469
7409 /* Check if the command matches any of the builtins. 7470 /* Check if the command matches any of the builtins.
7410 * Depending on context, this might be redundant. But it's 7471 * Depending on context, this might be redundant. But it's
7411 * easier to waste a few CPU cycles than it is to figure out 7472 * easier to waste a few CPU cycles than it is to figure out
7412 * if this is one of those cases. 7473 * if this is one of those cases.
7413 */ 7474 */
7414 { 7475 /* Why "BB_MMU ? :" difference in logic? -
7415 const struct built_in_command *x; 7476 * On NOMMU, it is more expensive to re-execute shell
7416 7477 * just in order to run echo or test builtin.
7417#if ENABLE_HUSH_COMMAND 7478 * It's better to skip it here and run corresponding
7418 /* This loop effectively makes "command BAR" run BAR without 7479 * non-builtin later. */
7419 * looking it up among functions. 7480 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]);
7420 */ 7481 if (x) {
7421 while (strcmp(argv[0], "command") == 0 && argv[1]) 7482 if_command_vV_print_and_exit(opt_vV, argv[0], "a shell builtin");
7422 argv++; 7483 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
7423//TODO: implement -Vvp and "disable dying if BAR is a builtin" behavior
7424#endif
7425 /* On NOMMU, it is more expensive to re-execute shell
7426 * just in order to run echo or test builtin.
7427 * It's better to skip it here and run corresponding
7428 * non-builtin later. */
7429 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]);
7430 if (x) {
7431 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
7432 }
7433 } 7484 }
7434 7485
7435#if ENABLE_FEATURE_SH_STANDALONE 7486#if ENABLE_FEATURE_SH_STANDALONE
@@ -7437,6 +7488,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7437 { 7488 {
7438 int a = find_applet_by_name(argv[0]); 7489 int a = find_applet_by_name(argv[0]);
7439 if (a >= 0) { 7490 if (a >= 0) {
7491 if_command_vV_print_and_exit(opt_vV, argv[0], "an applet");
7440# if BB_MMU /* see above why on NOMMU it is not allowed */ 7492# if BB_MMU /* see above why on NOMMU it is not allowed */
7441 if (APPLET_IS_NOEXEC(a)) { 7493 if (APPLET_IS_NOEXEC(a)) {
7442 /* Do not leak open fds from opened script files etc. 7494 /* Do not leak open fds from opened script files etc.
@@ -7466,6 +7518,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7466#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU 7518#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
7467 skip: 7519 skip:
7468#endif 7520#endif
7521 if_command_vV_print_and_exit(opt_vV, argv[0], NULL);
7469 execvp_or_die(argv); 7522 execvp_or_die(argv);
7470} 7523}
7471 7524
@@ -9895,7 +9948,7 @@ static int FAST_FUNC builtin_set(char **argv)
9895 9948
9896 /* Nothing known, so abort */ 9949 /* Nothing known, so abort */
9897 error: 9950 error:
9898 bb_error_msg("set: %s: invalid option", arg); 9951 bb_error_msg("%s: %s: invalid option", "set", arg);
9899 return EXIT_FAILURE; 9952 return EXIT_FAILURE;
9900} 9953}
9901#endif 9954#endif