aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/uevent/coldboot.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-03-30 21:20:42 +0900
committerOphestra <cat@gensokyo.uk>2026-03-30 23:01:08 +0900
commitf03c0fb249ea8787ae8ec086970eb089109ebf6f (patch)
tree5e89ba203112c5e3ca984da96b9dc60be19ade2a /internal/uevent/coldboot.go
parenta6600be34ad812ff13c89f45c3cadaac6d994e67 (diff)
internal/uevent: synthetic events for coldboot
This causes the kernel to regenerate events that happened before earlyinit started. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/uevent/coldboot.go')
-rw-r--r--internal/uevent/coldboot.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/internal/uevent/coldboot.go b/internal/uevent/coldboot.go
new file mode 100644
index 00000000..07f6497f
--- /dev/null
+++ b/internal/uevent/coldboot.go
@@ -0,0 +1,71 @@
+package uevent
+
+import (
+ "context"
+ "errors"
+ "io/fs"
+ "log"
+ "os"
+ "path/filepath"
+)
+
+// synthAdd is prepared bytes written to uevent to cause a synthetic add event
+// to be emitted during coldboot.
+var synthAdd = []byte(KOBJ_ADD.String())
+
+// Coldboot writes "add" to every uevent file that it finds in /sys/devices.
+// This causes the kernel to regenerate the uevents for these paths.
+//
+// The specified pathname must present the sysfs root.
+//
+// Note that while [AOSP documentation] claims to also scan /sys/class and
+// /sys/block, this is no longer the case, and the documentation was not updated
+// when this changed.
+//
+// [AOSP documentation]: https://android.googlesource.com/platform/system/core/+/master/init/README.ueventd.md
+func Coldboot(
+ ctx context.Context,
+ pathname string,
+ visited chan<- string,
+ handleWalkErr func(error) error,
+) error {
+ if handleWalkErr == nil {
+ handleWalkErr = func(err error) error {
+ if errors.Is(err, fs.ErrNotExist) {
+ log.Println("coldboot", err)
+ return nil
+ }
+ return err
+ }
+ }
+
+ return filepath.WalkDir(filepath.Join(pathname, "devices"), func(
+ path string,
+ d fs.DirEntry,
+ err error,
+ ) error {
+ if err != nil {
+ return handleWalkErr(err)
+ }
+ if err = ctx.Err(); err != nil {
+ return err
+ }
+
+ if d.IsDir() || d.Name() != "uevent" {
+ return nil
+ }
+ if err = os.WriteFile(path, synthAdd, 0); err != nil {
+ return handleWalkErr(err)
+ }
+
+ select {
+ case visited <- path:
+ break
+
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+
+ return nil
+ })
+}