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) + } + } + } + } + +}