From 832a2b42d610753dd9b7e8b425516093fce504d2 Mon Sep 17 00:00:00 2001 From: flamingcow Date: Sun, 26 Jul 2026 10:54:19 -0700 Subject: [PATCH] Mount the filesystems we need so this can run as PID 1 --- fb.go | 1 + init.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 25 ++++++++------------ system.go | 18 ++++++++++++++ ui.go | 2 +- 5 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 init.go diff --git a/fb.go b/fb.go index ef353a6..7454c1f 100644 --- a/fb.go +++ b/fb.go @@ -17,6 +17,7 @@ const ( kdText = 0x00 kdGraphics = 0x01 consolePath = "/dev/tty0" + fbPath = "/dev/fb0" ) // The variable screen info is a flat run of 40 u32s, so it is read as an array diff --git a/init.go b/init.go new file mode 100644 index 0000000..4296555 --- /dev/null +++ b/init.go @@ -0,0 +1,71 @@ +package main + +import ( + "fmt" + + "golang.org/x/sys/unix" +) + +// Running as PID 1 there is nothing underneath us: sysfs and devtmpfs are what +// every check, counter and device node below is reached through, and no one +// else is going to mount them. Written as checks like everything else, so this +// is a silent no-op under a running system. + +type mountSpec struct { + dir string + fstype string + magic int64 + flags uintptr +} + +var wantMounts = []mountSpec{ + {"/proc", "proc", unix.PROC_SUPER_MAGIC, unix.MS_NOSUID | unix.MS_NODEV | unix.MS_NOEXEC}, + {"/sys", "sysfs", unix.SYSFS_MAGIC, unix.MS_NOSUID | unix.MS_NODEV | unix.MS_NOEXEC}, + // devtmpfs reports itself as tmpfs, so an existing tmpfs on /dev is taken + // as good enough; the kernel populates the nodes either way. + {"/dev", "devtmpfs", unix.TMPFS_MAGIC, unix.MS_NOSUID}, +} + +func checkMount(m mountSpec) checkResult { + res := checkResult{item: "mount " + m.dir} + var st unix.Statfs_t + err := unix.Statfs(m.dir, &st) + if err == unix.ENOENT { + if err := unix.Mkdir(m.dir, 0o755); err != nil { + res.err = fmt.Errorf("creating %s: %w", m.dir, err) + res.fatal = true + return res + } + err = unix.Statfs(m.dir, &st) + } + if err != nil { + res.err = err + res.fatal = true + return res + } + if int64(st.Type) == m.magic { + res.state = m.fstype + " already mounted" + return res + } + if err := unix.Mount(m.fstype, m.dir, m.fstype, m.flags, ""); err != nil { + res.err = err + res.fatal = true + return res + } + res.fixed = true + res.state = "mounted " + m.fstype + return res +} + +// Each mount is what the next check stands on, so the first failure ends it. +func mountFilesystems() []checkResult { + var out []checkResult + for _, m := range wantMounts { + res := checkMount(m) + out = append(out, res) + if res.fatal { + return out + } + } + return out +} diff --git a/main.go b/main.go index 8f21357..dd81618 100644 --- a/main.go +++ b/main.go @@ -637,10 +637,11 @@ func main() { ) flag.Parse() + // Nothing here is recoverable by the time it reaches this point, and as PID 1 + // a plain exit would panic the kernel anyway with less to show for it. if err := run(*aName, *bName, *sizesArg, *streams, *batch, *nsPerM); err != nil { - fmt.Fprintln(os.Stderr, "error:", err) - os.Exit(1) + panic(err) } } @@ -665,6 +666,11 @@ func run(aName, bName, sizesArg string, if err != nil { return err } + + if err := reportChecks("MOUNTS", mountFilesystems()); err != nil { + return err + } + a, err := lookupEndpoint(aName) if err != nil { return err @@ -692,19 +698,8 @@ func run(aName, bName, sizesArg string, ethertypes[i] = uint16(etherBase + i) } - var fatal []string - var tuneRows [][]string - for _, r := range configureSystem(ifnames, ethertypes) { - tuneRows = append(tuneRows, []string{r.item, r.status(), r.detail()}) - if r.fatal { - fatal = append(fatal, r.item) - } - } - fmt.Println(renderBox("HOST SETTINGS", - []string{"CHECK", "STATUS", "DETAIL"}, - []bool{false, false, false}, tuneRows)) - if len(fatal) > 0 { - return fmt.Errorf("cannot test with %s in this state", strings.Join(fatal, ", ")) + if err := reportChecks("HOST SETTINGS", configureSystem(ifnames, ethertypes)); err != nil { + return err } cfg := config{ diff --git a/system.go b/system.go index 7ba79ca..d71a2a9 100644 --- a/system.go +++ b/system.go @@ -282,6 +282,24 @@ func (r checkResult) detail() string { return r.state } +func reportChecks(title string, results []checkResult) error { + var rows [][]string + var fatal []string + for _, r := range results { + rows = append(rows, []string{r.item, r.status(), r.detail()}) + if r.fatal { + fatal = append(fatal, r.item) + } + } + fmt.Println(renderBox(title, + []string{"CHECK", "STATUS", "DETAIL"}, + []bool{false, false, false}, rows)) + if len(fatal) > 0 { + return fmt.Errorf("cannot test with %s in this state", strings.Join(fatal, ", ")) + } + return nil +} + func ethtoolCall(fd int, ifname string, data unsafe.Pointer) error { var ifr dataIfreq if len(ifname) >= unix.IFNAMSIZ { diff --git a/ui.go b/ui.go index 0537677..cebd588 100644 --- a/ui.go +++ b/ui.go @@ -58,7 +58,7 @@ type display struct { } func newDisplay() (*display, error) { - fb, err := openFramebuffer("/dev/fb0") + fb, err := openFramebuffer(fbPath) if err != nil { return nil, err }