diff --git a/cmd/hakurei/print.go b/cmd/hakurei/print.go index 040a3b0..8f6e713 100644 --- a/cmd/hakurei/print.go +++ b/cmd/hakurei/print.go @@ -89,24 +89,19 @@ func printShowInstance( if params.Hostname != "" { t.Printf(" Hostname:\t%s\n", params.Hostname) } - flags := make([]string, 0, 7) - writeFlag := func(name string, flag uintptr, force bool) { - if params.Flags&flag != 0 || force { - flags = append(flags, name) + flags := params.Flags.String() + + // this is included in the upper hst.Config struct but is relevant here + const flagDirectWayland = "directwl" + if config.DirectWayland { + // hardcoded value when every flag is unset + if flags == "none" { + flags = flagDirectWayland + } else { + flags += ", " + flagDirectWayland } } - writeFlag("userns", hst.FUserns, false) - writeFlag("devel", hst.FDevel, false) - writeFlag("net", hst.FHostNet, false) - writeFlag("abstract", hst.FHostAbstract, false) - writeFlag("device", hst.FDevice, false) - writeFlag("tty", hst.FTty, false) - writeFlag("mapuid", hst.FMapRealUID, false) - writeFlag("directwl", 0, config.DirectWayland) - if len(flags) == 0 { - flags = append(flags, "none") - } - t.Printf(" Flags:\t%s\n", strings.Join(flags, " ")) + t.Printf(" Flags:\t%s\n", flags) if params.Path != nil { t.Printf(" Path:\t%s\n", params.Path) diff --git a/cmd/hakurei/print_test.go b/cmd/hakurei/print_test.go index caea899..bc65bac 100644 --- a/cmd/hakurei/print_test.go +++ b/cmd/hakurei/print_test.go @@ -43,7 +43,7 @@ func TestPrintShowInstance(t *testing.T) { Groups: video, dialout, plugdev Home: /data/data/org.chromium.Chromium Hostname: localhost - Flags: userns devel net abstract device tty mapuid + Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir Path: /run/current-system/sw/bin/chromium Arguments: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland @@ -87,6 +87,22 @@ App Enablements: (no enablements) Flags: none +`, false}, + {"config flag none directwl", nil, &hst.Config{DirectWayland: true, Container: new(hst.ContainerConfig)}, false, false, `Error: container configuration missing path to home directory! + +App + Identity: 0 + Enablements: (no enablements) + Flags: directwl + +`, false}, + {"config flag directwl", nil, &hst.Config{DirectWayland: true, Container: &hst.ContainerConfig{Flags: hst.FMultiarch}}, false, false, `Error: container configuration missing path to home directory! + +App + Identity: 0 + Enablements: (no enablements) + Flags: multiarch, directwl + `, false}, {"config nil entries", nil, &hst.Config{Container: &hst.ContainerConfig{Filesystem: make([]hst.FilesystemConfigJSON, 1)}, ExtraPerms: make([]hst.ExtraPermConfig, 1)}, false, false, `Error: container configuration missing path to home directory! @@ -124,7 +140,7 @@ App Groups: video, dialout, plugdev Home: /data/data/org.chromium.Chromium Hostname: localhost - Flags: userns devel net abstract device tty mapuid + Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir Path: /run/current-system/sw/bin/chromium Arguments: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland diff --git a/hst/container.go b/hst/container.go index 617d22d..7564391 100644 --- a/hst/container.go +++ b/hst/container.go @@ -2,6 +2,7 @@ package hst import ( "encoding/json" + "strings" "syscall" "time" @@ -38,9 +39,12 @@ const ( ExitRequest = 254 ) +// Flags are options held by [ContainerConfig]. +type Flags uintptr + const ( // FMultiarch unblocks syscalls required for multiarch to work on applicable targets. - FMultiarch uintptr = 1 << iota + FMultiarch Flags = 1 << iota // FSeccompCompat changes emitted seccomp filter programs to be identical to that of Flatpak. FSeccompCompat @@ -74,6 +78,45 @@ const ( FAll = fMax - 1 ) +func (flags Flags) String() string { + switch flags { + case FMultiarch: + return "multiarch" + case FSeccompCompat: + return "compat" + case FDevel: + return "devel" + case FUserns: + return "userns" + case FHostNet: + return "net" + case FHostAbstract: + return "abstract" + case FTty: + return "tty" + case FMapRealUID: + return "mapuid" + case FDevice: + return "device" + case FShareRuntime: + return "runtime" + case FShareTmpdir: + return "tmpdir" + + default: + s := make([]string, 0, 1<<4) + for f := Flags(1); f < fMax; f <<= 1 { + if flags&f != 0 { + s = append(s, f.String()) + } + } + if len(s) == 0 { + return "none" + } + return strings.Join(s, ", ") + } +} + // ContainerConfig describes the container configuration to be applied to an underlying [container]. type ContainerConfig struct { // Container UTS namespace hostname. @@ -106,7 +149,7 @@ type ContainerConfig struct { Args []string `json:"args"` // Flags holds boolean options of [ContainerConfig]. - Flags uintptr `json:"-"` + Flags Flags `json:"-"` } // ContainerConfigF is [ContainerConfig] stripped of its methods. diff --git a/hst/container_test.go b/hst/container_test.go index cdeb502..df84827 100644 --- a/hst/container_test.go +++ b/hst/container_test.go @@ -3,6 +3,7 @@ package hst_test import ( "encoding/json" "errors" + "math" "reflect" "syscall" "testing" @@ -10,6 +11,30 @@ import ( "hakurei.app/hst" ) +func TestFlagsString(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + flags hst.Flags + want string + }{ + {"none", 0, "none"}, + {"none high", hst.FAll + 1, "none"}, + {"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir"}, + {"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir"}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + if got := tc.flags.String(); got != tc.want { + t.Errorf("String(%#b): %q, want %q", tc.flags, got, tc.want) + } + }) + } +} + func TestContainerConfig(t *testing.T) { t.Parallel()