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 |