device.go (10221B)
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 import "errors" 14 import "github.com/jkeiser/iter" 15 16 // Device wraps a libudev device object 17 type Device struct { 18 ptr *C.struct_udev_device 19 u *Udev 20 } 21 22 // Lock the udev context 23 func (d *Device) lock() { 24 d.u.m.Lock() 25 } 26 27 // Unlock the udev context 28 func (d *Device) unlock() { 29 d.u.m.Unlock() 30 } 31 32 func deviceUnref(d *Device) { 33 C.udev_device_unref(d.ptr) 34 } 35 36 // Parent returns the parent Device, or nil if the receiver has no parent Device 37 func (d *Device) Parent() *Device { 38 d.lock() 39 defer d.unlock() 40 ptr := C.udev_device_get_parent(d.ptr) 41 if ptr != nil { 42 C.udev_device_ref(ptr) 43 } 44 return d.u.newDevice(ptr) 45 } 46 47 // ParentWithSubsystemDevtype returns the parent Device with the given subsystem and devtype, 48 // or nil if the receiver has no such parent device 49 func (d *Device) ParentWithSubsystemDevtype(subsystem, devtype string) *Device { 50 d.lock() 51 defer d.unlock() 52 ss, dt := C.CString(subsystem), C.CString(devtype) 53 defer freeCharPtr(ss) 54 defer freeCharPtr(dt) 55 ptr := C.udev_device_get_parent_with_subsystem_devtype(d.ptr, ss, dt) 56 if ptr != nil { 57 C.udev_device_ref(ptr) 58 } 59 return d.u.newDevice(ptr) 60 } 61 62 // Devpath returns the kernel devpath value of the udev device. 63 // The path does not contain the sys mount point, and starts with a '/'. 64 func (d *Device) Devpath() string { 65 d.lock() 66 defer d.unlock() 67 return C.GoString(C.udev_device_get_devpath(d.ptr)) 68 } 69 70 // Subsystem returns the subsystem string of the udev device. 71 // The string does not contain any "/". 72 func (d *Device) Subsystem() string { 73 d.lock() 74 defer d.unlock() 75 return C.GoString(C.udev_device_get_subsystem(d.ptr)) 76 } 77 78 // Devtype returns the devtype string of the udev device. 79 func (d *Device) Devtype() string { 80 d.lock() 81 defer d.unlock() 82 return C.GoString(C.udev_device_get_devtype(d.ptr)) 83 } 84 85 // Sysname returns the sysname of the udev device (e.g. ttyS3, sda1...). 86 func (d *Device) Sysname() string { 87 d.lock() 88 defer d.unlock() 89 return C.GoString(C.udev_device_get_sysname(d.ptr)) 90 } 91 92 // Syspath returns the sys path of the udev device. 93 // The path is an absolute path and starts with the sys mount point. 94 func (d *Device) Syspath() string { 95 d.lock() 96 defer d.unlock() 97 return C.GoString(C.udev_device_get_syspath(d.ptr)) 98 } 99 100 // Sysnum returns the trailing number of of the device name 101 func (d *Device) Sysnum() string { 102 d.lock() 103 defer d.unlock() 104 return C.GoString(C.udev_device_get_sysnum(d.ptr)) 105 } 106 107 // Devnode returns the device node file name belonging to the udev device. 108 // The path is an absolute path, and starts with the device directory. 109 func (d *Device) Devnode() string { 110 d.lock() 111 defer d.unlock() 112 return C.GoString(C.udev_device_get_devnode(d.ptr)) 113 } 114 115 // IsInitialized checks if udev has already handled the device and has set up 116 // device node permissions and context, or has renamed a network device. 117 // 118 // This is only implemented for devices with a device node or network interfaces. 119 // All other devices return 1 here. 120 func (d *Device) IsInitialized() bool { 121 d.lock() 122 defer d.unlock() 123 return C.udev_device_get_is_initialized(d.ptr) != 0 124 } 125 126 // Devlinks retrieves the map of device links pointing to the device file of the udev device. 127 // The path is an absolute path, and starts with the device directory. 128 func (d *Device) Devlinks() (r map[string]struct{}) { 129 d.lock() 130 defer d.unlock() 131 r = make(map[string]struct{}) 132 for l := C.udev_device_get_devlinks_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 133 r[C.GoString(C.udev_list_entry_get_name(l))] = struct{}{} 134 } 135 return 136 } 137 138 // DevlinkIterator returns an Iterator over the device links pointing to the device file of the udev device. 139 // The Iterator is using the github.com/jkeiser/iter package. 140 // Values are returned as an interface{} and should be cast to string. 141 func (d *Device) DevlinkIterator() iter.Iterator { 142 d.lock() 143 defer d.unlock() 144 l := C.udev_device_get_devlinks_list_entry(d.ptr) 145 return iter.Iterator{ 146 Next: func() (item interface{}, err error) { 147 d.lock() 148 defer d.unlock() 149 if l != nil { 150 item = C.GoString(C.udev_list_entry_get_name(l)) 151 l = C.udev_list_entry_get_next(l) 152 } else { 153 err = iter.FINISHED 154 } 155 return 156 }, 157 Close: func() { 158 }, 159 } 160 } 161 162 // Properties retrieves a map[string]string of key/value device properties of the udev device. 163 func (d *Device) Properties() (r map[string]string) { 164 d.lock() 165 defer d.unlock() 166 r = make(map[string]string) 167 for l := C.udev_device_get_properties_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 168 r[C.GoString(C.udev_list_entry_get_name(l))] = C.GoString(C.udev_list_entry_get_value(l)) 169 } 170 return 171 } 172 173 // PropertyIterator returns an Iterator over the key/value device properties of the udev device. 174 // The Iterator is using the github.com/jkeiser/iter package. 175 // Values are returned as an interface{} and should be cast to []string, 176 // which will have length 2 and represent a Key/Value pair. 177 func (d *Device) PropertyIterator() iter.Iterator { 178 d.lock() 179 defer d.unlock() 180 l := C.udev_device_get_properties_list_entry(d.ptr) 181 return iter.Iterator{ 182 Next: func() (item interface{}, err error) { 183 d.lock() 184 defer d.unlock() 185 if l != nil { 186 item = []string{ 187 C.GoString(C.udev_list_entry_get_name(l)), 188 C.GoString(C.udev_list_entry_get_value(l)), 189 } 190 l = C.udev_list_entry_get_next(l) 191 } else { 192 err = iter.FINISHED 193 } 194 return 195 }, 196 Close: func() { 197 }, 198 } 199 } 200 201 // Tags retrieves the Set of tags attached to the udev device. 202 func (d *Device) Tags() (r map[string]struct{}) { 203 d.lock() 204 defer d.unlock() 205 r = make(map[string]struct{}) 206 for l := C.udev_device_get_tags_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 207 r[C.GoString(C.udev_list_entry_get_name(l))] = struct{}{} 208 } 209 return 210 } 211 212 // TagIterator returns an Iterator over the tags attached to the udev device. 213 // The Iterator is using the github.com/jkeiser/iter package. 214 // Values are returned as an interface{} and should be cast to string. 215 func (d *Device) TagIterator() iter.Iterator { 216 d.lock() 217 defer d.unlock() 218 l := C.udev_device_get_tags_list_entry(d.ptr) 219 return iter.Iterator{ 220 Next: func() (item interface{}, err error) { 221 d.lock() 222 defer d.unlock() 223 if l != nil { 224 item = C.GoString(C.udev_list_entry_get_name(l)) 225 l = C.udev_list_entry_get_next(l) 226 } else { 227 err = iter.FINISHED 228 } 229 return 230 }, 231 Close: func() { 232 }, 233 } 234 } 235 236 // Sysattrs returns a Set with the systems attributes of the udev device. 237 func (d *Device) Sysattrs() (r map[string]struct{}) { 238 d.lock() 239 defer d.unlock() 240 r = make(map[string]struct{}) 241 for l := C.udev_device_get_sysattr_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { 242 r[C.GoString(C.udev_list_entry_get_name(l))] = struct{}{} 243 } 244 return 245 } 246 247 // SysattrIterator returns an Iterator over the systems attributes of the udev device. 248 // The Iterator is using the github.com/jkeiser/iter package. 249 // Values are returned as an interface{} and should be cast to string. 250 func (d *Device) SysattrIterator() iter.Iterator { 251 d.lock() 252 defer d.unlock() 253 l := C.udev_device_get_sysattr_list_entry(d.ptr) 254 return iter.Iterator{ 255 Next: func() (item interface{}, err error) { 256 d.lock() 257 defer d.unlock() 258 if l != nil { 259 item = C.GoString(C.udev_list_entry_get_name(l)) 260 l = C.udev_list_entry_get_next(l) 261 } else { 262 err = iter.FINISHED 263 } 264 return 265 }, 266 Close: func() { 267 }, 268 } 269 } 270 271 // PropertyValue retrieves the value of a device property 272 func (d *Device) PropertyValue(key string) string { 273 d.lock() 274 defer d.unlock() 275 k := C.CString(key) 276 defer freeCharPtr(k) 277 return C.GoString(C.udev_device_get_property_value(d.ptr, k)) 278 } 279 280 // Driver returns the driver for the receiver 281 func (d *Device) Driver() string { 282 d.lock() 283 defer d.unlock() 284 return C.GoString(C.udev_device_get_driver(d.ptr)) 285 } 286 287 // Devnum returns the device major/minor number. 288 func (d *Device) Devnum() Devnum { 289 d.lock() 290 defer d.unlock() 291 return Devnum{C.udev_device_get_devnum(d.ptr)} 292 } 293 294 // Action returns the action for the event. 295 // This is only valid if the device was received through a monitor. 296 // Devices read from sys do not have an action string. 297 // Usual actions are: add, remove, change, online, offline. 298 func (d *Device) Action() string { 299 d.lock() 300 defer d.unlock() 301 return C.GoString(C.udev_device_get_action(d.ptr)) 302 } 303 304 // Seqnum returns the sequence number of the event. 305 // This is only valid if the device was received through a monitor. 306 // Devices read from sys do not have a sequence number. 307 func (d *Device) Seqnum() uint64 { 308 d.lock() 309 defer d.unlock() 310 return uint64(C.udev_device_get_seqnum(d.ptr)) 311 } 312 313 // UsecSinceInitialized returns the number of microseconds passed since udev set up the device for the first time. 314 // This is only implemented for devices with need to store properties in the udev database. 315 // All other devices return 0 here. 316 func (d *Device) UsecSinceInitialized() uint64 { 317 d.lock() 318 defer d.unlock() 319 return uint64(C.udev_device_get_usec_since_initialized(d.ptr)) 320 } 321 322 // SysattrValue retrieves the content of a sys attribute file, and returns an empty string if there is no sys attribute value. 323 // The retrieved value is cached in the device. 324 // Repeated calls will return the same value and not open the attribute again. 325 func (d *Device) SysattrValue(sysattr string) string { 326 d.lock() 327 defer d.unlock() 328 s := C.CString(sysattr) 329 defer freeCharPtr(s) 330 return C.GoString(C.udev_device_get_sysattr_value(d.ptr, s)) 331 } 332 333 // SetSysattrValue sets the content of a sys attribute file, and returns an error if this fails. 334 func (d *Device) SetSysattrValue(sysattr, value string) (err error) { 335 d.lock() 336 defer d.unlock() 337 sa, val := C.CString(sysattr), C.CString(value) 338 defer freeCharPtr(sa) 339 defer freeCharPtr(val) 340 if C.udev_device_set_sysattr_value(d.ptr, sa, val) < 0 { 341 err = errors.New("udev: udev_device_set_sysattr_value failed") 342 } 343 return 344 } 345 346 // HasTag checks if the udev device has the tag specified 347 func (d *Device) HasTag(tag string) bool { 348 d.lock() 349 defer d.unlock() 350 t := C.CString(tag) 351 defer freeCharPtr(t) 352 return C.udev_device_has_tag(d.ptr, t) != 0 353 }