enumerate.go (8994B)
1 // +build linux,cgo 2 3 package udev 4 5 /* 6 #cgo LDFLAGS: -ludev 7 #include <libudev.h> 8 #include <linux/types.h> 9 #include <stdlib.h> 10 #include <linux/kdev_t.h> 11 */ 12 import "C" 13 14 import ( 15 "errors" 16 17 "github.com/jkeiser/iter" 18 ) 19 20 // Enumerate is an opaque struct wrapping a udev enumerate object. 21 type Enumerate struct { 22 ptr *C.struct_udev_enumerate 23 u *Udev 24 } 25 26 // Lock the udev context 27 func (e *Enumerate) lock() { 28 e.u.m.Lock() 29 } 30 31 // Unlock the udev context 32 func (e *Enumerate) unlock() { 33 e.u.m.Unlock() 34 } 35 36 // Unref the Enumerate object 37 func enumerateUnref(e *Enumerate) { 38 C.udev_enumerate_unref(e.ptr) 39 } 40 41 // AddMatchSubsystem adds a filter for a subsystem of the device to include in the list. 42 func (e *Enumerate) AddMatchSubsystem(subsystem string) (err error) { 43 e.lock() 44 defer e.unlock() 45 s := C.CString(subsystem) 46 defer freeCharPtr(s) 47 if C.udev_enumerate_add_match_subsystem(e.ptr, s) != 0 { 48 err = errors.New("udev: udev_enumerate_add_match_subsystem failed") 49 } 50 return 51 } 52 53 // AddNomatchSubsystem adds a filter for a subsystem of the device to exclude from the list. 54 func (e *Enumerate) AddNomatchSubsystem(subsystem string) (err error) { 55 e.lock() 56 defer e.unlock() 57 s := C.CString(subsystem) 58 defer freeCharPtr(s) 59 if C.udev_enumerate_add_nomatch_subsystem(e.ptr, s) != 0 { 60 err = errors.New("udev: udev_enumerate_add_nomatch_subsystem failed") 61 } 62 return 63 } 64 65 // AddMatchSysattr adds a filter for a sys attribute at the device to include in the list. 66 func (e *Enumerate) AddMatchSysattr(sysattr, value string) (err error) { 67 e.lock() 68 defer e.unlock() 69 s, v := C.CString(sysattr), C.CString(value) 70 defer freeCharPtr(s) 71 defer freeCharPtr(v) 72 if C.udev_enumerate_add_match_sysattr(e.ptr, s, v) != 0 { 73 err = errors.New("udev: udev_enumerate_add_match_sysattr failed") 74 } 75 return 76 } 77 78 // AddNomatchSysattr adds a filter for a sys attribute at the device to exclude from the list. 79 func (e *Enumerate) AddNomatchSysattr(sysattr, value string) (err error) { 80 e.lock() 81 defer e.unlock() 82 s, v := C.CString(sysattr), C.CString(value) 83 defer freeCharPtr(s) 84 defer freeCharPtr(v) 85 if C.udev_enumerate_add_nomatch_sysattr(e.ptr, s, v) != 0 { 86 err = errors.New("udev: udev_enumerate_add_nomatch_sysattr failed") 87 } 88 return 89 } 90 91 // AddMatchProperty adds a filter for a property of the device to include in the list. 92 func (e *Enumerate) AddMatchProperty(property, value string) (err error) { 93 e.lock() 94 defer e.unlock() 95 p, v := C.CString(property), C.CString(value) 96 defer freeCharPtr(p) 97 defer freeCharPtr(v) 98 if C.udev_enumerate_add_match_property(e.ptr, p, v) != 0 { 99 err = errors.New("udev: udev_enumerate_add_match_property failed") 100 } 101 return 102 } 103 104 // AddMatchSysname adds a filter for the name of the device to include in the list. 105 func (e *Enumerate) AddMatchSysname(sysname string) (err error) { 106 e.lock() 107 defer e.unlock() 108 s := C.CString(sysname) 109 defer freeCharPtr(s) 110 if C.udev_enumerate_add_match_sysname(e.ptr, s) != 0 { 111 err = errors.New("udev: udev_enumerate_add_match_sysname failed") 112 } 113 return 114 } 115 116 // AddMatchTag adds a filter for a tag of the device to include in the list. 117 func (e *Enumerate) AddMatchTag(tag string) (err error) { 118 e.lock() 119 defer e.unlock() 120 t := C.CString(tag) 121 defer freeCharPtr(t) 122 if C.udev_enumerate_add_match_tag(e.ptr, t) != 0 { 123 err = errors.New("udev: udev_enumerate_add_match_tag failed") 124 } 125 return 126 } 127 128 // AddMatchParent adds a filter for a parent Device to include in the list. 129 func (e *Enumerate) AddMatchParent(parent *Device) (err error) { 130 e.lock() 131 defer e.unlock() 132 if C.udev_enumerate_add_match_parent(e.ptr, parent.ptr) != 0 { 133 err = errors.New("udev: udev_enumerate_add_match_parent failed") 134 } 135 return 136 } 137 138 // AddMatchIsInitialized adds a filter matching only devices which udev has set up already. 139 // This makes sure, that the device node permissions and context are properly set and that network devices are fully renamed. 140 // Usually, devices which are found in the kernel but not already handled by udev, have still pending events. 141 // Services should subscribe to monitor events and wait for these devices to become ready, instead of using uninitialized devices. 142 // For now, this will not affect devices which do not have a device node and are not network interfaces. 143 func (e *Enumerate) AddMatchIsInitialized() (err error) { 144 e.lock() 145 defer e.unlock() 146 if C.udev_enumerate_add_match_is_initialized(e.ptr) != 0 { 147 err = errors.New("udev: udev_enumerate_add_match_is_initialized failed") 148 } 149 return 150 } 151 152 // AddSyspath adds a device to the list of enumerated devices, to retrieve it back sorted in dependency order. 153 func (e *Enumerate) AddSyspath(syspath string) (err error) { 154 e.lock() 155 defer e.unlock() 156 s := C.CString(syspath) 157 defer freeCharPtr(s) 158 if C.udev_enumerate_add_syspath(e.ptr, s) != 0 { 159 err = errors.New("udev: udev_enumerate_add_syspath failed") 160 } 161 return 162 } 163 164 // DeviceSyspaths retrieves a list of device syspaths matching the filter, sorted in dependency order. 165 func (e *Enumerate) DeviceSyspaths() (s []string, err error) { 166 e.lock() 167 defer e.unlock() 168 if C.udev_enumerate_scan_devices(e.ptr) < 0 { 169 err = errors.New("udev: udev_enumerate_scan_devices failed") 170 } else { 171 s = make([]string, 0) 172 for l := C.udev_enumerate_get_list_entry(e.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 173 s = append(s, C.GoString(C.udev_list_entry_get_name(l))) 174 } 175 } 176 return 177 } 178 179 // DeviceSyspathIterator returns an Iterator over the device syspaths matching the filter, sorted in dependency order. 180 // The Iterator is using the github.com/jkeiser/iter package. 181 // Values are returned as an interface{} and should be cast to string. 182 func (e *Enumerate) DeviceSyspathIterator() (it iter.Iterator, err error) { 183 e.lock() 184 defer e.unlock() 185 if C.udev_enumerate_scan_devices(e.ptr) < 0 { 186 err = errors.New("udev: udev_enumerate_scan_devices failed") 187 } else { 188 l := C.udev_enumerate_get_list_entry(e.ptr) 189 it = iter.Iterator{ 190 Next: func() (item interface{}, err error) { 191 e.lock() 192 defer e.unlock() 193 if l != nil { 194 item = C.GoString(C.udev_list_entry_get_name(l)) 195 l = C.udev_list_entry_get_next(l) 196 } else { 197 err = iter.FINISHED 198 } 199 return 200 }, 201 Close: func() { 202 }, 203 } 204 } 205 return 206 } 207 208 // SubsystemSyspaths retrieves a list of subsystem syspaths matching the filter, sorted in dependency order. 209 func (e *Enumerate) SubsystemSyspaths() (s []string, err error) { 210 e.lock() 211 defer e.unlock() 212 if C.udev_enumerate_scan_subsystems(e.ptr) < 0 { 213 err = errors.New("udev: udev_enumerate_scan_subsystems failed") 214 } else { 215 s = make([]string, 0) 216 for l := C.udev_enumerate_get_list_entry(e.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 217 s = append(s, C.GoString(C.udev_list_entry_get_name(l))) 218 } 219 } 220 return 221 } 222 223 // DeviceSubsystemIterator returns an Iterator over the subsystem syspaths matching the filter, sorted in dependency order. 224 // The Iterator is using the github.com/jkeiser/iter package. 225 // Values are returned as an interface{} and should be cast to string. 226 func (e *Enumerate) DeviceSubsystemIterator() (it iter.Iterator, err error) { 227 e.lock() 228 defer e.unlock() 229 if C.udev_enumerate_scan_subsystems(e.ptr) < 0 { 230 err = errors.New("udev: udev_enumerate_scan_devices failed") 231 } else { 232 l := C.udev_enumerate_get_list_entry(e.ptr) 233 it = iter.Iterator{ 234 Next: func() (item interface{}, err error) { 235 e.lock() 236 defer e.unlock() 237 if l != nil { 238 item = C.GoString(C.udev_list_entry_get_name(l)) 239 l = C.udev_list_entry_get_next(l) 240 } else { 241 err = iter.FINISHED 242 } 243 return 244 }, 245 Close: func() { 246 }, 247 } 248 } 249 return 250 } 251 252 // Devices retrieves a list of Devices matching the filter, sorted in dependency order. 253 func (e *Enumerate) Devices() (m []*Device, err error) { 254 e.lock() 255 defer e.unlock() 256 if C.udev_enumerate_scan_devices(e.ptr) < 0 { 257 err = errors.New("udev: udev_enumerate_scan_devices failed") 258 } else { 259 m = make([]*Device, 0) 260 for l := C.udev_enumerate_get_list_entry(e.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 261 s := C.udev_list_entry_get_name(l) 262 m = append(m, e.u.newDevice(C.udev_device_new_from_syspath(e.u.ptr, s))) 263 } 264 } 265 return 266 } 267 268 // DeviceIterator returns an Iterator over the Devices matching the filter, sorted in dependency order. 269 // The Iterator is using the github.com/jkeiser/iter package. 270 // Values are returned as an interface{} and should be cast to *Device. 271 func (e *Enumerate) DeviceIterator() (it iter.Iterator, err error) { 272 e.lock() 273 defer e.unlock() 274 if C.udev_enumerate_scan_devices(e.ptr) < 0 { 275 err = errors.New("udev: udev_enumerate_scan_devices failed") 276 } else { 277 l := C.udev_enumerate_get_list_entry(e.ptr) 278 it = iter.Iterator{ 279 Next: func() (item interface{}, err error) { 280 e.lock() 281 defer e.unlock() 282 if l != nil { 283 s := C.udev_list_entry_get_name(l) 284 item = e.u.newDevice(C.udev_device_new_from_syspath(e.u.ptr, s)) 285 l = C.udev_list_entry_get_next(l) 286 } else { 287 err = iter.FINISHED 288 } 289 return 290 }, 291 Close: func() { 292 }, 293 } 294 } 295 return 296 }