//go:build testtool package main import ( "encoding/gob" "log" "net" "os" "path" "reflect" "slices" "strings" "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/container/vfs" ) func main() { log.SetFlags(0) log.SetPrefix("testtool: ") var hostNet, layers bool if len(os.Args) == 2 && os.Args[0] == "testtool" { switch os.Args[1] { case "net": hostNet = true log.SetPrefix("testtool(net): ") break case "layers": layers = true log.SetPrefix("testtool(layers): ") break default: log.Fatalf("Args: %q", os.Args) return } } else if wantArgs := []string{"testtool"}; !slices.Equal(os.Args, wantArgs) { log.Fatalf("Args: %q, want %q", os.Args, wantArgs) } var overlayRoot bool wantEnv := []string{"HAKUREI_TEST=1"} if len(os.Environ()) == 2 { overlayRoot = true if !layers { log.SetPrefix("testtool(overlay root): ") } wantEnv = []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"} } if !slices.Equal(wantEnv, os.Environ()) { log.Fatalf("Environ: %q, want %q", os.Environ(), wantEnv) } var overlayWork bool const ( wantExec = "/opt/bin/testtool" wantExecWork = "/work/bin/testtool" ) var iftPath string if got, err := os.Executable(); err != nil { log.Fatalf("Executable: error = %v", err) } else { iftPath = path.Join(path.Dir(path.Dir(got)), "ift") if got != wantExec { switch got { case wantExecWork: overlayWork = true log.SetPrefix("testtool(overlay work): ") default: log.Fatalf("Executable: %q, want %q", got, wantExec) } } } wantHostname := "cure" if hostNet { wantHostname += "-net" } if hostname, err := os.Hostname(); err != nil { log.Fatalf("Hostname: error = %v", err) } else if hostname != wantHostname { log.Fatalf("Hostname: %q, want %q", hostname, wantHostname) } var m *vfs.MountInfo if f, err := os.Open(fhs.Proc + "self/mountinfo"); err != nil { log.Fatalf("Open: error = %v", err) } else { err = vfs.NewMountInfoDecoder(f).Decode(&m) closeErr := f.Close() if err != nil { log.Fatalf("Decode: error = %v", err) } if closeErr != nil { log.Fatalf("Close: error = %v", err) } } if ift, err := net.Interfaces(); err != nil { log.Fatal(err) } else if !hostNet { if len(ift) != 1 || ift[0].Name != "lo" { log.Fatalln("got interfaces", strings.Join(slices.Collect(func(yield func(ifn string) bool) { for _, ifi := range ift { if !yield(ifi.Name) { break } } }), ", ")) } } else { var iftParent []net.Interface var r *os.File if r, err = os.Open(iftPath); err != nil { log.Fatal(err) } else { err = gob.NewDecoder(r).Decode(&iftParent) closeErr := r.Close() if err != nil { log.Fatal(err) } if closeErr != nil { log.Fatal(closeErr) } } if !reflect.DeepEqual(ift, iftParent) { log.Fatalf("Interfaces: %#v, want %#v", ift, iftParent) } } const checksumEmptyDir = "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" ident := "U2cbgVgEtjfRuvHfE1cQnZ3t8yoexULQyo_VLgvxAVJSsobMcNaFIsuDWtmt7kzK" log.Println(m) next := func() { m = m.Next; log.Println(m) } if overlayRoot { ident = "5ey2wpmMpj483YYa7ZZQciYLA2cx3_l167JCqWW4Pd-5DVp81dj9EsBtVTwYptF6" if m.Root != "/" || m.Target != "/" || m.Source != "overlay" || m.FsType != "overlay" { log.Fatal("unexpected root mount entry") } var lowerdir string for _, o := range strings.Split(m.FsOptstr, ",") { const lowerdirKey = "lowerdir=" if strings.HasPrefix(o, lowerdirKey) { lowerdir = o[len(lowerdirKey):] } } if !layers { if path.Base(lowerdir) != checksumEmptyDir { log.Fatal("unexpected artifact checksum") } } else { ident = "tfjrsVuBuFgzWgwz-yPppFtylYuC1VFWnKhyBiHbWTGkyz8lt7Ee9QXWaIHPXs4x" lowerdirsEscaped := strings.Split(lowerdir, ":") lowerdirs := lowerdirsEscaped[:0] // ignore the option separator since it does not appear in ident for i, e := range lowerdirsEscaped { if len(e) > 0 && e[len(e)-1] == check.SpecialOverlayEscape[0] && (len(e) == 1 || e[len(e)-2] != check.SpecialOverlayEscape[0]) { // ignore escaped pathname separator since it does not // appear in ident e = e[:len(e)-1] if len(lowerdirsEscaped) != i { lowerdirsEscaped[i+1] = e + lowerdirsEscaped[i+1] continue } } lowerdirs = append(lowerdirs, e) } if len(lowerdirs) != 2 || path.Base(lowerdirs[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" || path.Base(lowerdirs[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" { log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdirs, ", ")) } } } else { if hostNet { ident = "QdsJhGgnk5N2xdUNGcndXQxFKifxf1V_2t9X8CQ-pDcg24x6mGJC_BiLfGbs6Qml" } if m.Root != "/sysroot" || m.Target != "/" { log.Fatal("unexpected root mount entry") } next() if path.Base(m.Root) != "OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb" { log.Fatal("unexpected file artifact checksum") } next() if path.Base(m.Root) != checksumEmptyDir { log.Fatal("unexpected artifact checksum") } } next() // testtool artifact next() if overlayWork { ident = "acaDzHZv40dZaz4cGAXayqbRMgbEOuiuiUijZL8IgDQvyeCNMFE3onBMYfny-kXA" if m.Root != "/" || m.Target != "/work" || m.Source != "overlay" || m.FsType != "overlay" { log.Fatal("unexpected work mount entry") } } else { if path.Base(m.Root) != ident || m.Target != "/work" { log.Fatal("unexpected work mount entry") } } next() if path.Base(m.Root) != ident || m.Target != "/tmp" { log.Fatal("unexpected temp mount entry") } next() if m.Root != "/" || m.Target != "/proc" || m.Source != "proc" || m.FsType != "proc" { log.Fatal("unexpected proc mount entry") } next() if m.Root != "/" || m.Target != "/dev" || m.Source != "devtmpfs" || m.FsType != "tmpfs" { log.Fatal("unexpected dev mount entry") } for i := 0; i < 9; i++ { // private /dev entries next() } if m.Next != nil { log.Println("unexpected extra mount entries") for m.Next != nil { next() } os.Exit(1) } checkData := []byte{0} if hostNet { checkData = []byte("net") } if err := os.WriteFile("check", checkData, 0400); err != nil { log.Fatal(err) } }