aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/kobject/event.go
blob: 33cb91b8c371d059ca574d1d48b4818801710c34 (plain)
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
package kobject

import (
	"errors"
	"strconv"
	"strings"
	"unsafe"

	"hakurei.app/internal/uevent"
)

// Event is a [uevent.Message] with known environment variables processed.
type Event struct {
	// alloc_uevent_skb: action_string
	Action uevent.KobjectAction `json:"action"`
	// alloc_uevent_skb: devpath
	DevPath string `json:"devpath"`

	// Uninterpreted environment variable pairs. An entry missing a separator
	// gains the value "\x00".
	Env map[string]string `json:"env"`

	// SEQNUM value set by the kernel.
	Sequence uint64 `json:"seqnum"`
	// SYNTH_UUID value set on trigger, nil denotes a non-synthetic event.
	Synth *uevent.UUID `json:"synth_uuid,omitempty"`
	// SUBSYSTEM value set by the kernel.
	Subsystem string `json:"subsystem"`
}

// Populate populates e with the contents of a [uevent.Message].
//
// The ACTION and DEVPATH environment variables are ignored and assumed to be
// consistent with the header.
func (e *Event) Populate(reportErr func(error), m *uevent.Message) {
	if reportErr == nil {
		reportErr = func(error) {}
	}

	*e = Event{
		Action:  m.Action,
		DevPath: m.DevPath,
		Env:     make(map[string]string),
	}

	for _, s := range m.Env {
		k, v, ok := strings.Cut(s, "=")
		if !ok {
			if _, ok = e.Env[s]; !ok {
				e.Env[s] = "\x00"
			}
			continue
		}

		switch k {
		case "ACTION", "DEVPATH":
			continue

		case "SEQNUM":
			seq, err := strconv.ParseUint(v, 10, 64)
			if err != nil {
				if _e := errors.Unwrap(err); _e != nil {
					err = _e
				}
				reportErr(err)

				e.Env[k] = v
				continue
			}
			e.Sequence = seq

		case "SYNTH_UUID":
			var uuid uevent.UUID
			err := uuid.UnmarshalText(unsafe.Slice(unsafe.StringData(v), len(v)))
			if err != nil {
				reportErr(err)

				e.Env[k] = v
				continue
			}
			e.Synth = &uuid

		case "SUBSYSTEM":
			e.Subsystem = v

		default:
			e.Env[k] = v
		}
	}
}