1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * This file defines a wrapper around libudev so we can avoid 9 * linking directly to it and use dlopen instead. 10 */ 11 12 #ifndef HAL_LINUX_UDEV_H_ 13 #define HAL_LINUX_UDEV_H_ 14 15 #include <dlfcn.h> 16 17 #include "mozilla/ArrayUtils.h" 18 19 namespace mozilla { 20 21 struct udev; 22 struct udev_device; 23 struct udev_enumerate; 24 struct udev_list_entry; 25 struct udev_monitor; 26 27 class udev_lib { 28 public: udev_lib()29 udev_lib() : lib(nullptr), udev(nullptr) { 30 // Be careful about ABI compat! 0 -> 1 didn't change any 31 // symbols this code relies on, per: 32 // https://lists.fedoraproject.org/pipermail/devel/2012-June/168227.html 33 const char* lib_names[] = {"libudev.so.0", "libudev.so.1"}; 34 // Check whether a library is already loaded so we don't load two 35 // conflicting libs. 36 for (unsigned i = 0; i < ArrayLength(lib_names); i++) { 37 lib = dlopen(lib_names[i], RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL); 38 if (lib) { 39 break; 40 } 41 } 42 // If nothing loads the first time through, it means no version of libudev 43 // was already loaded. 44 if (!lib) { 45 for (unsigned i = 0; i < ArrayLength(lib_names); i++) { 46 lib = dlopen(lib_names[i], RTLD_LAZY | RTLD_GLOBAL); 47 if (lib) { 48 break; 49 } 50 } 51 } 52 if (lib && LoadSymbols()) { 53 udev = udev_new(); 54 } 55 } 56 ~udev_lib()57 ~udev_lib() { 58 if (udev) { 59 udev_unref(udev); 60 } 61 62 if (lib) { 63 dlclose(lib); 64 } 65 } 66 67 explicit operator bool() { return udev; } 68 69 private: 70 #define DLSYM(s) \ 71 do { \ 72 (s) = (decltype(s))dlsym(lib, #s); \ 73 if (!(s)) return false; \ 74 } while (0) 75 LoadSymbols()76 bool LoadSymbols() { 77 DLSYM(udev_new); 78 DLSYM(udev_unref); 79 DLSYM(udev_device_unref); 80 DLSYM(udev_device_new_from_syspath); 81 DLSYM(udev_device_get_devnode); 82 DLSYM(udev_device_get_parent_with_subsystem_devtype); 83 DLSYM(udev_device_get_property_value); 84 DLSYM(udev_device_get_action); 85 DLSYM(udev_device_get_sysattr_value); 86 DLSYM(udev_enumerate_new); 87 DLSYM(udev_enumerate_unref); 88 DLSYM(udev_enumerate_add_match_subsystem); 89 DLSYM(udev_enumerate_scan_devices); 90 DLSYM(udev_enumerate_get_list_entry); 91 DLSYM(udev_list_entry_get_next); 92 DLSYM(udev_list_entry_get_name); 93 DLSYM(udev_monitor_new_from_netlink); 94 DLSYM(udev_monitor_filter_add_match_subsystem_devtype); 95 DLSYM(udev_monitor_enable_receiving); 96 DLSYM(udev_monitor_get_fd); 97 DLSYM(udev_monitor_receive_device); 98 DLSYM(udev_monitor_unref); 99 100 return true; 101 } 102 103 #undef DLSYM 104 105 void* lib; 106 107 public: 108 struct udev* udev; 109 110 // Function pointers returned from dlsym. 111 struct udev* (*udev_new)(void); 112 void (*udev_unref)(struct udev*); 113 114 void (*udev_device_unref)(struct udev_device*); 115 struct udev_device* (*udev_device_new_from_syspath)(struct udev*, 116 const char*); 117 const char* (*udev_device_get_devnode)(struct udev_device*); 118 struct udev_device* (*udev_device_get_parent_with_subsystem_devtype)( 119 struct udev_device*, const char*, const char*); 120 const char* (*udev_device_get_property_value)(struct udev_device*, 121 const char*); 122 const char* (*udev_device_get_action)(struct udev_device*); 123 const char* (*udev_device_get_sysattr_value)(struct udev_device*, 124 const char*); 125 126 struct udev_enumerate* (*udev_enumerate_new)(struct udev*); 127 void (*udev_enumerate_unref)(struct udev_enumerate*); 128 int (*udev_enumerate_add_match_subsystem)(struct udev_enumerate*, 129 const char*); 130 int (*udev_enumerate_scan_devices)(struct udev_enumerate*); 131 struct udev_list_entry* (*udev_enumerate_get_list_entry)( 132 struct udev_enumerate*); 133 134 struct udev_list_entry* (*udev_list_entry_get_next)(struct udev_list_entry*); 135 const char* (*udev_list_entry_get_name)(struct udev_list_entry*); 136 137 struct udev_monitor* (*udev_monitor_new_from_netlink)(struct udev*, 138 const char*); 139 int (*udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor*, 140 const char*, 141 const char*); 142 int (*udev_monitor_enable_receiving)(struct udev_monitor*); 143 int (*udev_monitor_get_fd)(struct udev_monitor*); 144 struct udev_device* (*udev_monitor_receive_device)(struct udev_monitor*); 145 void (*udev_monitor_unref)(struct udev_monitor*); 146 }; 147 148 } // namespace mozilla 149 150 #endif // HAL_LINUX_UDEV_H_ 151