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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
package uevent
import (
"bytes"
"strconv"
"strings"
)
// A Message represents a kernel message to userspace.
type Message struct {
// alloc_uevent_skb: action_string
Action KobjectAction `json:"action"`
// alloc_uevent_skb: devpath
DevPath string `json:"devpath"`
// add_uevent_var: key value strings
Env []string `json:"env"`
}
// String returns a multiline user-facing string representation of [Message].
func (msg *Message) String() string {
var buf strings.Builder
buf.WriteString(msg.Action.String() + " event")
if msg.DevPath != "" {
buf.WriteString(" on " + msg.DevPath)
}
buf.WriteString(":")
for _, s := range msg.Env {
buf.WriteString("\n" + s)
}
return buf.String()
}
var (
// zero is a single pre-allocated NUL character.
zero = []byte{0}
// sepHeader is the separator in a [Message] header.
sepHeader = []byte{'@'}
)
func (msg *Message) AppendBinary(b []byte) (_ []byte, err error) {
if b, err = msg.Action.AppendText(b); err != nil {
return
}
b = append(b, sepHeader...)
b = append(b, msg.DevPath...)
b = append(b, zero...)
for _, s := range msg.Env {
b = append(b, s...)
b = append(b, zero...)
}
return b, nil
}
func (msg *Message) MarshalBinary() ([]byte, error) {
return msg.AppendBinary(nil)
}
// MissingHeaderError is an invalid representation of [Message] which is missing
// its header added by alloc_uevent_skb.
type MissingHeaderError string
var _ Recoverable = MissingHeaderError("")
func (MissingHeaderError) recoverable() {}
func (e MissingHeaderError) Error() string {
return "message " + strconv.Quote(string(e)) + " has no header"
}
// MessageError describes a malformed representation of [Message].
type MessageError struct {
// Full offending data.
Data string `json:"data"`
// Offending section.
Section string `json:"section"`
// Part of header in Section.
Kind int `json:"kind"`
}
var _ Recoverable = new(MessageError)
var _ Nontrivial = new(MessageError)
const (
// MErrorKindHeaderSep denotes a message header missing its separator.
MErrorKindHeaderSep = iota
// MErrorKindFinalNUL denotes a message body missing its final NUL terminator.
MErrorKindFinalNUL
)
func (*MessageError) recoverable() {}
func (*MessageError) nontrivial() {}
func (e *MessageError) Error() string {
switch e.Kind {
case MErrorKindHeaderSep:
return "header " + strconv.Quote(e.Section) + " missing separator"
case MErrorKindFinalNUL:
return "entry " + strconv.Quote(e.Section) + " missing NUL"
default:
return "section " + strconv.Quote(e.Section) + " is invalid"
}
}
func (msg *Message) UnmarshalBinary(data []byte) error {
header, body, ok := bytes.Cut(data, zero)
if !ok {
return MissingHeaderError(data)
}
action_string, devpath, ok := bytes.Cut(header, sepHeader)
if !ok {
return &MessageError{string(data), string(header), MErrorKindHeaderSep}
}
if err := msg.Action.UnmarshalText(action_string); err != nil {
return err
}
msg.DevPath = string(devpath)
if len(body) == 0 {
msg.Env = nil
return nil
}
msg.Env = make([]string, 0, bytes.Count(body, zero))
var s []byte
for len(body) != 0 {
var r []byte
s, r, ok = bytes.Cut(body, zero)
if !ok {
return &MessageError{string(data), string(body), MErrorKindFinalNUL}
}
body = r
msg.Env = append(msg.Env, string(s))
}
return nil
}
|