usb-ks

USB Killswitch
git clone git://git.laack.co/usb-ks.git
Log | Files | Refs | README | LICENSE

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 }