From 5676b2b5813323a18ec6c88fefdbf436160c9913 Mon Sep 17 00:00:00 2001 From: flamingcow Date: Sun, 26 Jul 2026 15:50:55 -0700 Subject: [PATCH] Detect mounts by mount root, wait for the touchscreen, and default to eth0/eth1 --- init.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- main.go | 11 +++++---- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/init.go b/init.go index 4296555..7bf2bb8 100644 --- a/init.go +++ b/init.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" "golang.org/x/sys/unix" ) @@ -21,11 +22,26 @@ type mountSpec struct { 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. + // devtmpfs reports itself as tmpfs, which is why the magic alone is not + // enough to tell it apart from the directory it would be mounted over. {"/dev", "devtmpfs", unix.TMPFS_MAGIC, unix.MS_NOSUID}, } +// Whether something is mounted here, as opposed to this being a plain +// directory on whatever filesystem contains it. The type alone cannot answer +// that: booted from an initramfs the root is itself tmpfs, so an empty /dev +// directory on it is indistinguishable by magic from a mounted devtmpfs. +func isMountRoot(dir string) (bool, error) { + var stx unix.Statx_t + if err := unix.Statx(unix.AT_FDCWD, dir, 0, unix.STATX_BASIC_STATS, &stx); err != nil { + return false, err + } + if stx.Attributes_mask&unix.STATX_ATTR_MOUNT_ROOT == 0 { + return false, fmt.Errorf("kernel does not report STATX_ATTR_MOUNT_ROOT") + } + return stx.Attributes&unix.STATX_ATTR_MOUNT_ROOT != 0, nil +} + func checkMount(m mountSpec) checkResult { res := checkResult{item: "mount " + m.dir} var st unix.Statfs_t @@ -43,7 +59,13 @@ func checkMount(m mountSpec) checkResult { res.fatal = true return res } - if int64(st.Type) == m.magic { + mounted, err := isMountRoot(m.dir) + if err != nil { + res.err = err + res.fatal = true + return res + } + if mounted && int64(st.Type) == m.magic { res.state = m.fstype + " already mounted" return res } @@ -69,3 +91,45 @@ func mountFilesystems() []checkResult { } return out } + +const ( + touchTimeout = 30 * time.Second + touchPoll = 100 * time.Millisecond +) + +// USB enumerates asynchronously and the kernel hands us control long before the +// bus has settled, so unlike everything else here the touchscreen is genuinely +// not there yet rather than absent. It is the only device we wait for. +func waitForTouchscreen() checkResult { + res := checkResult{item: "touchscreen"} + start := time.Now() + for { + f, err := findTouchscreen() + if err == nil { + f.Close() + waited := time.Since(start) + if waited < touchPoll { + res.state = "ready" + return res + } + res.fixed = true + res.state = fmt.Sprintf("ready after %.1fs", waited.Seconds()) + return res + } + if time.Since(start) >= touchTimeout { + res.err = fmt.Errorf("%w after %s", err, touchTimeout) + res.fatal = true + return res + } + time.Sleep(touchPoll) + } +} + +func bootstrap() []checkResult { + out := mountFilesystems() + // /dev/input/event* only exists once devtmpfs is mounted above. + if out[len(out)-1].fatal { + return out + } + return append(out, waitForTouchscreen()) +} diff --git a/main.go b/main.go index dd81618..e13da99 100644 --- a/main.go +++ b/main.go @@ -627,8 +627,10 @@ type config struct { func main() { var ( - aName = flag.String("a", "", "first interface") - bName = flag.String("b", "", "second interface") + // The names the kernel gives the only two ports built into it, since as + // PID 1 there is no udev to rename them and no command line to pass. + aName = flag.String("a", "eth0", "first interface") + bName = flag.String("b", "eth1", "second interface") sizesArg = flag.String("sizes", "64,128,256,512,1024,1280,1514", "frame sizes in bytes, excluding FCS, cycled per packet") streams = flag.Int("streams", 7, "independent streams per direction, capped by rx rings; each gets its own ethertype, steered by a flow rule to its own rx queue") batch = flag.Int("batch", 64, "frames per sendmmsg/recvmmsg call") @@ -659,15 +661,12 @@ const ( func run(aName, bName, sizesArg string, nStreams, batch int, nsPerM float64) error { - if aName == "" || bName == "" { - return fmt.Errorf("both -a and -b are required") - } sizes, err := parseSizes(sizesArg) if err != nil { return err } - if err := reportChecks("MOUNTS", mountFilesystems()); err != nil { + if err := reportChecks("BOOT", bootstrap()); err != nil { return err }