diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2024-10-08 04:03:17 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2024-10-08 04:03:17 +0200 |
| commit | 49d9e06fbab0b02a71deed57610edb0c8f4fb20c (patch) | |
| tree | 6b5263bcdb0972eaf17f35dbb8c2ce65d13a790e | |
| parent | 8c4bccb83e5e2594f16310b7cbe07bf05fc9f13a (diff) | |
| download | busybox-w32-49d9e06fbab0b02a71deed57610edb0c8f4fb20c.tar.gz busybox-w32-49d9e06fbab0b02a71deed57610edb0c8f4fb20c.tar.bz2 busybox-w32-49d9e06fbab0b02a71deed57610edb0c8f4fb20c.zip | |
libbb: modify find_executable() to not temporarily write to PATH
This allows to simplify "which" applet code
function old new delta
find_executable 93 111 +18
which_main 191 177 -14
builtin_source 316 294 -22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 18/-36) Total: -18 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | debianutils/which.c | 9 | ||||
| -rw-r--r-- | include/libbb.h | 2 | ||||
| -rw-r--r-- | libbb/executable.c | 56 | ||||
| -rw-r--r-- | shell/hush.c | 35 |
4 files changed, 48 insertions, 54 deletions
diff --git a/debianutils/which.c b/debianutils/which.c index 1f547919f..a7d55a215 100644 --- a/debianutils/which.c +++ b/debianutils/which.c | |||
| @@ -31,15 +31,12 @@ | |||
| 31 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 31 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 32 | int which_main(int argc UNUSED_PARAM, char **argv) | 32 | int which_main(int argc UNUSED_PARAM, char **argv) |
| 33 | { | 33 | { |
| 34 | char *env_path; | 34 | const char *env_path; |
| 35 | int status = 0; | 35 | int status = 0; |
| 36 | /* This sizeof(): bb_default_root_path is shorter than BB_PATH_ROOT_PATH */ | ||
| 37 | char buf[sizeof(BB_PATH_ROOT_PATH)]; | ||
| 38 | 36 | ||
| 39 | env_path = getenv("PATH"); | 37 | env_path = getenv("PATH"); |
| 40 | if (!env_path) | 38 | if (!env_path) |
| 41 | /* env_path must be writable, and must not alloc, so... */ | 39 | env_path = bb_default_root_path; |
| 42 | env_path = strcpy(buf, bb_default_root_path); | ||
| 43 | 40 | ||
| 44 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); | 41 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); |
| 45 | argv += optind; | 42 | argv += optind; |
| @@ -54,7 +51,7 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
| 54 | puts(*argv); | 51 | puts(*argv); |
| 55 | } | 52 | } |
| 56 | } else { | 53 | } else { |
| 57 | char *path; | 54 | const char *path; |
| 58 | char *p; | 55 | char *p; |
| 59 | 56 | ||
| 60 | path = env_path; | 57 | path = env_path; |
diff --git a/include/libbb.h b/include/libbb.h index f5f8e1635..4d6193795 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -1227,7 +1227,7 @@ void FAST_FUNC update_utmp_DEAD_PROCESS(pid_t pid); | |||
| 1227 | 1227 | ||
| 1228 | 1228 | ||
| 1229 | int file_is_executable(const char *name) FAST_FUNC; | 1229 | int file_is_executable(const char *name) FAST_FUNC; |
| 1230 | char *find_executable(const char *filename, char **PATHp) FAST_FUNC; | 1230 | char *find_executable(const char *filename, const char **PATHp) FAST_FUNC; |
| 1231 | int executable_exists(const char *filename) FAST_FUNC; | 1231 | int executable_exists(const char *filename) FAST_FUNC; |
| 1232 | 1232 | ||
| 1233 | /* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff), | 1233 | /* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff), |
diff --git a/libbb/executable.c b/libbb/executable.c index a033b74d9..09bed1eaf 100644 --- a/libbb/executable.c +++ b/libbb/executable.c | |||
| @@ -21,14 +21,11 @@ int FAST_FUNC file_is_executable(const char *name) | |||
| 21 | /* search (*PATHp) for an executable file; | 21 | /* search (*PATHp) for an executable file; |
| 22 | * return allocated string containing full path if found; | 22 | * return allocated string containing full path if found; |
| 23 | * PATHp points to the component after the one where it was found | 23 | * PATHp points to the component after the one where it was found |
| 24 | * (or NULL), | 24 | * (or NULL if found in last component), |
| 25 | * you may call find_executable again with this PATHp to continue | 25 | * you may call find_executable again with this PATHp to continue |
| 26 | * (if it's not NULL). | 26 | * return NULL otherwise (PATHp is undefined) |
| 27 | * return NULL otherwise; (PATHp is undefined) | ||
| 28 | * in all cases (*PATHp) contents are temporarily modified | ||
| 29 | * but are restored on return (s/:/NUL/ and back). | ||
| 30 | */ | 27 | */ |
| 31 | char* FAST_FUNC find_executable(const char *filename, char **PATHp) | 28 | char* FAST_FUNC find_executable(const char *name, const char **PATHp) |
| 32 | { | 29 | { |
| 33 | /* About empty components in $PATH: | 30 | /* About empty components in $PATH: |
| 34 | * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html | 31 | * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html |
| @@ -38,38 +35,45 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) | |||
| 38 | * initial colon preceding the rest of the list, or as a trailing colon | 35 | * initial colon preceding the rest of the list, or as a trailing colon |
| 39 | * following the rest of the list. | 36 | * following the rest of the list. |
| 40 | */ | 37 | */ |
| 41 | char *p, *n; | 38 | char *p = (char*) *PATHp; |
| 42 | 39 | ||
| 43 | p = *PATHp; | 40 | if (!p) |
| 44 | while (p) { | 41 | return NULL; |
| 45 | int ex; | 42 | while (1) { |
| 43 | const char *end = strchrnul(p, ':'); | ||
| 44 | int sz = end - p; | ||
| 46 | 45 | ||
| 47 | n = strchr(p, ':'); | 46 | if (sz != 0) { |
| 48 | if (n) *n = '\0'; | 47 | p = xasprintf("%.*s/%s", sz, p, name); |
| 49 | p = concat_path_file( | 48 | } else { |
| 50 | p[0] ? p : ".", /* handle "::" case */ | 49 | /* We have xxx::yyy in $PATH, |
| 51 | filename | 50 | * it means "use current dir" */ |
| 52 | ); | 51 | p = xstrdup(name); |
| 53 | ex = file_is_executable(p); | 52 | // A bit of discrepancy wrt the path used if file is found here. |
| 54 | if (n) *n++ = ':'; | 53 | // bash 5.2.15 "type" returns "./NAME". |
| 55 | if (ex) { | 54 | // GNU which v2.21 returns "/CUR/DIR/NAME". |
| 56 | *PATHp = n; | 55 | // With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy, |
| 56 | // current dir is not tried the second time. | ||
| 57 | } | ||
| 58 | if (file_is_executable(p)) { | ||
| 59 | *PATHp = (*end ? end+1 : NULL); | ||
| 57 | return p; | 60 | return p; |
| 58 | } | 61 | } |
| 59 | free(p); | 62 | free(p); |
| 60 | p = n; | 63 | if (*end == '\0') |
| 61 | } /* on loop exit p == NULL */ | 64 | return NULL; |
| 62 | return p; | 65 | p = (char *) end + 1; |
| 66 | } | ||
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | /* search $PATH for an executable file; | 69 | /* search $PATH for an executable file; |
| 66 | * return 1 if found; | 70 | * return 1 if found; |
| 67 | * return 0 otherwise; | 71 | * return 0 otherwise; |
| 68 | */ | 72 | */ |
| 69 | int FAST_FUNC executable_exists(const char *filename) | 73 | int FAST_FUNC executable_exists(const char *name) |
| 70 | { | 74 | { |
| 71 | char *path = getenv("PATH"); | 75 | const char *path = getenv("PATH"); |
| 72 | char *ret = find_executable(filename, &path); | 76 | char *ret = find_executable(name, &path); |
| 73 | free(ret); | 77 | free(ret); |
| 74 | return ret != NULL; | 78 | return ret != NULL; |
| 75 | } | 79 | } |
diff --git a/shell/hush.c b/shell/hush.c index 4e477d05a..04dda0734 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -8207,41 +8207,34 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) | |||
| 8207 | //TODO: shares code with find_executable() in libbb, factor out? | 8207 | //TODO: shares code with find_executable() in libbb, factor out? |
| 8208 | static char *find_in_PATH(const char *name) | 8208 | static char *find_in_PATH(const char *name) |
| 8209 | { | 8209 | { |
| 8210 | char *ret; | 8210 | char *p = (char*) get_local_var_value("PATH"); |
| 8211 | const char *PATH = get_local_var_value("PATH"); | ||
| 8212 | 8211 | ||
| 8213 | if (!PATH) | 8212 | if (!p) |
| 8214 | return NULL; | 8213 | return NULL; |
| 8215 | ret = NULL; | ||
| 8216 | while (1) { | 8214 | while (1) { |
| 8217 | const char *end = strchrnul(PATH, ':'); | 8215 | const char *end = strchrnul(p, ':'); |
| 8218 | int sz = end - PATH; /* must be int! */ | 8216 | int sz = end - p; /* must be int! */ |
| 8219 | 8217 | ||
| 8220 | free(ret); | ||
| 8221 | if (sz != 0) { | 8218 | if (sz != 0) { |
| 8222 | ret = xasprintf("%.*s/%s", sz, PATH, name); | 8219 | p = xasprintf("%.*s/%s", sz, p, name); |
| 8223 | } else { | 8220 | } else { |
| 8224 | /* We have xxx::yyyy in $PATH, | 8221 | /* We have xxx::yyy in $PATH, |
| 8225 | * it means "use current dir" */ | 8222 | * it means "use current dir" */ |
| 8226 | ret = xstrdup(name); | 8223 | p = xstrdup(name); |
| 8227 | } | 8224 | } |
| 8228 | if (access(ret, F_OK) == 0) | 8225 | if (access(p, F_OK) == 0) |
| 8229 | break; | 8226 | return p; |
| 8230 | 8227 | free(p); | |
| 8231 | if (*end == '\0') { | 8228 | if (*end == '\0') |
| 8232 | free(ret); | ||
| 8233 | return NULL; | 8229 | return NULL; |
| 8234 | } | 8230 | p = (char *) end + 1; |
| 8235 | PATH = end + 1; | ||
| 8236 | } | 8231 | } |
| 8237 | |||
| 8238 | return ret; | ||
| 8239 | } | 8232 | } |
| 8240 | 8233 | ||
| 8241 | #if ENABLE_HUSH_TYPE || ENABLE_HUSH_COMMAND | 8234 | #if ENABLE_HUSH_TYPE || ENABLE_HUSH_COMMAND |
| 8242 | static char *find_executable_in_PATH(const char *name) | 8235 | static char *find_executable_in_PATH(const char *name) |
| 8243 | { | 8236 | { |
| 8244 | char *PATH; | 8237 | const char *PATH; |
| 8245 | if (strchr(name, '/')) { | 8238 | if (strchr(name, '/')) { |
| 8246 | /* Name with '/' is tested verbatim, with no PATH traversal: | 8239 | /* Name with '/' is tested verbatim, with no PATH traversal: |
| 8247 | * "cd /bin; type ./cat" should print "./cat is ./cat", | 8240 | * "cd /bin; type ./cat" should print "./cat is ./cat", |
| @@ -8251,7 +8244,7 @@ static char *find_executable_in_PATH(const char *name) | |||
| 8251 | return xstrdup(name); | 8244 | return xstrdup(name); |
| 8252 | return NULL; | 8245 | return NULL; |
| 8253 | } | 8246 | } |
| 8254 | PATH = (char*)get_local_var_value("PATH"); | 8247 | PATH = get_local_var_value("PATH"); |
| 8255 | return find_executable(name, &PATH); /* path == NULL is ok */ | 8248 | return find_executable(name, &PATH); /* path == NULL is ok */ |
| 8256 | } | 8249 | } |
| 8257 | #endif | 8250 | #endif |
