diff --git a/cmd/hakurei/command.go b/cmd/hakurei/command.go index e335647..213cc41 100644 --- a/cmd/hakurei/command.go +++ b/cmd/hakurei/command.go @@ -15,17 +15,17 @@ import ( "time" "hakurei.app/command" - "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal" "hakurei.app/internal/app" "hakurei.app/internal/app/state" + "hakurei.app/message" "hakurei.app/system/dbus" ) -func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningErrs, out io.Writer) command.Command { +func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErrs, out io.Writer) command.Command { var ( flagVerbose bool flagJSON bool diff --git a/cmd/hakurei/command_test.go b/cmd/hakurei/command_test.go index d22249f..d29485d 100644 --- a/cmd/hakurei/command_test.go +++ b/cmd/hakurei/command_test.go @@ -7,7 +7,7 @@ import ( "testing" "hakurei.app/command" - "hakurei.app/container" + "hakurei.app/message" ) func TestHelp(t *testing.T) { @@ -69,7 +69,7 @@ Flags: for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out := new(bytes.Buffer) - c := buildCommand(t.Context(), container.NewMsg(nil), new(earlyHardeningErrs), out) + c := buildCommand(t.Context(), message.NewMsg(nil), new(earlyHardeningErrs), out) if err := c.Parse(tc.args); !errors.Is(err, command.ErrHelp) && !errors.Is(err, flag.ErrHelp) { t.Errorf("Parse: error = %v; want %v", err, command.ErrHelp) diff --git a/cmd/hakurei/main.go b/cmd/hakurei/main.go index 5cc8224..dcea40c 100644 --- a/cmd/hakurei/main.go +++ b/cmd/hakurei/main.go @@ -13,6 +13,7 @@ import ( "syscall" "hakurei.app/container" + "hakurei.app/message" ) var ( @@ -31,7 +32,7 @@ func main() { log.SetPrefix("hakurei: ") log.SetFlags(0) - msg := container.NewMsg(log.Default()) + msg := message.NewMsg(log.Default()) early := earlyHardeningErrs{ yamaLSM: container.SetPtracer(0), diff --git a/cmd/hakurei/parse.go b/cmd/hakurei/parse.go index 14b9c16..3d15f66 100644 --- a/cmd/hakurei/parse.go +++ b/cmd/hakurei/parse.go @@ -10,13 +10,13 @@ import ( "strings" "syscall" - "hakurei.app/container" "hakurei.app/hst" "hakurei.app/internal/app" "hakurei.app/internal/app/state" + "hakurei.app/message" ) -func tryPath(msg container.Msg, name string) (config *hst.Config) { +func tryPath(msg message.Msg, name string) (config *hst.Config) { var r io.Reader config = new(hst.Config) @@ -49,7 +49,7 @@ func tryPath(msg container.Msg, name string) (config *hst.Config) { return } -func tryFd(msg container.Msg, name string) io.ReadCloser { +func tryFd(msg message.Msg, name string) io.ReadCloser { if v, err := strconv.Atoi(name); err != nil { if !errors.Is(err, strconv.ErrSyntax) { msg.Verbosef("name cannot be interpreted as int64: %v", err) @@ -68,7 +68,7 @@ func tryFd(msg container.Msg, name string) io.ReadCloser { } } -func tryShort(msg container.Msg, name string) (config *hst.Config, entry *state.State) { +func tryShort(msg message.Msg, name string) (config *hst.Config, entry *state.State) { likePrefix := false if len(name) <= 32 { likePrefix = true diff --git a/cmd/hakurei/print.go b/cmd/hakurei/print.go index 1a97b85..e013909 100644 --- a/cmd/hakurei/print.go +++ b/cmd/hakurei/print.go @@ -11,10 +11,10 @@ import ( "text/tabwriter" "time" - "hakurei.app/container" "hakurei.app/hst" "hakurei.app/internal/app" "hakurei.app/internal/app/state" + "hakurei.app/message" ) func printShowSystem(output io.Writer, short, flagJSON bool) { @@ -56,7 +56,7 @@ func printShowInstance( if err := config.Validate(); err != nil { valid = false - if m, ok := container.GetErrorMessage(err); ok { + if m, ok := message.GetMessage(err); ok { mustPrint(output, "Error: "+m+"!\n\n") } } diff --git a/cmd/hpkg/main.go b/cmd/hpkg/main.go index bb3f886..e3346bf 100644 --- a/cmd/hpkg/main.go +++ b/cmd/hpkg/main.go @@ -11,10 +11,10 @@ import ( "syscall" "hakurei.app/command" - "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/hst" + "hakurei.app/message" ) var ( @@ -24,7 +24,7 @@ var ( func main() { log.SetPrefix("hpkg: ") log.SetFlags(0) - msg := container.NewMsg(log.Default()) + msg := message.NewMsg(log.Default()) if err := os.Setenv("SHELL", pathShell.String()); err != nil { log.Fatalf("cannot set $SHELL: %v", err) diff --git a/cmd/hpkg/paths.go b/cmd/hpkg/paths.go index e5c045a..811c7b7 100644 --- a/cmd/hpkg/paths.go +++ b/cmd/hpkg/paths.go @@ -7,10 +7,10 @@ import ( "strconv" "sync/atomic" - "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/hst" + "hakurei.app/message" ) const bash = "bash" @@ -52,7 +52,7 @@ func lookPath(file string) string { var beforeRunFail = new(atomic.Pointer[func()]) -func mustRun(msg container.Msg, name string, arg ...string) { +func mustRun(msg message.Msg, name string, arg ...string) { msg.Verbosef("spawning process: %q %q", name, arg) cmd := exec.Command(name, arg...) cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr diff --git a/cmd/hpkg/proc.go b/cmd/hpkg/proc.go index 1bbf5b4..7088910 100644 --- a/cmd/hpkg/proc.go +++ b/cmd/hpkg/proc.go @@ -9,14 +9,14 @@ import ( "os" "os/exec" - "hakurei.app/container" "hakurei.app/hst" "hakurei.app/internal" + "hakurei.app/message" ) var hakureiPath = internal.MustHakureiPath() -func mustRunApp(ctx context.Context, msg container.Msg, config *hst.Config, beforeFail func()) { +func mustRunApp(ctx context.Context, msg message.Msg, config *hst.Config, beforeFail func()) { var ( cmd *exec.Cmd st io.WriteCloser diff --git a/cmd/hpkg/with.go b/cmd/hpkg/with.go index df03a21..cb86f50 100644 --- a/cmd/hpkg/with.go +++ b/cmd/hpkg/with.go @@ -5,15 +5,15 @@ import ( "os" "strings" - "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/hst" + "hakurei.app/message" ) func withNixDaemon( ctx context.Context, - msg container.Msg, + msg message.Msg, action string, command []string, net bool, updateConfig func(config *hst.Config) *hst.Config, app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func(), ) { @@ -64,7 +64,7 @@ func withNixDaemon( func withCacheDir( ctx context.Context, - msg container.Msg, + msg message.Msg, action string, command []string, workDir *check.Absolute, app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) { mustRunAppDropShell(ctx, msg, &hst.Config{ @@ -102,7 +102,7 @@ func withCacheDir( }, dropShell, beforeFail) } -func mustRunAppDropShell(ctx context.Context, msg container.Msg, config *hst.Config, dropShell bool, beforeFail func()) { +func mustRunAppDropShell(ctx context.Context, msg message.Msg, config *hst.Config, dropShell bool, beforeFail func()) { if dropShell { if config.Container != nil { config.Container.Args = []string{bash, "-l"} diff --git a/container/autoroot.go b/container/autoroot.go index 0ebe6b2..f555aca 100644 --- a/container/autoroot.go +++ b/container/autoroot.go @@ -6,6 +6,7 @@ import ( "hakurei.app/container/check" "hakurei.app/container/fhs" + "hakurei.app/message" ) func init() { gob.Register(new(AutoRootOp)) } @@ -81,7 +82,7 @@ func (r *AutoRootOp) String() string { } // IsAutoRootBindable returns whether a dir entry name is selected for AutoRoot. -func IsAutoRootBindable(msg Msg, name string) bool { +func IsAutoRootBindable(msg message.Msg, name string) bool { switch name { case "proc", "dev", "tmp", "mnt", "etc": diff --git a/container/autoroot_test.go b/container/autoroot_test.go index 8c72b78..d53edc7 100644 --- a/container/autoroot_test.go +++ b/container/autoroot_test.go @@ -8,6 +8,7 @@ import ( "hakurei.app/container/bits" "hakurei.app/container/check" "hakurei.app/container/stub" + "hakurei.app/message" ) func TestAutoRootOp(t *testing.T) { @@ -195,7 +196,7 @@ func TestIsAutoRootBindable(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - var msg Msg + var msg message.Msg if tc.log { msg = &kstub{nil, stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { panic("unreachable") }, stub.Expect{Calls: []stub.Call{ call("verbose", stub.ExpectArgs{[]any{"got unexpected root entry"}}, nil, nil), diff --git a/container/container.go b/container/container.go index 5b6514d..ae83fc3 100644 --- a/container/container.go +++ b/container/container.go @@ -18,6 +18,7 @@ import ( "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/container/seccomp" + "hakurei.app/message" ) const ( @@ -52,7 +53,7 @@ type ( cmd *exec.Cmd ctx context.Context - msg Msg + msg message.Msg Params } @@ -396,9 +397,9 @@ func (p *Container) ProcessState() *os.ProcessState { } // New returns the address to a new instance of [Container] that requires further initialisation before use. -func New(ctx context.Context, msg Msg) *Container { +func New(ctx context.Context, msg message.Msg) *Container { if msg == nil { - msg = NewMsg(nil) + msg = message.NewMsg(nil) } p := &Container{ctx: ctx, msg: msg, Params: Params{Ops: new(Ops)}} @@ -409,7 +410,7 @@ func New(ctx context.Context, msg Msg) *Container { } // NewCommand calls [New] and initialises the [Params.Path] and [Params.Args] fields. -func NewCommand(ctx context.Context, msg Msg, pathname *check.Absolute, name string, args ...string) *Container { +func NewCommand(ctx context.Context, msg message.Msg, pathname *check.Absolute, name string, args ...string) *Container { z := New(ctx, msg) z.Path = pathname z.Args = append([]string{name}, args...) diff --git a/container/container_test.go b/container/container_test.go index 2d60f29..6a85869 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -26,6 +26,7 @@ import ( "hakurei.app/container/vfs" "hakurei.app/hst" "hakurei.app/ldd" + "hakurei.app/message" ) func TestStartError(t *testing.T) { @@ -152,13 +153,13 @@ func TestStartError(t *testing.T) { }) t.Run("msg", func(t *testing.T) { - if got, ok := container.GetErrorMessage(tc.err); !ok { + if got, ok := message.GetMessage(tc.err); !ok { if tc.msg != "" { - t.Errorf("GetErrorMessage: err does not implement MessageError") + t.Errorf("GetMessage: err does not implement MessageError") } return } else if got != tc.msg { - t.Errorf("GetErrorMessage: %q, want %q", got, tc.msg) + t.Errorf("GetMessage: %q, want %q", got, tc.msg) } }) }) @@ -545,7 +546,7 @@ func testContainerCancel( } func TestContainerString(t *testing.T) { - msg := container.NewMsg(nil) + msg := message.NewMsg(nil) c := container.NewCommand(t.Context(), msg, check.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env") c.SeccompFlags |= seccomp.AllowMultiarch c.SeccompRules = seccomp.Preset( @@ -711,7 +712,7 @@ func TestMain(m *testing.M) { } func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) { - msg := container.NewMsg(nil) + msg := message.NewMsg(nil) c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...) c.Env = append(c.Env, envDoCheck+"=1") c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0) diff --git a/container/dispatcher.go b/container/dispatcher.go index 65881cc..5f8c72c 100644 --- a/container/dispatcher.go +++ b/container/dispatcher.go @@ -11,6 +11,7 @@ import ( "syscall" "hakurei.app/container/seccomp" + "hakurei.app/message" ) type osFile interface { @@ -37,7 +38,7 @@ type syscallDispatcher interface { setNoNewPrivs() error // lastcap provides [LastCap]. - lastcap(msg Msg) uintptr + lastcap(msg message.Msg) uintptr // capset provides capset. capset(hdrp *capHeader, datap *[2]capData) error // capBoundingSetDrop provides capBoundingSetDrop. @@ -52,9 +53,9 @@ type syscallDispatcher interface { receive(key string, e any, fdp *uintptr) (closeFunc func() error, err error) // bindMount provides procPaths.bindMount. - bindMount(msg Msg, source, target string, flags uintptr) error + bindMount(msg message.Msg, source, target string, flags uintptr) error // remount provides procPaths.remount. - remount(msg Msg, target string, flags uintptr) error + remount(msg message.Msg, target string, flags uintptr) error // mountTmpfs provides mountTmpfs. mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error // ensureFile provides ensureFile. @@ -122,11 +123,11 @@ type syscallDispatcher interface { wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error) // printf provides the Printf method of [log.Logger]. - printf(msg Msg, format string, v ...any) + printf(msg message.Msg, format string, v ...any) // fatal provides the Fatal method of [log.Logger] - fatal(msg Msg, v ...any) + fatal(msg message.Msg, v ...any) // fatalf provides the Fatalf method of [log.Logger] - fatalf(msg Msg, format string, v ...any) + fatalf(msg message.Msg, format string, v ...any) } // direct implements syscallDispatcher on the current kernel. @@ -140,7 +141,7 @@ func (direct) setPtracer(pid uintptr) error { return SetPtracer(pid) } func (direct) setDumpable(dumpable uintptr) error { return SetDumpable(dumpable) } func (direct) setNoNewPrivs() error { return SetNoNewPrivs() } -func (direct) lastcap(msg Msg) uintptr { return LastCap(msg) } +func (direct) lastcap(msg message.Msg) uintptr { return LastCap(msg) } func (direct) capset(hdrp *capHeader, datap *[2]capData) error { return capset(hdrp, datap) } func (direct) capBoundingSetDrop(cap uintptr) error { return capBoundingSetDrop(cap) } func (direct) capAmbientClearAll() error { return capAmbientClearAll() } @@ -150,10 +151,10 @@ func (direct) receive(key string, e any, fdp *uintptr) (func() error, error) { return Receive(key, e, fdp) } -func (direct) bindMount(msg Msg, source, target string, flags uintptr) error { +func (direct) bindMount(msg message.Msg, source, target string, flags uintptr) error { return hostProc.bindMount(msg, source, target, flags) } -func (direct) remount(msg Msg, target string, flags uintptr) error { +func (direct) remount(msg message.Msg, target string, flags uintptr) error { return hostProc.remount(msg, target, flags) } func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error { @@ -221,6 +222,6 @@ func (direct) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *s return syscall.Wait4(pid, wstatus, options, rusage) } -func (direct) printf(msg Msg, format string, v ...any) { msg.GetLogger().Printf(format, v...) } -func (direct) fatal(msg Msg, v ...any) { msg.GetLogger().Fatal(v...) } -func (direct) fatalf(msg Msg, format string, v ...any) { msg.GetLogger().Fatalf(format, v...) } +func (direct) printf(msg message.Msg, format string, v ...any) { msg.GetLogger().Printf(format, v...) } +func (direct) fatal(msg message.Msg, v ...any) { msg.GetLogger().Fatal(v...) } +func (direct) fatalf(msg message.Msg, format string, v ...any) { msg.GetLogger().Fatalf(format, v...) } diff --git a/container/dispatcher_test.go b/container/dispatcher_test.go index 2a2685f..4e6ee76 100644 --- a/container/dispatcher_test.go +++ b/container/dispatcher_test.go @@ -18,6 +18,7 @@ import ( "hakurei.app/container/seccomp" "hakurei.app/container/stub" + "hakurei.app/message" ) type opValidTestCase struct { @@ -329,7 +330,7 @@ func (k *kstub) setDumpable(dumpable uintptr) error { } func (k *kstub) setNoNewPrivs() error { k.Helper(); return k.Expects("setNoNewPrivs").Err } -func (k *kstub) lastcap(msg Msg) uintptr { +func (k *kstub) lastcap(msg message.Msg) uintptr { k.Helper() k.checkMsg(msg) return k.Expects("lastcap").Ret.(uintptr) @@ -409,7 +410,7 @@ func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error return } -func (k *kstub) bindMount(msg Msg, source, target string, flags uintptr) error { +func (k *kstub) bindMount(msg message.Msg, source, target string, flags uintptr) error { k.Helper() k.checkMsg(msg) return k.Expects("bindMount").Error( @@ -418,7 +419,7 @@ func (k *kstub) bindMount(msg Msg, source, target string, flags uintptr) error { stub.CheckArg(k.Stub, "flags", flags, 2)) } -func (k *kstub) remount(msg Msg, target string, flags uintptr) error { +func (k *kstub) remount(msg message.Msg, target string, flags uintptr) error { k.Helper() k.checkMsg(msg) return k.Expects("remount").Error( @@ -702,7 +703,7 @@ func (k *kstub) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage return } -func (k *kstub) printf(_ Msg, format string, v ...any) { +func (k *kstub) printf(_ message.Msg, format string, v ...any) { k.Helper() if k.Expects("printf").Error( stub.CheckArg(k.Stub, "format", format, 0), @@ -711,7 +712,7 @@ func (k *kstub) printf(_ Msg, format string, v ...any) { } } -func (k *kstub) fatal(_ Msg, v ...any) { +func (k *kstub) fatal(_ message.Msg, v ...any) { k.Helper() if k.Expects("fatal").Error( stub.CheckArgReflect(k.Stub, "v", v, 0)) != nil { @@ -720,7 +721,7 @@ func (k *kstub) fatal(_ Msg, v ...any) { panic(stub.PanicExit) } -func (k *kstub) fatalf(_ Msg, format string, v ...any) { +func (k *kstub) fatalf(_ message.Msg, format string, v ...any) { k.Helper() if k.Expects("fatalf").Error( stub.CheckArg(k.Stub, "format", format, 0), @@ -730,7 +731,7 @@ func (k *kstub) fatalf(_ Msg, format string, v ...any) { panic(stub.PanicExit) } -func (k *kstub) checkMsg(msg Msg) { +func (k *kstub) checkMsg(msg message.Msg) { k.Helper() var target *kstub diff --git a/container/executable.go b/container/executable.go index 9b6d4f6..f80a1f7 100644 --- a/container/executable.go +++ b/container/executable.go @@ -3,6 +3,8 @@ package container import ( "os" "sync" + + "hakurei.app/message" ) var ( @@ -10,7 +12,7 @@ var ( executableOnce sync.Once ) -func copyExecutable(msg Msg) { +func copyExecutable(msg message.Msg) { if name, err := os.Executable(); err != nil { msg.BeforeExit() msg.GetLogger().Fatalf("cannot read executable path: %v", err) @@ -19,7 +21,7 @@ func copyExecutable(msg Msg) { } } -func MustExecutable(msg Msg) string { +func MustExecutable(msg message.Msg) string { executableOnce.Do(func() { copyExecutable(msg) }) return executable } diff --git a/container/executable_test.go b/container/executable_test.go index 5608a8a..33981bb 100644 --- a/container/executable_test.go +++ b/container/executable_test.go @@ -5,11 +5,12 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/message" ) func TestExecutable(t *testing.T) { for i := 0; i < 16; i++ { - if got := container.MustExecutable(container.NewMsg(nil)); got != os.Args[0] { + if got := container.MustExecutable(message.NewMsg(nil)); got != os.Args[0] { t.Errorf("MustExecutable: %q, want %q", got, os.Args[0]) } diff --git a/container/init.go b/container/init.go index 9481acd..923a36e 100644 --- a/container/init.go +++ b/container/init.go @@ -14,6 +14,7 @@ import ( "hakurei.app/container/fhs" "hakurei.app/container/seccomp" + "hakurei.app/message" ) const ( @@ -61,7 +62,7 @@ type ( setupState struct { nonrepeatable uintptr *Params - Msg + message.Msg } ) @@ -95,14 +96,14 @@ type initParams struct { } // Init is called by [TryArgv0] if the current process is the container init. -func Init(msg Msg) { +func Init(msg message.Msg) { if msg == nil { panic("attempting to call initEntrypoint with nil msg") } initEntrypoint(direct{}, msg) } -func initEntrypoint(k syscallDispatcher, msg Msg) { +func initEntrypoint(k syscallDispatcher, msg message.Msg) { k.lockOSThread() if k.getpid() != 1 { @@ -125,7 +126,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) { k.fatal(msg, "invalid setup descriptor") } if errors.Is(err, ErrReceiveEnv) { - k.fatal(msg, "HAKUREI_SETUP not set") + k.fatal(msg, setupEnv+" not set") } k.fatalf(msg, "cannot decode init setup payload: %v", err) @@ -448,11 +449,11 @@ const initName = "init" // TryArgv0 calls [Init] if the last element of argv0 is "init". // If a nil msg is passed, the system logger is used instead. -func TryArgv0(msg Msg) { +func TryArgv0(msg message.Msg) { if msg == nil { log.SetPrefix(initName + ": ") log.SetFlags(0) - msg = NewMsg(log.Default()) + msg = message.NewMsg(log.Default()) } if len(os.Args) > 0 && path.Base(os.Args[0]) == initName { diff --git a/container/mount.go b/container/mount.go index 0c459c9..360a71d 100644 --- a/container/mount.go +++ b/container/mount.go @@ -7,6 +7,7 @@ import ( . "syscall" "hakurei.app/container/vfs" + "hakurei.app/message" ) /* @@ -87,7 +88,7 @@ const ( ) // bindMount mounts source on target and recursively applies flags if MS_REC is set. -func (p *procPaths) bindMount(msg Msg, source, target string, flags uintptr) error { +func (p *procPaths) bindMount(msg message.Msg, source, target string, flags uintptr) error { // syscallDispatcher.bindMount and procPaths.remount must not be called from this function if err := p.k.mount(source, target, FstypeNULL, MS_SILENT|MS_BIND|flags&MS_REC, zeroString); err != nil { @@ -97,7 +98,7 @@ func (p *procPaths) bindMount(msg Msg, source, target string, flags uintptr) err } // remount applies flags on target, recursively if MS_REC is set. -func (p *procPaths) remount(msg Msg, target string, flags uintptr) error { +func (p *procPaths) remount(msg message.Msg, target string, flags uintptr) error { // syscallDispatcher methods bindMount, remount must not be called from this function var targetFinal string @@ -159,7 +160,7 @@ func (p *procPaths) remount(msg Msg, target string, flags uintptr) error { } // remountWithFlags remounts mount point described by [vfs.MountInfoNode]. -func remountWithFlags(k syscallDispatcher, msg Msg, n *vfs.MountInfoNode, mf uintptr) error { +func remountWithFlags(k syscallDispatcher, msg message.Msg, n *vfs.MountInfoNode, mf uintptr) error { // syscallDispatcher methods bindMount, remount must not be called from this function kf, unmatched := n.Flags() diff --git a/container/sysctl.go b/container/sysctl.go index 9a1e818..4387c4d 100644 --- a/container/sysctl.go +++ b/container/sysctl.go @@ -7,6 +7,7 @@ import ( "sync" "hakurei.app/container/fhs" + "hakurei.app/message" ) var ( @@ -23,7 +24,7 @@ const ( kernelCapLastCapPath = fhs.ProcSys + "kernel/cap_last_cap" ) -func mustReadSysctl(msg Msg) { +func mustReadSysctl(msg message.Msg) { sysctlOnce.Do(func() { if v, err := os.ReadFile(kernelOverflowuidPath); err != nil { msg.GetLogger().Fatalf("cannot read %q: %v", kernelOverflowuidPath, err) @@ -45,6 +46,6 @@ func mustReadSysctl(msg Msg) { }) } -func OverflowUid(msg Msg) int { mustReadSysctl(msg); return kernelOverflowuid } -func OverflowGid(msg Msg) int { mustReadSysctl(msg); return kernelOverflowgid } -func LastCap(msg Msg) uintptr { mustReadSysctl(msg); return uintptr(kernelCapLastCap) } +func OverflowUid(msg message.Msg) int { mustReadSysctl(msg); return kernelOverflowuid } +func OverflowGid(msg message.Msg) int { mustReadSysctl(msg); return kernelOverflowgid } +func LastCap(msg message.Msg) uintptr { mustReadSysctl(msg); return uintptr(kernelCapLastCap) } diff --git a/helper/container.go b/helper/container.go index 4708038..b85f585 100644 --- a/helper/container.go +++ b/helper/container.go @@ -12,12 +12,13 @@ import ( "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/helper/proc" + "hakurei.app/message" ) // New initialises a Helper instance with wt as the null-terminated argument writer. func New( ctx context.Context, - msg container.Msg, + msg message.Msg, pathname *check.Absolute, name string, wt io.WriterTo, stat bool, diff --git a/hst/dbus_test.go b/hst/dbus_test.go index 8b04494..d575f7d 100644 --- a/hst/dbus_test.go +++ b/hst/dbus_test.go @@ -5,8 +5,8 @@ import ( "slices" "testing" - "hakurei.app/container" "hakurei.app/hst" + "hakurei.app/message" ) func TestBadInterfaceError(t *testing.T) { @@ -26,10 +26,10 @@ func TestBadInterfaceError(t *testing.T) { if gotError := tc.err.Error(); gotError != tc.want { t.Errorf("Error: %s, want %s", gotError, tc.want) } - if gotMessage, ok := container.GetErrorMessage(tc.err); !ok { - t.Error("GetErrorMessage: ok = false") + if gotMessage, ok := message.GetMessage(tc.err); !ok { + t.Error("GetMessage: ok = false") } else if gotMessage != tc.want { - t.Errorf("GetErrorMessage: %s, want %s", gotMessage, tc.want) + t.Errorf("GetMessage: %s, want %s", gotMessage, tc.want) } }) } diff --git a/hst/hst_test.go b/hst/hst_test.go index 90380e0..0bd6c2b 100644 --- a/hst/hst_test.go +++ b/hst/hst_test.go @@ -8,9 +8,9 @@ import ( "syscall" "testing" - "hakurei.app/container" "hakurei.app/container/stub" "hakurei.app/hst" + "hakurei.app/message" ) func TestAppError(t *testing.T) { @@ -65,14 +65,14 @@ func TestAppError(t *testing.T) { }) t.Run("message", func(t *testing.T) { - gotMessage, gotMessageOk := container.GetErrorMessage(tc.err) + gotMessage, gotMessageOk := message.GetMessage(tc.err) if want := tc.message != "\x00"; gotMessageOk != want { - t.Errorf("GetErrorMessage: ok = %v, want %v", gotMessage, want) + t.Errorf("GetMessage: ok = %v, want %v", gotMessage, want) } if gotMessageOk { if gotMessage != tc.message { - t.Errorf("GetErrorMessage: %s, want %s", gotMessage, tc.message) + t.Errorf("GetMessage: %s, want %s", gotMessage, tc.message) } } }) diff --git a/internal/app/app.go b/internal/app/app.go index 102c273..0d5f1a5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -6,13 +6,13 @@ import ( "log" "os" - "hakurei.app/container" "hakurei.app/hst" "hakurei.app/internal/app/state" + "hakurei.app/message" ) // Main runs an app according to [hst.Config] and terminates. Main does not return. -func Main(ctx context.Context, msg container.Msg, config *hst.Config) { +func Main(ctx context.Context, msg message.Msg, config *hst.Config) { var id state.ID if err := state.NewAppID(&id); err != nil { log.Fatal(err) diff --git a/internal/app/app_test.go b/internal/app/app_test.go index 9cab358..7dcbc7d 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -23,12 +23,13 @@ import ( "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal/app/state" + "hakurei.app/message" "hakurei.app/system" "hakurei.app/system/acl" ) func TestApp(t *testing.T) { - msg := container.NewMsg(nil) + msg := message.NewMsg(nil) msg.SwapVerbose(testing.Verbose()) testCases := []struct { @@ -744,8 +745,8 @@ func (k *stubNixOS) cmdOutput(cmd *exec.Cmd) ([]byte, error) { } } -func (k *stubNixOS) overflowUid(container.Msg) int { return 65534 } -func (k *stubNixOS) overflowGid(container.Msg) int { return 65534 } +func (k *stubNixOS) overflowUid(message.Msg) int { return 65534 } +func (k *stubNixOS) overflowGid(message.Msg) int { return 65534 } func (k *stubNixOS) mustHsuPath() *check.Absolute { return m("/proc/nonexistent/hsu") } diff --git a/internal/app/dispatcher.go b/internal/app/dispatcher.go index f375902..6e00a9b 100644 --- a/internal/app/dispatcher.go +++ b/internal/app/dispatcher.go @@ -12,6 +12,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/internal" + "hakurei.app/message" ) // osFile represents [os.File]. @@ -53,9 +54,9 @@ type syscallDispatcher interface { cmdOutput(cmd *exec.Cmd) ([]byte, error) // overflowUid provides [container.OverflowUid]. - overflowUid(msg container.Msg) int + overflowUid(msg message.Msg) int // overflowGid provides [container.OverflowGid]. - overflowGid(msg container.Msg) int + overflowGid(msg message.Msg) int // mustHsuPath provides [internal.MustHsuPath]. mustHsuPath() *check.Absolute @@ -90,8 +91,8 @@ func (direct) lookupGroupId(name string) (gid string, err error) { func (direct) cmdOutput(cmd *exec.Cmd) ([]byte, error) { return cmd.Output() } -func (direct) overflowUid(msg container.Msg) int { return container.OverflowUid(msg) } -func (direct) overflowGid(msg container.Msg) int { return container.OverflowGid(msg) } +func (direct) overflowUid(msg message.Msg) int { return container.OverflowUid(msg) } +func (direct) overflowGid(msg message.Msg) int { return container.OverflowGid(msg) } func (direct) mustHsuPath() *check.Absolute { return internal.MustHsuPath() } diff --git a/internal/app/dispatcher_test.go b/internal/app/dispatcher_test.go index 834b11b..f6d10ba 100644 --- a/internal/app/dispatcher_test.go +++ b/internal/app/dispatcher_test.go @@ -4,8 +4,8 @@ import ( "os" "os/exec" - "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/message" ) type panicDispatcher struct{} @@ -21,7 +21,7 @@ func (panicDispatcher) tempdir() string { panic("unreachab func (panicDispatcher) evalSymlinks(string) (string, error) { panic("unreachable") } func (panicDispatcher) lookupGroupId(string) (string, error) { panic("unreachable") } func (panicDispatcher) cmdOutput(*exec.Cmd) ([]byte, error) { panic("unreachable") } -func (panicDispatcher) overflowUid(container.Msg) int { panic("unreachable") } -func (panicDispatcher) overflowGid(container.Msg) int { panic("unreachable") } +func (panicDispatcher) overflowUid(message.Msg) int { panic("unreachable") } +func (panicDispatcher) overflowGid(message.Msg) int { panic("unreachable") } func (panicDispatcher) mustHsuPath() *check.Absolute { panic("unreachable") } func (panicDispatcher) fatalf(string, ...any) { panic("unreachable") } diff --git a/internal/app/finalise.go b/internal/app/finalise.go index a2a8f30..7693f25 100644 --- a/internal/app/finalise.go +++ b/internal/app/finalise.go @@ -8,9 +8,9 @@ import ( "os/user" "sync/atomic" - "hakurei.app/container" "hakurei.app/hst" "hakurei.app/internal/app/state" + "hakurei.app/message" "hakurei.app/system" ) @@ -37,7 +37,7 @@ type outcome struct { syscallDispatcher } -func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, config *hst.Config) error { +func (k *outcome) finalise(ctx context.Context, msg message.Msg, id *state.ID, config *hst.Config) error { if ctx == nil || id == nil { // unreachable panic("invalid call to finalise") diff --git a/internal/app/hsu.go b/internal/app/hsu.go index 982cb51..9f0408a 100644 --- a/internal/app/hsu.go +++ b/internal/app/hsu.go @@ -9,9 +9,9 @@ import ( "strconv" "sync" - "hakurei.app/container" "hakurei.app/container/fhs" "hakurei.app/hst" + "hakurei.app/message" ) // Hsu caches responses from cmd/hsu. @@ -74,7 +74,7 @@ func (h *Hsu) ID() (int, error) { func (h *Hsu) MustID() int { return h.MustIDMsg(nil) } // MustIDMsg implements MustID with a custom [container.Msg]. -func (h *Hsu) MustIDMsg(msg container.Msg) int { +func (h *Hsu) MustIDMsg(msg message.Msg) int { id, err := h.ID() if err == nil { return id @@ -87,7 +87,7 @@ func (h *Hsu) MustIDMsg(msg container.Msg) int { } os.Exit(1) return -0xdeadbeef - } else if m, ok := container.GetErrorMessage(err); ok { + } else if m, ok := message.GetMessage(err); ok { log.Fatal(m) return -0xdeadbeef } else { diff --git a/internal/app/outcome.go b/internal/app/outcome.go index f029a4b..f458993 100644 --- a/internal/app/outcome.go +++ b/internal/app/outcome.go @@ -8,6 +8,7 @@ import ( "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/internal/app/state" + "hakurei.app/message" "hakurei.app/system" "hakurei.app/system/acl" ) @@ -61,7 +62,7 @@ type outcomeState struct { // Copied via populateLocal. k syscallDispatcher // Copied via populateLocal. - msg container.Msg + msg message.Msg } // valid checks outcomeState to be safe for use with outcomeOp. @@ -75,7 +76,7 @@ func (s *outcomeState) valid() bool { // populateEarly populates exported fields via syscallDispatcher. // This must only be called from the priv side. -func (s *outcomeState) populateEarly(k syscallDispatcher, msg container.Msg, config *hst.Config) { +func (s *outcomeState) populateEarly(k syscallDispatcher, msg message.Msg, config *hst.Config) { s.Shim = &shimParams{PrivPID: os.Getpid(), Verbose: msg.IsVerbose(), Ops: fromConfig(config)} // enforce bounds and default early @@ -98,7 +99,7 @@ func (s *outcomeState) populateEarly(k syscallDispatcher, msg container.Msg, con // populateLocal populates unexported fields from transmitted exported fields. // These fields are cheaper to recompute per-process. -func (s *outcomeState) populateLocal(k syscallDispatcher, msg container.Msg) error { +func (s *outcomeState) populateLocal(k syscallDispatcher, msg message.Msg) error { if !s.valid() || k == nil || msg == nil { return newWithMessage("impossible outcome state reached") } diff --git a/internal/app/process.go b/internal/app/process.go index 3225496..0962e21 100644 --- a/internal/app/process.go +++ b/internal/app/process.go @@ -17,6 +17,7 @@ import ( "hakurei.app/hst" "hakurei.app/internal" "hakurei.app/internal/app/state" + "hakurei.app/message" "hakurei.app/system" ) @@ -40,7 +41,7 @@ type mainState struct { cmdWait chan error k *outcome - container.Msg + message.Msg uintptr } @@ -207,7 +208,7 @@ func (ms mainState) fatal(fallback string, ferr error) { } // main carries out outcome and terminates. main does not return. -func (k *outcome) main(msg container.Msg) { +func (k *outcome) main(msg message.Msg) { if !k.active.CompareAndSwap(false, true) { panic("outcome: attempted to run twice") } @@ -312,10 +313,10 @@ func (k *outcome) main(msg container.Msg) { os.Exit(0) } -// printMessageError prints the error message according to [container.GetErrorMessage], +// printMessageError prints the error message according to [message.GetMessage], // or fallback prepended to err if an error message is not available. func printMessageError(fallback string, err error) { - m, ok := container.GetErrorMessage(err) + m, ok := message.GetMessage(err) if !ok { log.Println(fallback, err) return diff --git a/internal/app/shim.go b/internal/app/shim.go index 52aa530..27305e6 100644 --- a/internal/app/shim.go +++ b/internal/app/shim.go @@ -18,6 +18,7 @@ import ( "hakurei.app/container/bits" "hakurei.app/container/seccomp" "hakurei.app/hst" + "hakurei.app/message" ) //#include "shim-signal.h" @@ -57,7 +58,7 @@ func (p *shimParams) valid() bool { func ShimMain() { log.SetPrefix("shim: ") log.SetFlags(0) - msg := container.NewMsg(log.Default()) + msg := message.NewMsg(log.Default()) if err := container.SetDumpable(container.SUID_DUMP_DISABLE); err != nil { log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err) @@ -81,7 +82,7 @@ func ShimMain() { closeSetup = f if err = state.populateLocal(direct{}, msg); err != nil { - if m, ok := container.GetErrorMessage(err); ok { + if m, ok := message.GetMessage(err); ok { log.Fatal(m) } else { log.Fatalf("cannot populate local state: %v", err) @@ -114,7 +115,7 @@ func ShimMain() { } for _, op := range state.Shim.Ops { if err := op.toContainer(&stateParams); err != nil { - if m, ok := container.GetErrorMessage(err); ok { + if m, ok := message.GetMessage(err); ok { log.Fatal(m) } else { log.Fatalf("cannot create container state: %v", err) diff --git a/internal/app/spcontainer.go b/internal/app/spcontainer.go index 3827fa2..ee2833b 100644 --- a/internal/app/spcontainer.go +++ b/internal/app/spcontainer.go @@ -15,6 +15,7 @@ import ( "hakurei.app/container/fhs" "hakurei.app/container/seccomp" "hakurei.app/hst" + "hakurei.app/message" "hakurei.app/system/dbus" ) @@ -299,7 +300,7 @@ func resolveRoot(c *hst.ContainerConfig) (rootfs hst.FilesystemConfig, filesyste } // evalSymlinks calls syscallDispatcher.evalSymlinks but discards errors unwrapping to [fs.ErrNotExist]. -func evalSymlinks(msg container.Msg, k syscallDispatcher, v *string) error { +func evalSymlinks(msg message.Msg, k syscallDispatcher, v *string) error { if p, err := k.evalSymlinks(*v); err != nil { if !errors.Is(err, fs.ErrNotExist) { return err diff --git a/internal/app/state/multi.go b/internal/app/state/multi.go index 244b5c5..ca608f5 100644 --- a/internal/app/state/multi.go +++ b/internal/app/state/multi.go @@ -11,8 +11,8 @@ import ( "sync" "syscall" - "hakurei.app/container" "hakurei.app/hst" + "hakurei.app/message" ) // fine-grained locking and access @@ -22,7 +22,7 @@ type multiStore struct { // initialised backends backends *sync.Map - msg container.Msg + msg message.Msg mu sync.RWMutex } @@ -280,7 +280,7 @@ func (b *multiBackend) close() error { } // NewMulti returns an instance of the multi-file store. -func NewMulti(msg container.Msg, runDir string) Store { +func NewMulti(msg message.Msg, runDir string) Store { return &multiStore{ msg: msg, base: path.Join(runDir, "state"), diff --git a/internal/app/state/multi_test.go b/internal/app/state/multi_test.go index b8e1db9..fd99443 100644 --- a/internal/app/state/multi_test.go +++ b/internal/app/state/multi_test.go @@ -4,10 +4,10 @@ import ( "log" "testing" - "hakurei.app/container" "hakurei.app/internal/app/state" + "hakurei.app/message" ) func TestMulti(t *testing.T) { - testStore(t, state.NewMulti(container.NewMsg(log.New(log.Writer(), "multi: ", 0)), t.TempDir())) + testStore(t, state.NewMulti(message.NewMsg(log.New(log.Writer(), "multi: ", 0)), t.TempDir())) } diff --git a/ldd/exec.go b/ldd/exec.go index 5554d9b..ef5bf7b 100644 --- a/ldd/exec.go +++ b/ldd/exec.go @@ -13,6 +13,7 @@ import ( "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/container/seccomp" + "hakurei.app/message" ) const ( @@ -25,7 +26,7 @@ var ( msgStaticGlibc = []byte("not a dynamic executable") ) -func Exec(ctx context.Context, msg container.Msg, p string) ([]*Entry, error) { +func Exec(ctx context.Context, msg message.Msg, p string) ([]*Entry, error) { c, cancel := context.WithTimeout(ctx, lddTimeout) defer cancel() diff --git a/container/msg.go b/message/message.go similarity index 90% rename from container/msg.go rename to message/message.go index 38c38ec..36f8ae4 100644 --- a/container/msg.go +++ b/message/message.go @@ -1,4 +1,5 @@ -package container +// Package message provides interfaces and a base implementation for extended reporting on top of [log.Logger] +package message import ( "errors" @@ -6,19 +7,19 @@ import ( "sync/atomic" ) -// MessageError is an error with a user-facing message. -type MessageError interface { +// Error is an error with a user-facing message. +type Error interface { // Message returns a user-facing error message. Message() string error } -// GetErrorMessage returns whether an error implements [MessageError], and the message if it does. -func GetErrorMessage(err error) (string, bool) { - var e MessageError +// GetMessage returns whether an error implements [Error], and the message if it does. +func GetMessage(err error) (string, bool) { + var e Error if !errors.As(err, &e) || e == nil { - return zeroString, false + return "", false } return e.Message(), true } diff --git a/container/msg_test.go b/message/message_test.go similarity index 64% rename from container/msg_test.go rename to message/message_test.go index ed5c0c5..93ceaac 100644 --- a/container/msg_test.go +++ b/message/message_test.go @@ -1,4 +1,4 @@ -package container_test +package message_test import ( "bytes" @@ -11,6 +11,7 @@ import ( "hakurei.app/container" "hakurei.app/container/stub" + "hakurei.app/message" ) func TestMessageError(t *testing.T) { @@ -29,12 +30,12 @@ func TestMessageError(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - got, ok := container.GetErrorMessage(tc.err) + got, ok := message.GetMessage(tc.err) if got != tc.want { - t.Errorf("GetErrorMessage: %q, want %q", got, tc.want) + t.Errorf("GetMessage: %q, want %q", got, tc.want) } if ok != tc.wantOk { - t.Errorf("GetErrorMessage: ok = %v, want %v", ok, tc.wantOk) + t.Errorf("GetMessage: ok = %v, want %v", ok, tc.wantOk) } }) } @@ -46,9 +47,9 @@ func TestDefaultMsg(t *testing.T) { t.Run("logger", func(t *testing.T) { t.Run("nil", func(t *testing.T) { - got := container.NewMsg(nil).GetLogger() + got := message.NewMsg(nil).GetLogger() - if out := got.Writer().(*container.Suspendable).Downstream; out != log.Writer() { + if out := got.Writer().(*message.Suspendable).Downstream; out != log.Writer() { t.Errorf("GetLogger: Downstream = %#v", out) } @@ -59,13 +60,13 @@ func TestDefaultMsg(t *testing.T) { t.Run("takeover", func(t *testing.T) { l := log.New(io.Discard, "\x00", 0xdeadbeef) - got := container.NewMsg(l) + got := message.NewMsg(l) if logger := got.GetLogger(); logger != l { t.Errorf("GetLogger: %#v, want %#v", logger, l) } - if ds := l.Writer().(*container.Suspendable).Downstream; ds != io.Discard { + if ds := l.Writer().(*message.Suspendable).Downstream; ds != io.Discard { t.Errorf("GetLogger: Downstream = %#v", ds) } }) @@ -78,93 +79,93 @@ func TestDefaultMsg(t *testing.T) { pt, next []byte err error - f func(t *testing.T, msg container.Msg) + f func(t *testing.T, msg message.Msg) }{ - {"zero verbose", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"zero verbose", nil, nil, nil, func(t *testing.T, msg message.Msg) { if msg.IsVerbose() { t.Error("IsVerbose unexpected true") } }}, - {"swap false", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"swap false", nil, nil, nil, func(t *testing.T, msg message.Msg) { if msg.SwapVerbose(false) { t.Error("SwapVerbose unexpected true") } }}, - {"write discard", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"write discard", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.Verbose("\x00") msg.Verbosef("\x00") }}, - {"verbose false", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"verbose false", nil, nil, nil, func(t *testing.T, msg message.Msg) { if msg.IsVerbose() { t.Error("IsVerbose unexpected true") } }}, - {"swap true", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"swap true", nil, nil, nil, func(t *testing.T, msg message.Msg) { if msg.SwapVerbose(true) { t.Error("SwapVerbose unexpected true") } }}, - {"write verbose", []byte("test: \x00\n"), nil, nil, func(_ *testing.T, msg container.Msg) { + {"write verbose", []byte("test: \x00\n"), nil, nil, func(_ *testing.T, msg message.Msg) { msg.Verbose("\x00") }}, - {"write verbosef", []byte(`test: "\x00"` + "\n"), nil, nil, func(_ *testing.T, msg container.Msg) { + {"write verbosef", []byte(`test: "\x00"` + "\n"), nil, nil, func(_ *testing.T, msg message.Msg) { msg.Verbosef("%q", "\x00") }}, - {"verbose true", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"verbose true", nil, nil, nil, func(t *testing.T, msg message.Msg) { if !msg.IsVerbose() { t.Error("IsVerbose unexpected false") } }}, - {"resume noop", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"resume noop", nil, nil, nil, func(t *testing.T, msg message.Msg) { if msg.Resume() { t.Error("Resume unexpected success") } }}, - {"beforeExit noop", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"beforeExit noop", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.BeforeExit() }}, - {"beforeExit suspend", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"beforeExit suspend", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.Suspend() }}, - {"beforeExit message", []byte("test: beforeExit reached on suspended output\n"), nil, nil, func(_ *testing.T, msg container.Msg) { + {"beforeExit message", []byte("test: beforeExit reached on suspended output\n"), nil, nil, func(_ *testing.T, msg message.Msg) { msg.BeforeExit() }}, - {"post beforeExit resume noop", nil, nil, nil, func(t *testing.T, msg container.Msg) { + {"post beforeExit resume noop", nil, nil, nil, func(t *testing.T, msg message.Msg) { if msg.Resume() { t.Error("Resume unexpected success") } }}, - {"suspend", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"suspend", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.Suspend() }}, - {"suspend write", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"suspend write", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.GetLogger().Print("\x00") }}, - {"resume error", []byte("test: \x00\n"), []byte("test: cannot dump buffer on resume: unique error 0 injected by the test suite\n"), stub.UniqueError(0), func(t *testing.T, msg container.Msg) { + {"resume error", []byte("test: \x00\n"), []byte("test: cannot dump buffer on resume: unique error 0 injected by the test suite\n"), stub.UniqueError(0), func(t *testing.T, msg message.Msg) { if !msg.Resume() { t.Error("Resume unexpected failure") } }}, - {"suspend drop", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"suspend drop", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.Suspend() }}, - {"suspend write fill", nil, nil, nil, func(_ *testing.T, msg container.Msg) { + {"suspend write fill", nil, nil, nil, func(_ *testing.T, msg message.Msg) { msg.GetLogger().Print(strings.Repeat("\x00", suspendBufMax)) }}, - {"resume dropped", append([]byte("test: "), bytes.Repeat([]byte{0}, suspendBufMax-6)...), []byte("test: dropped 7 bytes while output is suspended\n"), nil, func(t *testing.T, msg container.Msg) { + {"resume dropped", append([]byte("test: "), bytes.Repeat([]byte{0}, suspendBufMax-6)...), []byte("test: dropped 7 bytes while output is suspended\n"), nil, func(t *testing.T, msg message.Msg) { if !msg.Resume() { t.Error("Resume unexpected failure") } }}, } - msg := container.NewMsg(log.New(&dw, "test: ", 0)) + msg := message.NewMsg(log.New(&dw, "test: ", 0)) for _, step := range steps { // these share the same writer, so cannot be subtests t.Logf("running step %q", step.name) diff --git a/container/output.go b/message/output.go similarity index 98% rename from container/output.go rename to message/output.go index 4d799eb..cb8df57 100644 --- a/container/output.go +++ b/message/output.go @@ -1,4 +1,4 @@ -package container +package message import ( "bytes" diff --git a/container/output_test.go b/message/output_test.go similarity index 97% rename from container/output_test.go rename to message/output_test.go index b6dedf1..ab69fe5 100644 --- a/container/output_test.go +++ b/message/output_test.go @@ -1,4 +1,4 @@ -package container_test +package message_test import ( "bytes" @@ -8,8 +8,8 @@ import ( "syscall" "testing" - "hakurei.app/container" "hakurei.app/container/stub" + "hakurei.app/message" ) func TestSuspendable(t *testing.T) { @@ -74,7 +74,7 @@ func TestSuspendable(t *testing.T) { var dw expectWriter - w := container.Suspendable{Downstream: &dw} + w := message.Suspendable{Downstream: &dw} for _, step := range steps { // these share the same writer, so cannot be subtests t.Logf("writing step %q", step.name) diff --git a/system/dbus/dbus_test.go b/system/dbus/dbus_test.go index 978b55e..299a463 100644 --- a/system/dbus/dbus_test.go +++ b/system/dbus/dbus_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "hakurei.app/container" "hakurei.app/helper" + "hakurei.app/message" "hakurei.app/system/dbus" ) @@ -93,9 +93,9 @@ func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) { t.Run("invalid start", func(t *testing.T) { if !useSandbox { - p = dbus.NewDirect(t.Context(), container.NewMsg(nil), nil, nil) + p = dbus.NewDirect(t.Context(), message.NewMsg(nil), nil, nil) } else { - p = dbus.New(t.Context(), container.NewMsg(nil), nil, nil) + p = dbus.New(t.Context(), message.NewMsg(nil), nil, nil) } if err := p.Start(); !errors.Is(err, syscall.ENOTRECOVERABLE) { @@ -128,9 +128,9 @@ func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) { defer cancel() output := new(strings.Builder) if !useSandbox { - p = dbus.NewDirect(ctx, container.NewMsg(nil), final, output) + p = dbus.NewDirect(ctx, message.NewMsg(nil), final, output) } else { - p = dbus.New(ctx, container.NewMsg(nil), final, output) + p = dbus.New(ctx, message.NewMsg(nil), final, output) } t.Run("invalid wait", func(t *testing.T) { diff --git a/system/dbus/export_test.go b/system/dbus/export_test.go index b1dc365..bc24f3f 100644 --- a/system/dbus/export_test.go +++ b/system/dbus/export_test.go @@ -4,11 +4,11 @@ import ( "context" "io" - "hakurei.app/container" + "hakurei.app/message" ) // NewDirect returns a new instance of [Proxy] with its sandbox disabled. -func NewDirect(ctx context.Context, msg container.Msg, final *Final, output io.Writer) *Proxy { +func NewDirect(ctx context.Context, msg message.Msg, final *Final, output io.Writer) *Proxy { p := New(ctx, msg, final, output) p.useSandbox = false return p diff --git a/system/dbus/proxy.go b/system/dbus/proxy.go index 535f233..385a8c7 100644 --- a/system/dbus/proxy.go +++ b/system/dbus/proxy.go @@ -6,9 +6,9 @@ import ( "sync" "syscall" - "hakurei.app/container" "hakurei.app/helper" "hakurei.app/hst" + "hakurei.app/message" ) // ProxyName is the file name or path to the proxy program. @@ -19,7 +19,7 @@ var ProxyName = "xdg-dbus-proxy" type Proxy struct { helper helper.Helper ctx context.Context - msg container.Msg + msg message.Msg cancel context.CancelCauseFunc cause func() error @@ -100,6 +100,6 @@ func Finalise(sessionBus, systemBus ProxyPair, session, system *hst.BusConfig) ( } // New returns a new instance of [Proxy]. -func New(ctx context.Context, msg container.Msg, final *Final, output io.Writer) *Proxy { +func New(ctx context.Context, msg message.Msg, final *Final, output io.Writer) *Proxy { return &Proxy{name: ProxyName, ctx: ctx, msg: msg, final: final, output: output, useSandbox: true} } diff --git a/system/output.go b/system/output.go index 022164f..71acace 100644 --- a/system/output.go +++ b/system/output.go @@ -6,6 +6,7 @@ import ( "os" "hakurei.app/container" + "hakurei.app/message" ) // OpError is returned by [I.Commit] and [I.Revert]. @@ -70,14 +71,14 @@ func printJoinedError(println func(v ...any), fallback string, err error) { error } if !errors.As(err, &joinErr) { - if m, ok := container.GetErrorMessage(err); ok { + if m, ok := message.GetMessage(err); ok { println(m) } else { println(fallback, err) } } else { for _, err = range joinErr.Unwrap() { - if m, ok := container.GetErrorMessage(err); ok { + if m, ok := message.GetMessage(err); ok { println(m) } else { println(err.Error()) diff --git a/system/output_test.go b/system/output_test.go index b144d79..d395b13 100644 --- a/system/output_test.go +++ b/system/output_test.go @@ -9,6 +9,7 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/message" ) func TestOpError(t *testing.T) { @@ -64,13 +65,13 @@ func TestOpError(t *testing.T) { }) t.Run("msg", func(t *testing.T) { - if got, ok := container.GetErrorMessage(tc.err); !ok { + if got, ok := message.GetMessage(tc.err); !ok { if tc.msg != "" { - t.Errorf("GetErrorMessage: err does not implement MessageError") + t.Errorf("GetMessage: err does not implement MessageError") } return } else if got != tc.msg { - t.Errorf("GetErrorMessage: %q, want %q", got, tc.msg) + t.Errorf("GetMessage: %q, want %q", got, tc.msg) } }) }) diff --git a/system/system.go b/system/system.go index 5599218..cadaab0 100644 --- a/system/system.go +++ b/system/system.go @@ -6,8 +6,8 @@ import ( "errors" "strings" - "hakurei.app/container" "hakurei.app/hst" + "hakurei.app/message" ) const ( @@ -68,7 +68,7 @@ func TypeString(e hst.Enablement) string { } // New returns the address of a new [I] targeting uid. -func New(ctx context.Context, msg container.Msg, uid int) (sys *I) { +func New(ctx context.Context, msg message.Msg, uid int) (sys *I) { if ctx == nil || msg == nil || uid < 0 { panic("invalid call to New") } @@ -89,7 +89,7 @@ type I struct { // the behaviour of Revert is only defined for up to one call reverted bool - msg container.Msg + msg message.Msg syscallDispatcher } diff --git a/system/system_test.go b/system/system_test.go index 5a361b9..91b6856 100644 --- a/system/system_test.go +++ b/system/system_test.go @@ -8,10 +8,10 @@ import ( "strconv" "testing" - "hakurei.app/container" "hakurei.app/container/check" "hakurei.app/container/stub" "hakurei.app/hst" + "hakurei.app/message" "hakurei.app/system/internal/xcb" ) @@ -74,7 +74,7 @@ func TestNew(t *testing.T) { t.Errorf("recover: %v, want %v", r, want) } }() - New(nil, container.NewMsg(nil), 0) + New(nil, message.NewMsg(nil), 0) }) t.Run("msg", func(t *testing.T) { @@ -94,11 +94,11 @@ func TestNew(t *testing.T) { t.Errorf("recover: %v, want %v", r, want) } }() - New(t.Context(), container.NewMsg(nil), -1) + New(t.Context(), message.NewMsg(nil), -1) }) }) - sys := New(t.Context(), container.NewMsg(nil), 0xdeadbeef) + sys := New(t.Context(), message.NewMsg(nil), 0xdeadbeef) if sys.ctx == nil { t.Error("New: ctx = nil") } @@ -115,51 +115,51 @@ func TestEqual(t *testing.T) { want bool }{ {"simple UID", - New(t.Context(), container.NewMsg(nil), 150), - New(t.Context(), container.NewMsg(nil), 150), + New(t.Context(), message.NewMsg(nil), 150), + New(t.Context(), message.NewMsg(nil), 150), true}, {"simple UID differ", - New(t.Context(), container.NewMsg(nil), 150), - New(t.Context(), container.NewMsg(nil), 151), + New(t.Context(), message.NewMsg(nil), 150), + New(t.Context(), message.NewMsg(nil), 151), false}, {"simple UID nil", - New(t.Context(), container.NewMsg(nil), 150), + New(t.Context(), message.NewMsg(nil), 150), nil, false}, {"op length mismatch", - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"), - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). Ensure(m("/run"), 0755), false}, {"op value mismatch", - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). Ensure(m("/run"), 0644), - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). Ensure(m("/run"), 0755), false}, {"op type mismatch", - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). CopyFile(new([]byte), m("/home/ophestra/xdg/config/pulse/cookie"), 0, 256), - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). Ensure(m("/run"), 0755), false}, {"op equals", - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). Ensure(m("/run"), 0755), - New(t.Context(), container.NewMsg(nil), 150). + New(t.Context(), message.NewMsg(nil), 150). ChangeHosts("chronos"). Ensure(m("/run"), 0755), true},