1 /*
2  * This file is part of libbluray
3  * Copyright (C) 2009-2010  Obliter0n
4  * Copyright (C) 2009-2010  John Stebbins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #if HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #ifdef HAVE_DLADDR
26 #  define _GNU_SOURCE  /* dladdr */
27 #endif
28 
29 #include "dl.h"
30 #include "util/macro.h"
31 #include "util/logging.h"
32 #include "util/strutl.h"
33 
34 #ifdef __APPLE__
35 // Required to make dladdr available
36 #    define _DARWIN_C_SOURCE
37 #endif
38 
39 #if defined(HAVE_DLFCN_H)
40 #   include <dlfcn.h>
41 #elif defined(HAVE_SYS_DL_H)
42 #   include <sys/dl.h>
43 #endif
44 
45 #include <string.h>
46 
_dl_dlopen(const char * path)47 static void *_dl_dlopen(const char *path)
48 {
49     void *result;
50 
51     result = dlopen(path, RTLD_LAZY);
52 
53     if (!result) {
54         BD_DEBUG(DBG_FILE, "can't open library '%s': %s\n", path, dlerror());
55     } else {
56         BD_DEBUG(DBG_FILE, "opened library '%s'\n", path);
57     }
58 
59     return result;
60 }
61 
dl_dlopen(const char * path,const char * version)62 void *dl_dlopen(const char *path, const char *version)
63 {
64     char *name;
65     void *dll;
66     int i;
67 
68 #if defined(__APPLE__)
69     static const char ext[] = ".dylib";
70     /*
71       Search for the library in several locations:
72        ""               - default search path (including DYLD_LIBRARY_PATH)
73        @loader_path     - location of current library/binary (ex. libbluray.dylib)
74        @executable_path - location of running binary (ex. /Applications/Some.app/Contents/MacOS)
75        @rpath           - search rpaths of running binary (man install_name_path)
76        /usr/local/lib/  - explicitly added path, as runtime hardened programs ignore DYLD_FALLBACK_PATH now
77     */
78     static const char *search_paths[] = {"", "@loader_path/lib/", "@loader_path/", "@executable_path/",
79                                          "@executable_path/lib/", "@executable_path/../lib/",
80                                          "@executable_path/../Resources/", "@rpath/", "/usr/local/lib/", NULL};
81     version = NULL;
82 #else
83     static const char ext[] = ".so";
84     static const char *search_paths[] = {"", NULL};
85 #endif
86 
87     for (i = 0 ; search_paths[i] ; ++i) {
88         if (version) {
89             name = str_printf("%s%s%s.%s", search_paths[i], path, ext, version);
90         } else {
91             name = str_printf("%s%s%s", search_paths[i], path, ext);
92         }
93 
94         if (!name) {
95             BD_DEBUG(DBG_FILE | DBG_CRIT, "out of memory\n");
96             continue;
97         }
98 
99         dll = _dl_dlopen (name);
100         X_FREE(name);
101         if (dll) {
102             return dll;
103         }
104     }
105 
106     return NULL;
107 }
108 
dl_dlsym(void * handle,const char * symbol)109 void *dl_dlsym(void *handle, const char *symbol)
110 {
111     void *result = dlsym(handle, symbol);
112 
113     if (!result) {
114         BD_DEBUG(DBG_FILE, "dlsym(%p, '%s') failed: %s\n", handle, symbol, dlerror());
115     }
116 
117     return result;
118 }
119 
dl_dlclose(void * handle)120 int dl_dlclose(void *handle)
121 {
122     return dlclose(handle);
123 }
124 
125 #define PATH_SEPARATOR '/'
dl_get_path(void)126 const char *dl_get_path(void)
127 {
128     static char *lib_path    = NULL;
129     static int   initialized = 0;
130 
131     if (!initialized) {
132         initialized = 1;
133 
134 #if defined(__APPLE__) || defined(HAVE_DLADDR)
135         Dl_info dl_info;
136         int ret = dladdr((void *)dl_get_path, &dl_info);
137         if (ret != 0) {
138             lib_path = strdup(dl_info.dli_fname);
139 
140             /* cut library name from path */
141             char *p = strrchr(lib_path, PATH_SEPARATOR);
142             if (p) {
143                 *(p+1) = 0;
144             }
145             BD_DEBUG(DBG_FILE, "library file is %s\n", lib_path);
146         } else {
147             BD_DEBUG(DBG_FILE, "Can't determine libbluray.so install path\n");
148         }
149 #else
150         BD_DEBUG(DBG_FILE, "Can't determine libbluray.so install path\n");
151 #endif
152     }
153 
154     return lib_path;
155 }
156