return strcmp(((dl_t const *)one)->name, ((dl_t const *)two)->name);
}
+/** Utility function to dlopen the library containing a particular symbol
+ *
+ * @note Not really part of our 'dl' API, just a convenience function.
+ *
+ * @param[in] sym_name to resolve.
+ * @param[in] flags to pass to dlopen.
+ * @return
+ * - NULL on error.
+ * - A new handle on success.
+ */
+void *dl_open_by_sym(char const *sym_name, int flags)
+{
+ Dl_info info;
+ void *sym;
+ void *handle;
+
+ /*
+ * Resolve the test symbol in our own symbol space by
+ * iterating through all the libraries.
+ * This might be slow. Don't do this at runtime!
+ */
+ sym = dlsym(RTLD_DEFAULT, sym_name);
+ if (!sym) {
+ fr_strerror_printf("Can't resolve symbol %s", sym_name);
+ return NULL;
+ }
+
+ /*
+ * Lookup the library the symbol belongs to
+ */
+ if (dladdr(sym, &info) == 0) {
+ fr_strerror_printf("Failed retrieving info for \"%s\" (%p)", sym_name, sym);
+ return NULL;
+ }
+
+ handle = dlopen(info.dli_fname, flags);
+ if (!handle) {
+ fr_strerror_printf("Failed loading \"%s\": %s", info.dli_fname, dlerror());
+ return NULL;
+ }
+
+ return handle;
+}
+
/** Walk over the registered init callbacks, searching for the symbols they depend on
*
* Allows code outside of the dl API to register initialisation functions that get
static int mod_load(void)
{
- Dl_info info;
- void *sym;
-
-#define PYTHON_TEST_SYMBOL "Py_IsInitialized"
#define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_python - " _fmt, ## __VA_ARGS__)
#define LOAD_WARN(_fmt, ...) fr_log(LOG_DST, L_WARN, __FILE__, __LINE__, "rlm_python - " _fmt, ## __VA_ARGS__)
dependency_version_number_add(NULL, "python", Py_GetVersion());
/*
- * Resolve the test symbol in our own
- * symbol space.
- */
- sym = dlsym(RTLD_DEFAULT, PYTHON_TEST_SYMBOL);
- if (!sym) {
- LOAD_WARN("Can't find %s in symbol table, skipping loading python into global symbol table",
- PYTHON_TEST_SYMBOL);
- goto skip_dlopen;
- }
-
- /*
- * It's unclear whether passing function
- * pointers will always "just work",
- * which is why we resolve the symbol
- * at runtime then call dladdr.
+ * Load python using RTLD_GLOBAL and dlopen
+ * This fixes issues where python C extensions
+ * can't find the symbols they need.
*/
- if (dladdr(sym, &info) == 0) {
- LOAD_WARN("Failed resolving symbol %s (%p) to library path: %s "
- ", skipping loading python into global symbol table", PYTHON_TEST_SYMBOL, sym, dlerror());
- goto skip_dlopen;
- }
-
- /*
- * Explicitly load libpython, so symbols will be available to lib-dynload modules
- */
- python_dlhandle = dlopen(info.dli_fname, RTLD_NOW | RTLD_GLOBAL);
- if (!python_dlhandle) fr_log(LOG_DST, L_WARN, __FILE__, __LINE__,
- "Failed loading libpython symbols from \"%s\" into global symbol table: %s",
- info.dli_fname, dlerror());
-
-skip_dlopen:
+ python_dlhandle = dl_open_by_sym("Py_IsInitialized", RTLD_NOW | RTLD_GLOBAL);
+ if (!python_dlhandle) LOAD_WARN("Failed loading libpython symbols into global symbol table: %s", fr_strerror());
#if PY_MAJOR_VERSION == 3
/*