Skip to content

Commit dff5a2a

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

1 file changed

Lines changed: 17 additions & 6 deletions

File tree

driver/driver.c

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

177-
#if defined(__linux__)
177+
/*
178+
* Glibc, Musl 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(__GLIBC__) || defined(__linux__) || (defined(__sun) && defined(__SVR4))
178189
static const char *get_runpath() {
179190
void *handle = dlopen(NULL, RTLD_NOW);
180191
if (handle == NULL) {
@@ -194,18 +205,18 @@ static const char *get_runpath() {
194205
} else if (dyn->d_tag == DT_RUNPATH) {
195206
runpath = dyn;
196207
} else if (dyn->d_tag == DT_STRTAB) {
197-
strtab = (const char *)dyn->d_un.d_val;
208+
strtab = (const char *)dyn->d_un.d_ptr;
198209
}
199210
}
200-
if (runpath) {
211+
if (runpath != NULL && strtab != NULL) {
201212
return strtab + runpath->d_un.d_val;
202213
} else {
203214
return NULL;
204215
}
205216
}
206217

207218
#else
208-
// FIXME: I still didn't find the way to determine RUNPATH on non-Linux.
219+
// FIXME: I still didn't find the way to determine RUNPATH on non-Glibc/Musl/Soloris.
209220
// So use $ORIGIN as a temporary solution
210221
static char *get_runpath() { return get_origin(); }
211222
#endif
@@ -224,7 +235,7 @@ static char *get_driver_path() {
224235
char *LPAC_DRIVER_HOME = get_first_runpath(get_runpath());
225236
if (LPAC_DRIVER_HOME == NULL)
226237
return NULL;
227-
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN")) {
238+
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN") || !strcmp(LPAC_DRIVER_HOME, "@loader_path")) {
228239
free(LPAC_DRIVER_HOME);
229240
LPAC_DRIVER_HOME = get_origin();
230241
if (LPAC_DRIVER_HOME == NULL)
@@ -324,7 +335,7 @@ static const struct euicc_driver *find_driver_by_name(const enum euicc_driver_ty
324335
_cleanup_free_ char *LPAC_DRIVER_HOME = get_driver_path();
325336
if (LPAC_DRIVER_HOME == NULL)
326337
return false;
327-
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN")) {
338+
if (!strcmp(LPAC_DRIVER_HOME, "$ORIGIN") || !strcmp(LPAC_DRIVER_HOME, "@loader_path")) {
328339
free(LPAC_DRIVER_HOME);
329340
LPAC_DRIVER_HOME = get_origin();
330341
if (LPAC_DRIVER_HOME == NULL)

0 commit comments

Comments
 (0)