From 93cadc2fddbf8e640501dfd0ed0344119cb892ee Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 27 May 2009 17:06:25 -0400 Subject: hush: implement `type` Implement support for the POSIX `type` command. Only POSIX stuff is supported here, no bash extensions like -p or -P. In the process, split the $PATH searching code out of builtin_source() and into its own find_in_path() function so we don't duplicate it. Signed-off-by: Mike Frysinger --- shell/hush.c | 105 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 7167de701..efa93c1a6 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -539,6 +539,7 @@ static int builtin_shift(char **argv); static int builtin_source(char **argv); static int builtin_test(char **argv); static int builtin_trap(char **argv); +static int builtin_type(char **argv); static int builtin_true(char **argv); static int builtin_umask(char **argv); static int builtin_unset(char **argv); @@ -610,6 +611,7 @@ static const struct built_in_command bltins[] = { BLTIN("shift" , builtin_shift , "Shift positional parameters"), BLTIN("test" , builtin_test , "Test condition"), BLTIN("trap" , builtin_trap , "Trap signals"), + BLTIN("type" , builtin_type , "Write a description of command type"), // BLTIN("ulimit" , builtin_return , "Control resource limits"), BLTIN("umask" , builtin_umask , "Set file creation mask"), BLTIN("unset" , builtin_unset , "Unset environment variable"), @@ -2865,6 +2867,39 @@ static struct pipe *parse_stream(char **pstring, static void parse_and_run_string(const char *s); +static char *find_in_path(const char *arg) +{ + char *ret = NULL; + const char *PATH = get_local_var_value("PATH"); + + if (!PATH) + return NULL; + + while (1) { + const char *end = strchrnul(PATH, ':'); + int sz = end - PATH; /* must be int! */ + + free(ret); + if (sz != 0) { + ret = xasprintf("%.*s/%s", sz, PATH, arg); + } else { + /* We have xxx::yyyy in $PATH, + * it means "use current dir" */ + ret = xstrdup(arg); + } + if (access(ret, F_OK) == 0) + break; + + if (*end == '\0') { + free(ret); + return NULL; + } + PATH = end + 1; + } + + return ret; +} + static const struct built_in_command* find_builtin(const char *name) { const struct built_in_command *x; @@ -6728,6 +6763,43 @@ static int builtin_trap(char **argv) goto process_sig_list; } +/* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */ +static int builtin_type(char **argv) +{ + int i, ret = EXIT_SUCCESS; + + for (i = 1; argv[i]; ++i) { + void *path; + const void *find_ret; + const char *type; + + type = path = NULL; + + if (0) {} /* make conditional compile easier below */ + /*else if ((find_ret = find_alias(argv[i]))) + type = "an alias";*/ +#if ENABLE_HUSH_FUNCTIONS + else if ((find_ret = find_function(argv[i]))) + type = "a function"; +#endif + else if ((find_ret = find_builtin(argv[i]))) + type = "a shell builtin"; + else if ((find_ret = path = find_in_path(argv[i]))) + type = find_ret; + + if (!type) { + bb_error_msg("type: %s: not found", argv[i]); + ret = EXIT_FAILURE; + } else + printf("%s is %s\n", argv[i], type); + + if (path) + free(path); + } + + return ret; +} + #if ENABLE_HUSH_JOB /* built-in 'fg' and 'bg' handler */ static int builtin_fg_bg(char **argv) @@ -6986,7 +7058,7 @@ static int builtin_shift(char **argv) static int builtin_source(char **argv) { - const char *PATH; + char *arg_path; FILE *input; save_arg_t sv; #if ENABLE_HUSH_FUNCTIONS @@ -6996,36 +7068,15 @@ static int builtin_source(char **argv) if (*++argv == NULL) return EXIT_FAILURE; - if (strchr(*argv, '/') == NULL - && (PATH = get_local_var_value("PATH")) != NULL - ) { - /* Search through $PATH */ - while (1) { - const char *end = strchrnul(PATH, ':'); - int sz = end - PATH; /* must be int! */ - - if (sz != 0) { - char *tmp = xasprintf("%.*s/%s", sz, PATH, *argv); - input = fopen_for_read(tmp); - free(tmp); - } else { - /* We have xxx::yyyy in $PATH, - * it means "use current dir" */ - input = fopen_for_read(*argv); - } - if (input) - goto opened_ok; - if (*end == '\0') - break; - PATH = end + 1; - } - } - input = fopen_or_warn(*argv, "r"); + if (strchr(*argv, '/') == NULL && (arg_path = find_in_path(*argv)) != NULL) { + input = fopen_for_read(arg_path); + free(arg_path); + } else + input = fopen_or_warn(*argv, "r"); if (!input) { /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ return EXIT_FAILURE; } - opened_ok: close_on_exec_on(fileno(input)); #if ENABLE_HUSH_FUNCTIONS -- cgit v1.2.3