udev.go (4922B)
1 // +build linux,cgo 2 3 // Package udev provides a cgo wrapper around the libudev C library 4 package udev 5 6 /* 7 #cgo LDFLAGS: -ludev 8 #include <libudev.h> 9 #include <linux/types.h> 10 #include <stdlib.h> 11 #include <linux/kdev_t.h> 12 */ 13 import "C" 14 import ( 15 "runtime" 16 "sync" 17 ) 18 19 // Udev is an opaque struct wraping a udev library context 20 type Udev struct { 21 // A pointer to the C struct udev context 22 ptr *C.struct_udev 23 // Mutex for thread sync as libudev is not thread safe when called with the same struct udev 24 m sync.Mutex 25 once sync.Once 26 } 27 28 func udevUnref(u *Udev) { 29 C.udev_unref(u.ptr) 30 } 31 32 // Lock locks a udev context 33 func (u *Udev) lock() { 34 u.once.Do(func() { 35 u.ptr = C.udev_new() 36 runtime.SetFinalizer(u, udevUnref) 37 }) 38 u.m.Lock() 39 } 40 41 // Unlock unlocks a udev context 42 func (u *Udev) unlock() { 43 u.m.Unlock() 44 } 45 46 // newDevice is a private helper function and returns a pointer to a new device. 47 // The device is also added t the devices map in the udev context. 48 // The agrument ptr is a pointer to the underlying C udev_device structure. 49 // The function returns nil if the pointer passed is NULL. 50 func (u *Udev) newDevice(ptr *C.struct_udev_device) (d *Device) { 51 // If passed a NULL pointer, return nil 52 if ptr == nil { 53 return nil 54 } 55 // Create a new device object 56 d = &Device{ 57 ptr: ptr, 58 u: u, 59 } 60 runtime.SetFinalizer(d, deviceUnref) 61 // Return the device object 62 return 63 } 64 65 // newMonitor is a private helper function and returns a pointer to a new monitor. 66 // The monitor is also added t the monitors map in the udev context. 67 // The agrument ptr is a pointer to the underlying C udev_monitor structure. 68 // The function returns nil if the pointer passed is NULL. 69 func (u *Udev) newMonitor(ptr *C.struct_udev_monitor) (m *Monitor) { 70 // If passed a NULL pointer, return nil 71 if ptr == nil { 72 return nil 73 } 74 // Create a new device object 75 m = &Monitor{ 76 ptr: ptr, 77 u: u, 78 } 79 runtime.SetFinalizer(m, monitorUnref) 80 // Return the device object 81 return 82 } 83 84 func (u *Udev) newEnumerate(ptr *C.struct_udev_enumerate) (e *Enumerate) { 85 // If passed a NULL pointer, return nil 86 if ptr == nil { 87 return nil 88 } 89 // Create a new device object 90 e = &Enumerate{ 91 ptr: ptr, 92 u: u, 93 } 94 runtime.SetFinalizer(e, enumerateUnref) 95 // Return the device object 96 return 97 } 98 99 // NewDeviceFromSyspath returns a pointer to a new device identified by its syspath, and nil on error 100 // The device is identified by the syspath argument 101 func (u *Udev) NewDeviceFromSyspath(syspath string) *Device { 102 // Lock the udev context 103 u.lock() 104 defer u.unlock() 105 // Convert Go strings to C strings for passing 106 s := C.CString(syspath) 107 defer freeCharPtr(s) 108 // Return a new device 109 return u.newDevice(C.udev_device_new_from_syspath(u.ptr, s)) 110 } 111 112 // NewDeviceFromDevnum returns a pointer to a new device identified by its Devnum, and nil on error 113 // deviceType is 'c' for a character device and 'b' for a block device 114 func (u *Udev) NewDeviceFromDevnum(deviceType uint8, n Devnum) *Device { 115 u.lock() 116 defer u.unlock() 117 return u.newDevice(C.udev_device_new_from_devnum(u.ptr, C.char(deviceType), n.d)) 118 } 119 120 // NewDeviceFromSubsystemSysname returns a pointer to a new device identified by its subystem and sysname, and nil on error 121 func (u *Udev) NewDeviceFromSubsystemSysname(subsystem, sysname string) *Device { 122 u.lock() 123 defer u.unlock() 124 ss, sn := C.CString(subsystem), C.CString(sysname) 125 defer freeCharPtr(ss) 126 defer freeCharPtr(sn) 127 return u.newDevice(C.udev_device_new_from_subsystem_sysname(u.ptr, ss, sn)) 128 } 129 130 // NewDeviceFromDeviceID returns a pointer to a new device identified by its device id, and nil on error 131 func (u *Udev) NewDeviceFromDeviceID(id string) *Device { 132 u.lock() 133 defer u.unlock() 134 i := C.CString(id) 135 defer freeCharPtr(i) 136 return u.newDevice(C.udev_device_new_from_device_id(u.ptr, i)) 137 } 138 139 // NewEnumerate returns a pointer to a new enumerate, and nil on error 140 func (u *Udev) NewEnumerate() *Enumerate { 141 u.lock() 142 defer u.unlock() 143 return u.newEnumerate(C.udev_enumerate_new(u.ptr)) 144 } 145 146 // NewMonitorFromNetlink returns a pointer to a new monitor listening to a NetLink socket, and nil on error 147 // The name argument is either "kernel" or "udev". 148 // When passing "kernel" the events are received before they are processed by udev. 149 // When passing "udev" the events are received after udev has processed the events and created device nodes. 150 // In most cases you will want to use "udev". 151 func (u *Udev) NewMonitorFromNetlink(name string) *Monitor { 152 u.lock() 153 defer u.unlock() 154 n := C.CString(name) 155 defer freeCharPtr(n) 156 return u.newMonitor(C.udev_monitor_new_from_netlink(u.ptr, n)) 157 } 158 159 /* 160 // NewMonitorFromSocket returns a pointer to a new monitor listening to the specified socket, and nil on error 161 func (u *Udev) NewMonitorFromSocket(socketPath string) *Monitor { 162 u.lock() 163 defer u.unlock() 164 s := C.CString(socketPath) 165 defer freeCharPtr(s) 166 return u.newMonitor(C.udev_monitor_new_from_socket(u.ptr, s)) 167 } 168 */