summaryrefslogtreecommitdiff
path: root/loader
diff options
context:
space:
mode:
authorBenjamin Saunders <ben.e.saunders@gmail.com>2017-01-29 14:49:54 -0800
committerMark Young <marky@lunarg.com>2017-02-02 10:16:28 -0700
commitae847980b0af50af49aa0b62d232e7be0ebfcab2 (patch)
tree248cec0e78ae4e035ae9aac57119e110f75a026f /loader
parent08c7aae3177092f8567e2b5a946457be61616e9a (diff)
loader: Improve Linux manifest search
Searching XDG_CONFIG_DIRS and XDG_DATA_DIRS instead of hard-coding specific paths improves portability, particularly on platforms which don't implement the Filesystem Hierarchy Standard. For example, this allows the loader to function correctly out of the box on NixOS.
Diffstat (limited to 'loader')
-rw-r--r--loader/loader.c115
-rw-r--r--loader/vk_loader_platform.h44
2 files changed, 105 insertions, 54 deletions
diff --git a/loader/loader.c b/loader/loader.c
index 2875af13..81c37c4c 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -30,6 +30,7 @@
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
+#include <stddef.h>
#include <sys/types.h>
#if defined(_WIN32)
@@ -2585,7 +2586,7 @@ static void loader_add_layer_properties(const struct loader_instance *inst, stru
* Linux Layer| dirs | dirs
*/
static VkResult loader_get_manifest_files(const struct loader_instance *inst, const char *env_override, const char *source_override,
- bool is_layer, bool warn_if_not_present, const char *location, const char *home_location,
+ bool is_layer, bool warn_if_not_present, const char *location, const char *relative_location,
struct loader_manifest_files *out_files) {
const char * override = NULL;
char *override_getenv = NULL;
@@ -2617,9 +2618,9 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
}
#if !defined(_WIN32)
- if (location == NULL && home_location == NULL) {
+ if (relative_location == NULL) {
#else
- home_location = NULL;
+ relative_location = NULL;
if (location == NULL) {
#endif
loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
@@ -2638,16 +2639,92 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
// Make a copy of the input we are using so it is not modified
// Also handle getting the location(s) from registry on Windows
if (override == NULL) {
- loc = loader_stack_alloc(strlen(location) + 1);
+ size_t loc_size = 0;
+#if !defined(_WIN32)
+ const char *xdgconfdirs = secure_getenv("XDG_CONFIG_DIRS");
+ const char *xdgdatadirs = secure_getenv("XDG_DATA_DIRS");
+ if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0')
+ xdgconfdirs = "/etc/xdg";
+ if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0')
+ xdgdatadirs = "/usr/local/share:/usr/share";
+ const size_t rel_size = strlen(relative_location);
+ // Leave space for trailing separators
+ loc_size += strlen(xdgconfdirs) + strlen(xdgdatadirs) + 2*rel_size + 2;
+ for (const char *x = xdgconfdirs; *x; ++x)
+ if (*x == PATH_SEPARATOR) loc_size += rel_size;
+ for (const char *x = xdgdatadirs; *x; ++x)
+ if (*x == PATH_SEPARATOR) loc_size += rel_size;
+ loc_size += strlen(SYSCONFDIR) + rel_size + 1;
+#if defined(EXTRASYSCONFDIR)
+ loc_size += strlen(EXTRASYSCONFDIR) + rel_size + 1;
+#endif
+#else
+ loc_size += strlen(location) + 1;
+#endif
+ loc = loader_stack_alloc(loc_size);
if (loc == NULL) {
loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
"loader_get_manifest_files: Failed to allocate "
"%d bytes for manifest file location.",
- strlen(location));
+ loc_size);
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
- strcpy(loc, location);
+ char *loc_write = loc;
+#if !defined(_WIN32)
+ const char *loc_read;
+
+ loc_read = &xdgconfdirs[0];
+ for (const char *x = loc_read;; ++x) {
+ if (*x == PATH_SEPARATOR || *x == '\0') {
+ const size_t s = x - loc_read;
+ memcpy(loc_write, loc_read, s);
+ loc_write += s;
+ memcpy(loc_write, relative_location, rel_size);
+ loc_write += rel_size;
+ *loc_write++ = PATH_SEPARATOR;
+ if (*x == 0)
+ break;
+ loc_read = ++x;
+ }
+ }
+
+ memcpy(loc_write, SYSCONFDIR, strlen(SYSCONFDIR));
+ loc_write += strlen(SYSCONFDIR);
+ memcpy(loc_write, relative_location, rel_size);
+ loc_write += rel_size;
+ *loc_write++ = PATH_SEPARATOR;
+
+#if defined(EXTRASYSCONFDIR)
+ memcpy(loc_write, EXTRASYSCONFDIR, strlen(EXTRASYSCONFDIR));
+ loc_write += strlen(EXTRASYSCONFDIR);
+ memcpy(loc_write, relative_location, rel_size);
+ loc_write += rel_size;
+ *loc_write++ = PATH_SEPARATOR;
+#endif
+
+ loc_read = &xdgdatadirs[0];
+ for (const char *x = loc_read;; ++x) {
+ if (*x == PATH_SEPARATOR || *x == '\0') {
+ const size_t s = x - loc_read;
+ memcpy(loc_write, loc_read, s);
+ loc_write += s;
+ memcpy(loc_write, relative_location, rel_size);
+ loc_write += rel_size;
+ *loc_write++ = PATH_SEPARATOR;
+ if (*x == 0)
+ break;
+ loc_read = ++x;
+ }
+ }
+ --loc_write;
+#else
+ memcpy(loc_write, location, strlen(location));
+ loc_write += strlen(location);
+#endif
+ assert(loc_write - loc < (ptrdiff_t)loc_size);
+ *loc_write = '\0';
+
#if defined(_WIN32)
VkResult reg_result = loaderGetRegistryFiles(inst, loc, &reg);
if (VK_SUCCESS != reg_result || NULL == reg) {
@@ -2786,11 +2863,11 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
}
file = next_file;
#if !defined(_WIN32)
- if (home_location != NULL && (next_file == NULL || *next_file == '\0') && override == NULL) {
+ if (relative_location != NULL && (next_file == NULL || *next_file == '\0') && override == NULL) {
char *xdgdatahome = secure_getenv("XDG_DATA_HOME");
size_t len;
if (xdgdatahome != NULL) {
- char *home_loc = loader_stack_alloc(strlen(xdgdatahome) + 2 + strlen(home_location));
+ char *home_loc = loader_stack_alloc(strlen(xdgdatahome) + 2 + strlen(relative_location));
if (home_loc == NULL) {
loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
"loader_get_manifest_files: Failed to allocate "
@@ -2800,15 +2877,15 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
}
strcpy(home_loc, xdgdatahome);
// Add directory separator if needed
- if (home_location[0] != DIRECTORY_SYMBOL) {
+ if (relative_location[0] != DIRECTORY_SYMBOL) {
len = strlen(home_loc);
home_loc[len] = DIRECTORY_SYMBOL;
home_loc[len + 1] = '\0';
}
- strcat(home_loc, home_location);
+ strcat(home_loc, relative_location);
file = home_loc;
next_file = loader_get_next_path(file);
- home_location = NULL;
+ relative_location = NULL;
loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
home_loc);
@@ -2817,7 +2894,7 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
} else {
char *home = secure_getenv("HOME");
if (home != NULL) {
- char *home_loc = loader_stack_alloc(strlen(home) + 16 + strlen(home_location));
+ char *home_loc = loader_stack_alloc(strlen(home) + 16 + strlen(relative_location));
if (home_loc == NULL) {
loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
"loader_get_manifest_files: Failed to allocate "
@@ -2834,15 +2911,15 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
}
strcat(home_loc, ".local/share");
- if (home_location[0] != DIRECTORY_SYMBOL) {
+ if (relative_location[0] != DIRECTORY_SYMBOL) {
len = strlen(home_loc);
home_loc[len] = DIRECTORY_SYMBOL;
home_loc[len + 1] = '\0';
}
- strcat(home_loc, home_location);
+ strcat(home_loc, relative_location);
file = home_loc;
next_file = loader_get_next_path(file);
- home_location = NULL;
+ relative_location = NULL;
loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
home_loc);
@@ -2914,7 +2991,7 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
}
// Get a list of manifest files for ICDs
- res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false, true, DEFAULT_VK_DRIVERS_INFO, HOME_VK_DRIVERS_INFO,
+ res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false, true, DEFAULT_VK_DRIVERS_INFO, RELATIVE_VK_DRIVERS_INFO,
&manifest_files);
if (VK_SUCCESS != res || manifest_files.count == 0) {
goto out;
@@ -3128,14 +3205,14 @@ void loader_layer_scan(const struct loader_instance *inst, struct loader_layer_l
// Get a list of manifest files for explicit layers
if (VK_SUCCESS != loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH, true, true, DEFAULT_VK_ELAYERS_INFO,
- HOME_VK_ELAYERS_INFO, &manifest_files[0])) {
+ RELATIVE_VK_ELAYERS_INFO, &manifest_files[0])) {
goto out;
}
// Get a list of manifest files for any implicit layers
// Pass NULL for environment variable override - implicit layers are not
// overridden by LAYERS_PATH_ENV
- if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, HOME_VK_ILAYERS_INFO,
+ if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
&manifest_files[1])) {
goto out;
}
@@ -3198,7 +3275,7 @@ void loader_implicit_layer_scan(const struct loader_instance *inst, struct loade
// Pass NULL for environment variable override - implicit layers are not
// overridden by LAYERS_PATH_ENV
VkResult res =
- loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, HOME_VK_ILAYERS_INFO, &manifest_files);
+ loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO, &manifest_files);
if (VK_SUCCESS != res || manifest_files.count == 0) {
return;
}
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h
index 8a70865d..9af64a9e 100644
--- a/loader/vk_loader_platform.h
+++ b/loader/vk_loader_platform.h
@@ -57,35 +57,9 @@
#define VULKAN_ILAYERCONF_DIR "implicit_layer.d"
#define VULKAN_LAYER_DIR "layer"
-#if defined(EXTRASYSCONFDIR)
-#define EXTRA_DRIVERS_SYSCONFDIR_INFO ":" EXTRASYSCONFDIR VULKAN_DIR VULKAN_ICDCONF_DIR
-#define EXTRA_ELAYERS_SYSCONFDIR_INFO ":" EXTRASYSCONFDIR VULKAN_DIR VULKAN_ELAYERCONF_DIR
-#define EXTRA_ILAYERS_SYSCONFDIR_INFO ":" EXTRASYSCONFDIR VULKAN_DIR VULKAN_ILAYERCONF_DIR
-#else
-#define EXTRA_DRIVERS_SYSCONFDIR_INFO
-#define EXTRA_ELAYERS_SYSCONFDIR_INFO
-#define EXTRA_ILAYERS_SYSCONFDIR_INFO
-#endif
-
-#if defined(EXTRADATADIR)
-#define EXTRA_DRIVERS_DATADIR_INFO ":" EXTRADATADIR VULKAN_DIR VULKAN_ICDCONF_DIR
-#define EXTRA_ELAYERS_DATADIR_INFO ":" EXTRADATADIR VULKAN_DIR VULKAN_ELAYERCONF_DIR
-#define EXTRA_ILAYERS_DATADIR_INFO ":" EXTRADATADIR VULKAN_DIR VULKAN_ILAYERCONF_DIR
-#else
-#define EXTRA_DRIVERS_DATADIR_INFO
-#define EXTRA_ELAYERS_DATADIR_INFO
-#define EXTRA_ILAYERS_DATADIR_INFO
-#endif
-
-#define DEFAULT_VK_DRIVERS_INFO \
- SYSCONFDIR VULKAN_DIR VULKAN_ICDCONF_DIR \
- ":" DATADIR VULKAN_DIR VULKAN_ICDCONF_DIR EXTRA_DRIVERS_SYSCONFDIR_INFO EXTRA_DRIVERS_DATADIR_INFO
-#define DEFAULT_VK_ELAYERS_INFO \
- SYSCONFDIR VULKAN_DIR VULKAN_ELAYERCONF_DIR \
- ":" DATADIR VULKAN_DIR VULKAN_ELAYERCONF_DIR EXTRA_ELAYERS_SYSCONFDIR_INFO EXTRA_ELAYERS_DATADIR_INFO
-#define DEFAULT_VK_ILAYERS_INFO \
- SYSCONFDIR VULKAN_DIR VULKAN_ILAYERCONF_DIR \
- ":" DATADIR VULKAN_DIR VULKAN_ILAYERCONF_DIR EXTRA_ILAYERS_SYSCONFDIR_INFO EXTRA_ILAYERS_DATADIR_INFO
+#define DEFAULT_VK_DRIVERS_INFO ""
+#define DEFAULT_VK_ELAYERS_INFO ""
+#define DEFAULT_VK_ILAYERS_INFO ""
#define DEFAULT_VK_DRIVERS_PATH ""
#if !defined(DEFAULT_VK_LAYERS_PATH)
@@ -97,9 +71,9 @@
#endif
#define LAYERS_PATH_ENV "VK_LAYER_PATH"
-#define HOME_VK_DRIVERS_INFO VULKAN_DIR VULKAN_ICDCONF_DIR
-#define HOME_VK_ELAYERS_INFO VULKAN_DIR VULKAN_ELAYERCONF_DIR
-#define HOME_VK_ILAYERS_INFO VULKAN_DIR VULKAN_ILAYERCONF_DIR
+#define RELATIVE_VK_DRIVERS_INFO VULKAN_DIR VULKAN_ICDCONF_DIR
+#define RELATIVE_VK_ELAYERS_INFO VULKAN_DIR VULKAN_ELAYERCONF_DIR
+#define RELATIVE_VK_ILAYERS_INFO VULKAN_DIR VULKAN_ILAYERCONF_DIR
// C99:
#define PRINTF_SIZE_T_SPECIFIER "%zu"
@@ -201,9 +175,9 @@ static inline void loader_platform_thread_cond_broadcast(loader_platform_thread_
#define LAYERS_SOURCE_PATH NULL
#endif
#define LAYERS_PATH_ENV "VK_LAYER_PATH"
-#define HOME_VK_DRIVERS_INFO ""
-#define HOME_VK_ELAYERS_INFO ""
-#define HOME_VK_ILAYERS_INFO ""
+#define RELATIVE_VK_DRIVERS_INFO ""
+#define RELATIVE_VK_ELAYERS_INFO ""
+#define RELATIVE_VK_ILAYERS_INFO ""
#define PRINTF_SIZE_T_SPECIFIER "%Iu"
// File IO