/
device_utils_unix_hotplug_events.go
119 lines (99 loc) · 3.68 KB
/
device_utils_unix_hotplug_events.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package device
import (
"fmt"
"strconv"
"strings"
"sync"
deviceConfig "github.com/lxc/lxd/lxd/device/config"
"github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/lxd/state"
"github.com/lxc/lxd/shared/logger"
)
// UnixHotplugEvent represents the properties of a Unix hotplug device uevent.
type UnixHotplugEvent struct {
Action string
Vendor string
Product string
Path string
Major uint32
Minor uint32
Subsystem string
UeventParts []string
UeventLen int
}
// unixHotplugHandlers stores the event handler callbacks for Unix hotplug events.
var unixHotplugHandlers = map[string]func(UnixHotplugEvent) (*deviceConfig.RunConfig, error){}
// unixHotplugMutex controls access to the unixHotplugHandlers map.
var unixHotplugMutex sync.Mutex
// unixHotplugRegisterHandler registers a handler function to be called whenever a Unix hotplug device event occurs.
func unixHotplugRegisterHandler(instance instance.Instance, deviceName string, handler func(UnixHotplugEvent) (*deviceConfig.RunConfig, error)) {
unixHotplugMutex.Lock()
defer unixHotplugMutex.Unlock()
// Null delimited string of project name, instance name and device name.
key := fmt.Sprintf("%s\000%s\000%s", instance.Project().Name, instance.Name(), deviceName)
unixHotplugHandlers[key] = handler
}
// unixHotplugUnregisterHandler removes a registered Unix hotplug handler function for a device.
func unixHotplugUnregisterHandler(instance instance.Instance, deviceName string) {
unixHotplugMutex.Lock()
defer unixHotplugMutex.Unlock()
// Null delimited string of project name, instance name and device name.
key := fmt.Sprintf("%s\000%s\000%s", instance.Project().Name, instance.Name(), deviceName)
delete(unixHotplugHandlers, key)
}
// UnixHotplugRunHandlers executes any handlers registered for Unix hotplug events.
func UnixHotplugRunHandlers(state *state.State, event *UnixHotplugEvent) {
unixHotplugMutex.Lock()
defer unixHotplugMutex.Unlock()
for key, hook := range unixHotplugHandlers {
keyParts := strings.SplitN(key, "\000", 3)
projectName := keyParts[0]
instanceName := keyParts[1]
deviceName := keyParts[2]
if hook == nil {
delete(unixHotplugHandlers, key)
continue
}
runConf, err := hook(*event)
if err != nil {
logger.Error("Unix hotplug event hook failed", logger.Ctx{"err": err, "project": projectName, "instance": instanceName, "device": deviceName})
continue
}
// If runConf supplied, load instance and call its Unix hotplug event handler function so
// any instance specific device actions can occur.
if runConf != nil {
instance, err := instance.LoadByProjectAndName(state, projectName, instanceName)
if err != nil {
logger.Error("Unix hotplug event loading instance failed", logger.Ctx{"err": err, "project": projectName, "instance": instanceName, "device": deviceName})
continue
}
err = instance.DeviceEventHandler(runConf)
if err != nil {
logger.Error("Unix hotplug event instance handler failed", logger.Ctx{"err": err, "project": projectName, "instance": instanceName, "device": deviceName})
continue
}
}
}
}
// UnixHotplugNewEvent instantiates a new UnixHotplugEvent struct.
func UnixHotplugNewEvent(action string, vendor string, product string, major string, minor string, subsystem string, devname string, ueventParts []string, ueventLen int) (UnixHotplugEvent, error) {
majorInt, err := strconv.ParseUint(major, 10, 32)
if err != nil {
return UnixHotplugEvent{}, err
}
minorInt, err := strconv.ParseUint(minor, 10, 32)
if err != nil {
return UnixHotplugEvent{}, err
}
return UnixHotplugEvent{
action,
vendor,
product,
devname,
uint32(majorInt),
uint32(minorInt),
subsystem,
ueventParts,
ueventLen,
}, nil
}