Merge branch 'relative-path' into 'master'

EGL: Interpret relative ICD paths as relative to the JSON manifest

Closes #190

See merge request glvnd/libglvnd!247
This commit is contained in:
Kyle Brenneman 2021-08-04 14:54:59 +00:00
commit 1ad0ed4a66
2 changed files with 64 additions and 5 deletions

View file

@ -48,7 +48,8 @@ file in a well-known directory, similar to how Vulkan ICDs are loaded.
how it searches for a library.
* If the library path is a relative path containing at least
one directory separator, for example `./libEGL_myvendor.so`,
the loader's behaviour is currently unspecified.
then the loader is expected to treat it as being relative
to the directory containing the JSON file.
## ICD installation

View file

@ -23,7 +23,7 @@
static void LoadVendors(void);
static void TeardownVendor(__EGLvendorInfo *vendor);
static __EGLvendorInfo *LoadVendor(const char *filename);
static __EGLvendorInfo *LoadVendor(const char *filename, const char *jsonPath);
static void LoadVendorsFromConfigDir(const char *dirName);
static __EGLvendorInfo *LoadVendorFromConfigFile(const char *filename);
@ -317,7 +317,7 @@ static __EGLvendorInfo *LoadVendorFromConfigFile(const char *filename)
goto done;
}
libraryPath = node->valuestring;
vendor = LoadVendor(libraryPath);
vendor = LoadVendor(libraryPath, filename);
done:
if (root != NULL) {
@ -437,8 +437,11 @@ static void CheckVendorExtensions(__EGLvendorInfo *vendor)
}
}
static __EGLvendorInfo *LoadVendor(const char *filename)
static __EGLvendorInfo *LoadVendor(const char *filename, const char *jsonPath)
{
char *absolutePath = NULL;
char *jsonDir = NULL;
const char *dlopenName;
__PFNEGLMAINPROC eglMainProc;
__EGLvendorInfo *vendor = NULL;
__EGLvendorInfo *otherVendor;
@ -450,7 +453,58 @@ static __EGLvendorInfo *LoadVendor(const char *filename)
return NULL;
}
vendor->dlhandle = dlopen(filename, RTLD_LAZY);
if (filename == NULL) {
// Clearly not going to work
goto fail;
}
else if (filename[0] == '/') {
// filename is an absolute path, no special handling needed
// e.g. /usr/lib/libEGL_myvendor.so.0
dlopenName = filename;
}
else if (strchr(filename, '/') == NULL) {
// filename is a bare SONAME, no special handling needed
// e.g. libEGL_myvendor.so.0
dlopenName = filename;
}
else {
char *slash;
// filename is a relative path; we have to interpret it as
// relative to *somewhere*. dlopen() would interpret it as relative
// to the current working directory, but that seems unlikely to be
// useful. Instead, follow Vulkan by interpreting it as relative
// to the directory where we found the ICD.
// e.g. it might be ../../../$LIB/libEGL_myvendor.so.0
// Resolve symlinks and relative components in jsonPath. This assumes
// a POSIX.1-2008-compliant realpath(), similar to the implementations
// in glibc and musl.
jsonDir = realpath(jsonPath, NULL);
if (jsonDir == NULL) {
goto fail;
}
// Truncate jsonDir at the last slash to get the directory,
// e.g. /usr/share/glvnd/egl_vendor.d
slash = strrchr(jsonDir, '/');
if (slash == NULL) {
// Shouldn't happen, because the output of realpath() is absolute;
// recover by just not loading it
goto fail;
}
*slash = '\0';
// Concatenate jsonDir and filename
// e.g. /usr/share/glvnd/egl_vendor.d/../../../$LIB/libEGL_myvendor.so.0
if (glvnd_asprintf(&absolutePath, "%s/%s", jsonDir, filename) < 0) {
goto fail;
}
dlopenName = absolutePath;
}
vendor->dlhandle = dlopen(dlopenName, RTLD_LAZY);
if (vendor->dlhandle == NULL) {
goto fail;
}
@ -526,12 +580,16 @@ static __EGLvendorInfo *LoadVendor(const char *filename)
__EGL_DISPATCH_FUNC_INDICES[i]);
}
free(absolutePath);
free(jsonDir);
return vendor;
fail:
if (vendor != NULL) {
TeardownVendor(vendor);
}
free(absolutePath);
free(jsonDir);
return NULL;
}