From 085eaed7bae88a04c1dd45dfd4dcde8cfe3caf53 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 25 Feb 2026 16:37:42 +0900 Subject: [PATCH] cmd/earlyinit: early /dev/ and io setup This establishes an environment where devtmpfs is mounted, and if the kernel fails to set up console, 1 and 2 is pointed at /dev/kmsg. Signed-off-by: Ophestra --- cmd/earlyinit/main.go | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 cmd/earlyinit/main.go diff --git a/cmd/earlyinit/main.go b/cmd/earlyinit/main.go new file mode 100644 index 0000000..5301783 --- /dev/null +++ b/cmd/earlyinit/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "log" + "os" + "runtime" + . "syscall" +) + +func main() { + runtime.LockOSThread() + log.SetFlags(0) + log.SetPrefix("earlyinit: ") + + if err := Mount( + "devtmpfs", + "/dev/", + "devtmpfs", + MS_NOSUID|MS_NOEXEC, + "", + ); err != nil { + log.Fatalf("cannot mount devtmpfs: %v", err) + } + + // The kernel might be unable to set up the console. When that happens, + // printk is called with "Warning: unable to open an initial console." + // and the init runs with no files. The checkfds runtime function + // populates 0-2 by opening /dev/null for them. + // + // This check replaces 1 and 2 with /dev/kmsg to improve the chance + // of output being visible to the user. + if fi, err := os.Stdout.Stat(); err == nil { + if stat, ok := fi.Sys().(*Stat_t); ok { + if stat.Rdev == 0x103 { + var fd int + if fd, err = Open( + "/dev/kmsg", + O_WRONLY|O_CLOEXEC, + 0, + ); err != nil { + log.Fatalf("cannot open kmsg: %v", err) + } + + if err = Dup3(fd, Stdout, 0); err != nil { + log.Fatalf("cannot open stdout: %v", err) + } + if err = Dup3(fd, Stderr, 0); err != nil { + log.Fatalf("cannot open stderr: %v", err) + } + + if err = Close(fd); err != nil { + log.Printf("cannot close kmsg: %v", err) + } + } + } + } + +}