internal/uevent: optionally pass UUID during coldboot
All checks were successful
Test / Create distribution (push) Successful in 1m3s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 3m49s
Test / ShareFS (push) Successful in 3m47s
Test / Sandbox (race detector) (push) Successful in 5m12s
Test / Hakurei (race detector) (push) Successful in 6m20s
Test / Flake checks (push) Successful in 1m20s
All checks were successful
Test / Create distribution (push) Successful in 1m3s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 3m49s
Test / ShareFS (push) Successful in 3m47s
Test / Sandbox (race detector) (push) Successful in 5m12s
Test / Hakurei (race detector) (push) Successful in 6m20s
Test / Flake checks (push) Successful in 1m20s
This enables rejection of non-coldboot synthetic events. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -5,10 +5,14 @@ package uevent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"hakurei.app/internal/netlink"
|
||||
)
|
||||
@@ -121,6 +125,117 @@ func (c *Conn) receiveEvent(ctx context.Context) (*Message, error) {
|
||||
return &msg, err
|
||||
}
|
||||
|
||||
// UUID represents the value of SYNTH_UUID.
|
||||
//
|
||||
// This is not a generic UUID implementation. Do not attempt to use it for
|
||||
// anything other than passing and interpreting the SYNTH_UUID environment
|
||||
// variable of a uevent.
|
||||
type UUID [16]byte
|
||||
|
||||
const (
|
||||
// SizeUUID is the fixed size of string representation of [UUID] according
|
||||
// to Documentation/ABI/testing/sysfs-uevent.
|
||||
SizeUUID = 4 + len(UUID{})*2
|
||||
|
||||
// UUIDSep is the separator byte of [UUID].
|
||||
UUIDSep = '-'
|
||||
)
|
||||
|
||||
var (
|
||||
_ encoding.TextAppender = new(UUID)
|
||||
_ encoding.TextMarshaler = new(UUID)
|
||||
_ encoding.TextUnmarshaler = new(UUID)
|
||||
)
|
||||
|
||||
// String formats uuid according to Documentation/ABI/testing/sysfs-uevent.
|
||||
func (uuid *UUID) String() string {
|
||||
s := make([]byte, 0, SizeUUID)
|
||||
s = hex.AppendEncode(s, uuid[:4])
|
||||
s = append(s, UUIDSep)
|
||||
s = hex.AppendEncode(s, uuid[4:6])
|
||||
s = append(s, UUIDSep)
|
||||
s = hex.AppendEncode(s, uuid[6:8])
|
||||
s = append(s, UUIDSep)
|
||||
s = hex.AppendEncode(s, uuid[8:10])
|
||||
s = append(s, UUIDSep)
|
||||
s = hex.AppendEncode(s, uuid[10:16])
|
||||
return unsafe.String(unsafe.SliceData(s), len(s))
|
||||
}
|
||||
|
||||
func (uuid *UUID) AppendText(data []byte) ([]byte, error) {
|
||||
return append(data, uuid.String()...), nil
|
||||
}
|
||||
func (uuid *UUID) MarshalText() ([]byte, error) {
|
||||
return uuid.AppendText(nil)
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrAutoUUID is returned parsing a SYNTH_UUID generated by the kernel for
|
||||
// a synthetic event without a UUID passed in.
|
||||
ErrAutoUUID = errors.New("UUID is not passed in")
|
||||
)
|
||||
|
||||
// UUIDSizeError describes an incorrectly sized string representation of [UUID].
|
||||
type UUIDSizeError int
|
||||
|
||||
func (e UUIDSizeError) Error() string {
|
||||
return "got " + strconv.Itoa(int(e)) + " bytes " +
|
||||
"instead of " + strconv.Itoa(SizeUUID)
|
||||
}
|
||||
|
||||
// UUIDSeparatorError is an invalid separator in a malformed string
|
||||
// representation of [UUID].
|
||||
type UUIDSeparatorError byte
|
||||
|
||||
func (e UUIDSeparatorError) Error() string {
|
||||
return fmt.Sprintf("invalid UUID separator: %#U", rune(e))
|
||||
}
|
||||
|
||||
// UnmarshalText parses data according to Documentation/ABI/testing/sysfs-uevent.
|
||||
func (uuid *UUID) UnmarshalText(data []byte) (err error) {
|
||||
if len(data) == 1 && data[0] == '0' {
|
||||
return ErrAutoUUID
|
||||
}
|
||||
if len(data) != SizeUUID {
|
||||
return UUIDSizeError(len(data))
|
||||
}
|
||||
|
||||
if _, err = hex.Decode(uuid[:], data[:8]); err != nil {
|
||||
return
|
||||
}
|
||||
if data[8] != UUIDSep {
|
||||
return UUIDSeparatorError(data[8])
|
||||
}
|
||||
data = data[9:]
|
||||
|
||||
if _, err = hex.Decode(uuid[4:], data[:4]); err != nil {
|
||||
return
|
||||
}
|
||||
if data[4] != UUIDSep {
|
||||
return UUIDSeparatorError(data[4])
|
||||
}
|
||||
data = data[5:]
|
||||
|
||||
if _, err = hex.Decode(uuid[6:], data[:4]); err != nil {
|
||||
return
|
||||
}
|
||||
if data[4] != UUIDSep {
|
||||
return UUIDSeparatorError(data[4])
|
||||
}
|
||||
data = data[5:]
|
||||
|
||||
if _, err = hex.Decode(uuid[8:], data[:4]); err != nil {
|
||||
return
|
||||
}
|
||||
if data[4] != UUIDSep {
|
||||
return UUIDSeparatorError(data[4])
|
||||
}
|
||||
data = data[5:]
|
||||
|
||||
_, err = hex.Decode(uuid[10:], data)
|
||||
return
|
||||
}
|
||||
|
||||
// Consume continuously receives and parses events from the kernel and handles
|
||||
// [Recoverable] and [NeedsColdboot] errors via caller-supplied functions,
|
||||
// entering coldboot when required.
|
||||
@@ -145,6 +260,7 @@ func (c *Conn) receiveEvent(ctx context.Context) (*Message, error) {
|
||||
func (c *Conn) Consume(
|
||||
ctx context.Context,
|
||||
sysfs string,
|
||||
uuid *UUID,
|
||||
events chan<- *Message,
|
||||
coldboot bool,
|
||||
|
||||
@@ -193,7 +309,7 @@ coldboot:
|
||||
ctxColdboot, cancelColdboot := context.WithCancel(ctx)
|
||||
var coldbootErr error
|
||||
go func() {
|
||||
coldbootErr = Coldboot(ctxColdboot, sysfs, visited, handleWalkErr)
|
||||
coldbootErr = Coldboot(ctxColdboot, sysfs, uuid, visited, handleWalkErr)
|
||||
close(visited)
|
||||
}()
|
||||
for pathname := range visited {
|
||||
|
||||
Reference in New Issue
Block a user