Skip to content

Commit 8b36b48

Browse files
refactor(driver): make DT_RUNPATH detect more robust
Signed-off-by: Coelacanthus <uwu@coelacanthus.name>
1 parent 7f26a84 commit 8b36b48

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

driver/driver.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,19 @@ static char *get_origin() {
174174
}
175175
#endif
176176

177-
#if defined(__linux__)
177+
/*
178+
* Glibc, Musl, FreeBSD and Soloris support RTLD_DI_LINKMAP.
179+
* Musl hate the vendor detect macro and refuse to support __musl__.
180+
* They think we should test feature instead of detect vendor, it's normally right,
181+
* but for dlinfo(3), it's almost impossible because dlinfo has no errno or similar thing,
182+
* there is dlerror(3), right? No! dlerror(3) can only return a implementation-defined error string
183+
* (In C term, it should be called unspecified behavior because libc implementation needn't have
184+
* documentation for it) instead of an integer which we can compare it with specific value
185+
* programmatically. So we can't test this feature is available, we can only assume there is only
186+
* Glibc and Musl on Linux, forget Nolibc and other libc implementations on Linux.
187+
*/
188+
#if defined(RTLD_DI_LINKMAP) || defined(__GLIBC__) || defined(__linux__) || defined(__FreeBSD__) \
189+
|| (defined(__sun) && defined(__SVR4))
178190
static const char *get_runpath() {
179191
void *handle = dlopen(NULL, RTLD_NOW);
180192
if (handle == NULL) {
@@ -194,18 +206,18 @@ static const char *get_runpath() {
194206
} else if (dyn->d_tag == DT_RUNPATH) {
195207
runpath = dyn;
196208
} else if (dyn->d_tag == DT_STRTAB) {
197-
strtab = (const char *)dyn->d_un.d_val;
209+
strtab = (const char *)dyn->d_un.d_ptr;
198210
}
199211
}
200-
if (runpath) {
212+
if (runpath != NULL && strtab != NULL) {
201213
return strtab + runpath->d_un.d_val;
202214
} else {
203215
return NULL;
204216
}
205217
}
206218

207219
#else
208-
// FIXME: I still didn't find the way to determine RUNPATH on non-Linux.
220+
// FIXME: I still didn't find the way to determine RUNPATH on non-Glibc/Musl/Soloris.
209221
// So use $ORIGIN as a temporary solution
210222
static char *get_runpath() { return get_origin(); }
211223
#endif
@@ -224,7 +236,7 @@ static char *get_driver_path() {
224236
char *LPAC_DRIVER_HOME = get_first_runpath(get_runpath());
225237
if (LPAC_DRIVER_HOME == NULL)
226238
return NULL;
227-
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN")) {
239+
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN") || !strcmp(LPAC_DRIVER_HOME, "@loader_path")) {
228240
free(LPAC_DRIVER_HOME);
229241
LPAC_DRIVER_HOME = get_origin();
230242
if (LPAC_DRIVER_HOME == NULL)
@@ -324,7 +336,7 @@ static const struct euicc_driver *find_driver_by_name(const enum euicc_driver_ty
324336
_cleanup_free_ char *LPAC_DRIVER_HOME = get_driver_path();
325337
if (LPAC_DRIVER_HOME == NULL)
326338
return false;
327-
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN")) {
339+
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN") || !strcmp(LPAC_DRIVER_HOME, "@loader_path")) {
328340
free(LPAC_DRIVER_HOME);
329341
LPAC_DRIVER_HOME = get_origin();
330342
if (LPAC_DRIVER_HOME == NULL)

0 commit comments

Comments
 (0)