usb-ks

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

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 */