From 8c7109a2d58c40b86ad97ed520aff6b00bbf1667 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 26 May 2026 19:16:32 +0900 Subject: cmd/earlyinit: mount system device This currently relies on a trusted bootloader to determine the boot device. Signed-off-by: Ophestra --- cmd/earlyinit/uevent.go | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 cmd/earlyinit/uevent.go (limited to 'cmd/earlyinit/uevent.go') diff --git a/cmd/earlyinit/uevent.go b/cmd/earlyinit/uevent.go new file mode 100644 index 00000000..0ab134cf --- /dev/null +++ b/cmd/earlyinit/uevent.go @@ -0,0 +1,103 @@ +package main + +import ( + "context" + "log" + "time" + + "hakurei.app/fhs" + "hakurei.app/internal/report" + "hakurei.app/internal/uevent" +) + +// newRejectColdboot returns a function to be called on every subsequent pending +// coldboot, and returns whether coldboot should proceed. Rejection is sticky. +func newRejectColdboot() func() bool { + // one coldboot per five minutes, two consecutive coldboot + const ( + coldbootInterval = 5 * time.Minute + coldbootBurst = 2 + ) + + done := make(chan struct{}) + s := make(chan struct{}, coldbootBurst) + s <- struct{}{} // for early fault before reporting is ready + go func() { + t := time.NewTicker(coldbootInterval) + for { + select { + case <-done: + return + + case <-t.C: + select { + case s <- struct{}{}: + default: + } + } + } + }() + + return func() bool { + select { + case <-s: + return true + + case <-done: + return false + + default: + close(done) + return false + } + } +} + +// consume continuously consumes events from conn with retries. +func consume( + ctx context.Context, + r *report.Reporter, + conn *uevent.Conn, + uuid uevent.UUID, + events chan<- *uevent.Message, +) { + defer close(events) + + nextColdboot := newRejectColdboot() + coldboot := true +retry: + if dispatchErr := conn.Consume(ctx, fhs.Sys, &uuid, events, coldboot, func(path string) { + log.Println("coldboot visited", path) + }, func(err error) bool { + if _, ok := err.(uevent.NeedsColdboot); ok && !nextColdboot() { + r.Dispatch( + report.Degraded, + "rejecting coldboot loop", + err, + ) + return false + } + r.Dispatch( + report.Inconsistent, + "consumed invalid message", + err, + ) + return true + }, nil); dispatchErr != nil { + if _, ok := dispatchErr.(uevent.Recoverable); !ok { + r.Dispatch( + report.Fatal, + "discontinuing uevent processing due to nonrecoverable error", + dispatchErr, + ) + return + } + + if _, ok := dispatchErr.(uevent.NeedsColdboot); ok { + // coldboot loop rejected by handler + coldboot = false + } + + goto retry + } +} -- cgit v1.3.1