diff options
-rw-r--r-- | debianutils/which.c | 64 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/execable.c | 27 |
3 files changed, 70 insertions, 23 deletions
diff --git a/debianutils/which.c b/debianutils/which.c index 5ab67194d..41a864cfa 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -13,30 +13,69 @@ #include "libbb.h" int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int which_main(int argc, char **argv) +int which_main(int argc ATTRIBUTE_UNUSED, char **argv) { + USE_DESKTOP(int opt;) int status = EXIT_SUCCESS; + char *path; char *p; - if (argc <= 1 || argv[1][0] == '-') { - bb_show_usage(); - } + opt_complementary = "-1"; /* at least one argument */ + USE_DESKTOP(opt =) getopt32(argv, "a"); + argv += optind; - /* This matches what is seen on e.g. ubuntu - * "which" there is a shell script */ - if (!getenv("PATH")) { - putenv((char*)bb_PATH_root_path); + /* This matches what is seen on e.g. ubuntu. + * "which" there is a shell script. */ + path = getenv("PATH"); + if (!path) { + path = (char*)bb_PATH_root_path; + putenv(path); + path += 5; /* skip "PATH=" */ } - while (--argc > 0) { - argv++; + do { +#if ENABLE_DESKTOP +/* Much bloat just to support -a */ if (strchr(*argv, '/')) { if (execable_file(*argv)) { puts(*argv); continue; } + status = EXIT_FAILURE; } else { - p = find_execable(*argv); + char *path2 = xstrdup(path); + char *tmp = path2; + + p = find_execable(*argv, &tmp); + if (!p) + status = EXIT_FAILURE; + else { + print: + puts(p); + free(p); + if (opt) { + /* -a: show matches in all PATH components */ + if (tmp) { + p = find_execable(*argv, &tmp); + if (p) + goto print; + } + } + } + free(path2); + } +#else +/* Just ignoring -a */ + if (strchr(*argv, '/')) { + if (execable_file(*argv)) { + puts(*argv); + continue; + } + } else { + char *path2 = xstrdup(path); + char *tmp = path2; + p = find_execable(*argv, &tmp); + free(path2); if (p) { puts(p); free(p); @@ -44,7 +83,8 @@ int which_main(int argc, char **argv) } } status = EXIT_FAILURE; - } +#endif + } while (*(++argv) != NULL); fflush_stdout_and_exit(status); } diff --git a/include/libbb.h b/include/libbb.h index 492a561a9..1e4968bfa 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -700,7 +700,7 @@ void die_if_bad_username(const char* name); #endif int execable_file(const char *name); -char *find_execable(const char *filename); +char *find_execable(const char *filename, char **PATHp); int exists_execable(const char *filename); /* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff), diff --git a/libbb/execable.c b/libbb/execable.c index 2649a6cfe..5c2b4505c 100644 --- a/libbb/execable.c +++ b/libbb/execable.c @@ -19,15 +19,20 @@ int execable_file(const char *name) return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode)); } -/* search $PATH for an executable file; +/* search (*PATHp) for an executable file; * return allocated string containing full path if found; - * return NULL otherwise; + * PATHp points to the component after the one where it was found + * (or NULL), + * you may call find_execable again with this PATHp to continue + * (if it's not NULL). + * return NULL otherwise; (PATHp is undefined) + * in all cases (*PATHp) contents will be trashed (s/:/NUL/). */ -char *find_execable(const char *filename) +char *find_execable(const char *filename, char **PATHp) { - char *path, *p, *n; + char *p, *n; - p = path = xstrdup(getenv("PATH")); + p = *PATHp; while (p) { n = strchr(p, ':'); if (n) @@ -35,15 +40,14 @@ char *find_execable(const char *filename) if (*p != '\0') { /* it's not a PATH="foo::bar" situation */ p = concat_path_file(p, filename); if (execable_file(p)) { - free(path); + *PATHp = n; return p; } free(p); } p = n; - } - free(path); - return NULL; + } /* on loop exit p == NULL */ + return p; } /* search $PATH for an executable file; @@ -52,7 +56,10 @@ char *find_execable(const char *filename) */ int exists_execable(const char *filename) { - char *ret = find_execable(filename); + char *path = xstrdup(getenv("PATH")); + char *tmp = path; + char *ret = find_execable(filename, &tmp); + free(path); if (ret) { free(ret); return 1; |