* Rob Clark <robclark@freedesktop.org>
*/
+#include <errno.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_LIBUDEV
#include <assert.h>
#include <dlfcn.h>
-#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
-#include <errno.h>
#ifdef USE_DRICONF
#include "xmlconfig.h"
#include "xmlpool.h"
static void (*log_)(int level, const char *fmt, ...) = default_logger;
+int
+loader_open_device(const char *device_name)
+{
+ int fd;
+#ifdef O_CLOEXEC
+ fd = open(device_name, O_RDWR | O_CLOEXEC);
+ if (fd == -1 && errno == EINVAL)
+#endif
+ {
+ fd = open(device_name, O_RDWR);
+ if (fd != -1)
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ }
+ return fd;
+}
+
#ifdef HAVE_LIBUDEV
#include <libudev.h>
static void *
udev_dlopen_handle(void)
{
- if (!udev_handle) {
- udev_handle = dlopen("libudev.so.1", RTLD_LOCAL | RTLD_LAZY);
-
- if (!udev_handle) {
- /* libudev.so.1 changed the return types of the two unref functions
- * from voids to pointers. We don't use those return values, and the
- * only ABI I've heard that cares about this kind of change (calling
- * a function with a void * return that actually only returns void)
- * might be ia64.
- */
- udev_handle = dlopen("libudev.so.0", RTLD_LOCAL | RTLD_LAZY);
-
- if (!udev_handle) {
- log_(_LOADER_WARNING, "Couldn't dlopen libudev.so.1 or "
- "libudev.so.0, driver detection may be broken.\n");
- }
+ char name[80];
+ unsigned flags = RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY;
+ int version;
+
+ /* libudev.so.1 changed the return types of the two unref functions
+ * from voids to pointers. We don't use those return values, and the
+ * only ABI I've heard that cares about this kind of change (calling
+ * a function with a void * return that actually only returns void)
+ * might be ia64.
+ */
+
+ /* First try opening an already linked libudev, then try loading one */
+ do {
+ for (version = 1; version >= 0; version--) {
+ snprintf(name, sizeof(name), "libudev.so.%d", version);
+ udev_handle = dlopen(name, flags);
+ if (udev_handle)
+ return udev_handle;
}
- }
- return udev_handle;
+ if ((flags & RTLD_NOLOAD) == 0)
+ break;
+
+ flags &= ~RTLD_NOLOAD;
+ } while (1);
+
+ log_(_LOADER_WARNING,
+ "Couldn't dlopen libudev.so.1 or "
+ "libudev.so.0, driver detection may be broken.\n");
+ return NULL;
}
static int dlsym_failed = 0;
return id_path_tag;
}
-static int
-drm_open_device(const char *device_name)
-{
- int fd;
-#ifdef O_CLOEXEC
- fd = open(device_name, O_RDWR | O_CLOEXEC);
- if (fd == -1 && errno == EINVAL)
-#endif
- {
- fd = open(device_name, O_RDWR);
- if (fd != -1)
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
- }
- return fd;
-}
-
#ifdef USE_DRICONF
const char __driConfigOptionsLoader[] =
DRI_CONF_BEGIN
goto default_device_clean;
}
- fd = drm_open_device(device_name);
+ fd = loader_open_device(device_name);
if (fd >= 0) {
close(default_fd);
} else {