diff --git a/libutil/dr_frontend_unix.c b/libutil/dr_frontend_unix.c index 4dc9d3454f72c7f65527d195f71dd56f2a93e9e7..ac86d26aa3a407658eec42c810e9caf0e9e5f238 100644 --- a/libutil/dr_frontend_unix.c +++ b/libutil/dr_frontend_unix.c @@ -137,6 +137,8 @@ drfront_searchenv(const char *fname, const char *env_var, OUT char *full_path, char realpath_buf[PATH_MAX]; /* realpath hardcodes its buffer length */ drfront_status_t status_check = DRFRONT_ERROR; bool access_ret = false; + int r; + struct stat st; if (ret == NULL) return DRFRONT_ERROR_INVALID_PARAMETER; @@ -166,15 +168,21 @@ drfront_searchenv(const char *fname, const char *env_var, OUT char *full_path, NULL_TERMINATE_BUFFER(tmp); /* realpath checks for existence too. */ if (realpath(tmp, realpath_buf) != NULL) { - status_check = drfront_access(realpath_buf, DRFRONT_EXIST, &access_ret); + status_check = drfront_access(realpath_buf, DRFRONT_EXEC, &access_ret); if (status_check != DRFRONT_SUCCESS) { *ret = false; return status_check; } else if (access_ret == true) { - *ret = true; - snprintf(full_path, full_path_size, "%s", realpath_buf); - full_path[full_path_size - 1] = '\0'; - return DRFRONT_SUCCESS; + // XXX: An other option to prevent calling stat() twice + // could be a new variant DRFRONT_NOTDIR for drfront_access_mode_t + // that drfront_access() then takes into account. + r = stat(realpath_buf, &st); + if (r != -1 && !S_ISDIR(st.st_mode)) { + *ret = true; + snprintf(full_path, full_path_size, "%s", realpath_buf); + full_path[full_path_size - 1] = '\0'; + return DRFRONT_SUCCESS; + } } } cur = next + 1; diff --git a/suite/tests/libutil/frontend_test.c b/suite/tests/libutil/frontend_test.c index 0b45f1473c905f987e6d2c4f3e3641e2fe044ab1..cea70b812699c1bbea9fbf354209b8d8849a3352 100644 --- a/suite/tests/libutil/frontend_test.c +++ b/suite/tests/libutil/frontend_test.c @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2014-2019 Google, Inc. All rights reserved. + * Copyright (c) 2014-2022 Google, Inc. All rights reserved. * Copyright (c) 2003 VMware, Inc. All rights reserved. * **********************************************************/ @@ -31,7 +31,9 @@ * DAMAGE. */ +#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> +#include <string.h> #include "dr_api.h" #include "dr_frontend.h" @@ -42,6 +44,10 @@ main() { bool dir_exists; int res; + char path_env[4096]; + char path_buf[4096]; + char full_path_buf[4096]; + bool ret; res = drfront_create_dir("test_dir"); if (res != DRFRONT_SUCCESS && res != DRFRONT_EXIST) { printf("drfront_create_dir failed \n"); @@ -53,11 +59,38 @@ main() return -1; } - res = drfront_remove_dir("test_dir"); + res = drfront_get_env_var("PATH", path_env, sizeof(path_env)); + if (res != DRFRONT_SUCCESS) { + printf("failed to get env var: %d\n", res); + return -1; + } + const char *const subdir = "test_dir:"; + strncpy(path_buf, subdir, strlen(subdir)); + strncat(path_buf, path_env, sizeof(path_buf) - strlen(subdir) - 1); +#ifdef UNIX + if (setenv("PATH", path_buf, 1 /*override*/) != 0) { + printf("failed to set env var\n"); + return -1; + } +#else + if (!SetEnvironmentVariable("PATH", path_buf)) { + printf("failed to set env var\n"); + return -1; + } +#endif + drfront_create_dir("test_dir/test_ex"); + if (drfront_searchenv("test_ex", "PATH", full_path_buf, sizeof(full_path_buf), + &ret) != DRFRONT_ERROR) { + printf("failed to ignore test_ex in PATH\n"); + return -1; + } + + res = drfront_remove_dir("test_dir/test_ex"); if (res != DRFRONT_SUCCESS) { printf("drfront_remove_dir failed\n"); return -1; } + drfront_remove_dir("test_dir"); #ifdef WINDOWS if (drfront_set_verbose(1) != DRFRONT_SUCCESS) { printf("drfront_set_verbose failed\n");