michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file defines a wrapper around libudev so we can avoid michael@0: * linking directly to it and use dlopen instead. michael@0: */ michael@0: michael@0: #ifndef HAL_LINUX_UDEV_H_ michael@0: #define HAL_LINUX_UDEV_H_ michael@0: michael@0: #include michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: struct udev; michael@0: struct udev_device; michael@0: struct udev_enumerate; michael@0: struct udev_list_entry; michael@0: struct udev_monitor; michael@0: michael@0: class udev_lib { michael@0: public: michael@0: udev_lib() : lib(nullptr), michael@0: udev(nullptr) { michael@0: // Be careful about ABI compat! 0 -> 1 didn't change any michael@0: // symbols this code relies on, per: michael@0: // https://lists.fedoraproject.org/pipermail/devel/2012-June/168227.html michael@0: const char* lib_names[] = {"libudev.so.0", "libudev.so.1"}; michael@0: // Check whether a library is already loaded so we don't load two michael@0: // conflicting libs. michael@0: for (unsigned i = 0; i < ArrayLength(lib_names); i++) { michael@0: lib = dlopen(lib_names[i], RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL); michael@0: if (lib) { michael@0: break; michael@0: } michael@0: } michael@0: // If nothing loads the first time through, it means no version of libudev michael@0: // was already loaded. michael@0: if (!lib) { michael@0: for (unsigned i = 0; i < ArrayLength(lib_names); i++) { michael@0: lib = dlopen(lib_names[i], RTLD_LAZY | RTLD_GLOBAL); michael@0: if (lib) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: if (lib && LoadSymbols()) { michael@0: udev = udev_new(); michael@0: } michael@0: } michael@0: michael@0: ~udev_lib() { michael@0: if (udev) { michael@0: udev_unref(udev); michael@0: } michael@0: michael@0: if (lib) { michael@0: dlclose(lib); michael@0: } michael@0: } michael@0: michael@0: operator bool() { michael@0: return udev; michael@0: } michael@0: michael@0: private: michael@0: bool LoadSymbols() { michael@0: #define DLSYM(s) \ michael@0: do { \ michael@0: s = (typeof(s))dlsym(lib, #s); \ michael@0: if (!s) return false; \ michael@0: } while (0) michael@0: michael@0: DLSYM(udev_new); michael@0: DLSYM(udev_unref); michael@0: DLSYM(udev_device_unref); michael@0: DLSYM(udev_device_new_from_syspath); michael@0: DLSYM(udev_device_get_devnode); michael@0: DLSYM(udev_device_get_parent_with_subsystem_devtype); michael@0: DLSYM(udev_device_get_property_value); michael@0: DLSYM(udev_device_get_action); michael@0: DLSYM(udev_device_get_sysattr_value); michael@0: DLSYM(udev_enumerate_new); michael@0: DLSYM(udev_enumerate_unref); michael@0: DLSYM(udev_enumerate_add_match_subsystem); michael@0: DLSYM(udev_enumerate_scan_devices); michael@0: DLSYM(udev_enumerate_get_list_entry); michael@0: DLSYM(udev_list_entry_get_next); michael@0: DLSYM(udev_list_entry_get_name); michael@0: DLSYM(udev_monitor_new_from_netlink); michael@0: DLSYM(udev_monitor_filter_add_match_subsystem_devtype); michael@0: DLSYM(udev_monitor_enable_receiving); michael@0: DLSYM(udev_monitor_get_fd); michael@0: DLSYM(udev_monitor_receive_device); michael@0: DLSYM(udev_monitor_unref); michael@0: #undef DLSYM michael@0: return true; michael@0: } michael@0: michael@0: void* lib; michael@0: michael@0: public: michael@0: struct udev* udev; michael@0: michael@0: // Function pointers returned from dlsym. michael@0: struct udev* (*udev_new)(void); michael@0: void (*udev_unref)(struct udev*); michael@0: michael@0: void (*udev_device_unref)(struct udev_device*); michael@0: struct udev_device* (*udev_device_new_from_syspath)(struct udev*, michael@0: const char*); michael@0: const char* (*udev_device_get_devnode)(struct udev_device*); michael@0: struct udev_device* (*udev_device_get_parent_with_subsystem_devtype) michael@0: (struct udev_device*, const char*, const char*); michael@0: const char* (*udev_device_get_property_value)(struct udev_device*, michael@0: const char*); michael@0: const char* (*udev_device_get_action)(struct udev_device*); michael@0: const char* (*udev_device_get_sysattr_value)(struct udev_device*, michael@0: const char*); michael@0: michael@0: struct udev_enumerate* (*udev_enumerate_new)(struct udev*); michael@0: void (*udev_enumerate_unref)(struct udev_enumerate*); michael@0: int (*udev_enumerate_add_match_subsystem)(struct udev_enumerate*, michael@0: const char*); michael@0: int (*udev_enumerate_scan_devices)(struct udev_enumerate*); michael@0: struct udev_list_entry* (*udev_enumerate_get_list_entry) michael@0: (struct udev_enumerate*); michael@0: michael@0: struct udev_list_entry* (*udev_list_entry_get_next)(struct udev_list_entry *); michael@0: const char* (*udev_list_entry_get_name)(struct udev_list_entry*); michael@0: michael@0: struct udev_monitor* (*udev_monitor_new_from_netlink)(struct udev*, michael@0: const char*); michael@0: int (*udev_monitor_filter_add_match_subsystem_devtype) michael@0: (struct udev_monitor*, const char*, const char*); michael@0: int (*udev_monitor_enable_receiving)(struct udev_monitor*); michael@0: int (*udev_monitor_get_fd)(struct udev_monitor*); michael@0: struct udev_device* (*udev_monitor_receive_device)(struct udev_monitor*); michael@0: void (*udev_monitor_unref)(struct udev_monitor*); michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif // HAL_LINUX_UDEV_H_