File: device_utils_unix_hotplug_events.go

package info (click to toggle)
incus 6.0.5-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 25,788 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (119 lines) | stat: -rw-r--r-- 3,823 bytes parent folder | download | duplicates (7)
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/incus/v6/internal/server/device/config"
	"github.com/lxc/incus/v6/internal/server/instance"
	"github.com/lxc/incus/v6/internal/server/state"
	"github.com/lxc/incus/v6/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
}