hst/enablement: move bits from system
All checks were successful
Test / Create distribution (push) Successful in 54s
Test / Sandbox (push) Successful in 2m33s
Test / Hakurei (push) Successful in 3m36s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 4m48s
Test / Hakurei (race detector) (push) Successful in 5m47s
Test / Flake checks (push) Successful in 1m40s
All checks were successful
Test / Create distribution (push) Successful in 54s
Test / Sandbox (push) Successful in 2m33s
Test / Hakurei (push) Successful in 3m36s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 4m48s
Test / Hakurei (race detector) (push) Successful in 5m47s
Test / Flake checks (push) Successful in 1m40s
This is part of the hst API, should not be in the implementation package. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
dc467493d8
commit
44ba7a5f02
@ -17,7 +17,6 @@ import (
|
|||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
"hakurei.app/internal/app"
|
"hakurei.app/internal/app"
|
||||||
"hakurei.app/internal/app/state"
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/system"
|
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,18 +127,18 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE
|
|||||||
config.Home = a
|
config.Home = a
|
||||||
}
|
}
|
||||||
|
|
||||||
var e system.Enablement
|
var e hst.Enablement
|
||||||
if flagWayland {
|
if flagWayland {
|
||||||
e |= system.EWayland
|
e |= hst.EWayland
|
||||||
}
|
}
|
||||||
if flagX11 {
|
if flagX11 {
|
||||||
e |= system.EX11
|
e |= hst.EX11
|
||||||
}
|
}
|
||||||
if flagDBus {
|
if flagDBus {
|
||||||
e |= system.EDBus
|
e |= hst.EDBus
|
||||||
}
|
}
|
||||||
if flagPulse {
|
if flagPulse {
|
||||||
e |= system.EPulse
|
e |= hst.EPulse
|
||||||
}
|
}
|
||||||
config.Enablements = hst.NewEnablements(e)
|
config.Enablements = hst.NewEnablements(e)
|
||||||
|
|
||||||
|
@ -2,15 +2,56 @@ package hst
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewEnablements returns the address of [system.Enablement] as [Enablements].
|
// Enablement represents an optional host service to export to the target user.
|
||||||
func NewEnablements(e system.Enablement) *Enablements { return (*Enablements)(&e) }
|
type Enablement byte
|
||||||
|
|
||||||
// enablementsJSON is the [json] representation of the [system.Enablement] bit field.
|
const (
|
||||||
|
EWayland Enablement = 1 << iota
|
||||||
|
EX11
|
||||||
|
EDBus
|
||||||
|
EPulse
|
||||||
|
|
||||||
|
EM
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e Enablement) String() string {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return "(no enablements)"
|
||||||
|
case EWayland:
|
||||||
|
return "wayland"
|
||||||
|
case EX11:
|
||||||
|
return "x11"
|
||||||
|
case EDBus:
|
||||||
|
return "dbus"
|
||||||
|
case EPulse:
|
||||||
|
return "pulseaudio"
|
||||||
|
default:
|
||||||
|
buf := new(strings.Builder)
|
||||||
|
buf.Grow(32)
|
||||||
|
|
||||||
|
for i := Enablement(1); i < EM; i <<= 1 {
|
||||||
|
if e&i != 0 {
|
||||||
|
buf.WriteString(", " + i.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf.Len() == 0 {
|
||||||
|
return fmt.Sprintf("e%x", byte(e))
|
||||||
|
}
|
||||||
|
return strings.TrimPrefix(buf.String(), ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnablements returns the address of [Enablement] as [Enablements].
|
||||||
|
func NewEnablements(e Enablement) *Enablements { return (*Enablements)(&e) }
|
||||||
|
|
||||||
|
// enablementsJSON is the [json] representation of the [Enablement] bit field.
|
||||||
type enablementsJSON struct {
|
type enablementsJSON struct {
|
||||||
Wayland bool `json:"wayland,omitempty"`
|
Wayland bool `json:"wayland,omitempty"`
|
||||||
X11 bool `json:"x11,omitempty"`
|
X11 bool `json:"x11,omitempty"`
|
||||||
@ -18,15 +59,15 @@ type enablementsJSON struct {
|
|||||||
Pulse bool `json:"pulse,omitempty"`
|
Pulse bool `json:"pulse,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enablements is the [json] adapter for [system.Enablement].
|
// Enablements is the [json] adapter for [Enablement].
|
||||||
type Enablements system.Enablement
|
type Enablements Enablement
|
||||||
|
|
||||||
// Unwrap returns the underlying [system.Enablement].
|
// Unwrap returns the underlying [Enablement].
|
||||||
func (e *Enablements) Unwrap() system.Enablement {
|
func (e *Enablements) Unwrap() Enablement {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return system.Enablement(*e)
|
return Enablement(*e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Enablements) MarshalJSON() ([]byte, error) {
|
func (e *Enablements) MarshalJSON() ([]byte, error) {
|
||||||
@ -34,10 +75,10 @@ func (e *Enablements) MarshalJSON() ([]byte, error) {
|
|||||||
return nil, syscall.EINVAL
|
return nil, syscall.EINVAL
|
||||||
}
|
}
|
||||||
return json.Marshal(&enablementsJSON{
|
return json.Marshal(&enablementsJSON{
|
||||||
Wayland: system.Enablement(*e)&system.EWayland != 0,
|
Wayland: Enablement(*e)&EWayland != 0,
|
||||||
X11: system.Enablement(*e)&system.EX11 != 0,
|
X11: Enablement(*e)&EX11 != 0,
|
||||||
DBus: system.Enablement(*e)&system.EDBus != 0,
|
DBus: Enablement(*e)&EDBus != 0,
|
||||||
Pulse: system.Enablement(*e)&system.EPulse != 0,
|
Pulse: Enablement(*e)&EPulse != 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,18 +92,18 @@ func (e *Enablements) UnmarshalJSON(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ve system.Enablement
|
var ve Enablement
|
||||||
if v.Wayland {
|
if v.Wayland {
|
||||||
ve |= system.EWayland
|
ve |= EWayland
|
||||||
}
|
}
|
||||||
if v.X11 {
|
if v.X11 {
|
||||||
ve |= system.EX11
|
ve |= EX11
|
||||||
}
|
}
|
||||||
if v.DBus {
|
if v.DBus {
|
||||||
ve |= system.EDBus
|
ve |= EDBus
|
||||||
}
|
}
|
||||||
if v.Pulse {
|
if v.Pulse {
|
||||||
ve |= system.EPulse
|
ve |= EPulse
|
||||||
}
|
}
|
||||||
*e = Enablements(ve)
|
*e = Enablements(ve)
|
||||||
return nil
|
return nil
|
||||||
|
@ -7,9 +7,44 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestEnablementString(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
flags hst.Enablement
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{0, "(no enablements)"},
|
||||||
|
{hst.EWayland, "wayland"},
|
||||||
|
{hst.EX11, "x11"},
|
||||||
|
{hst.EDBus, "dbus"},
|
||||||
|
{hst.EPulse, "pulseaudio"},
|
||||||
|
{hst.EWayland | hst.EX11, "wayland, x11"},
|
||||||
|
{hst.EWayland | hst.EDBus, "wayland, dbus"},
|
||||||
|
{hst.EWayland | hst.EPulse, "wayland, pulseaudio"},
|
||||||
|
{hst.EX11 | hst.EDBus, "x11, dbus"},
|
||||||
|
{hst.EX11 | hst.EPulse, "x11, pulseaudio"},
|
||||||
|
{hst.EDBus | hst.EPulse, "dbus, pulseaudio"},
|
||||||
|
{hst.EWayland | hst.EX11 | hst.EDBus, "wayland, x11, dbus"},
|
||||||
|
{hst.EWayland | hst.EX11 | hst.EPulse, "wayland, x11, pulseaudio"},
|
||||||
|
{hst.EWayland | hst.EDBus | hst.EPulse, "wayland, dbus, pulseaudio"},
|
||||||
|
{hst.EX11 | hst.EDBus | hst.EPulse, "x11, dbus, pulseaudio"},
|
||||||
|
{hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse, "wayland, x11, dbus, pulseaudio"},
|
||||||
|
|
||||||
|
{1 << 5, "e20"},
|
||||||
|
{1 << 6, "e40"},
|
||||||
|
{1 << 7, "e80"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.want, func(t *testing.T) {
|
||||||
|
if got := tc.flags.String(); got != tc.want {
|
||||||
|
t.Errorf("String: %q, want %q", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEnablements(t *testing.T) {
|
func TestEnablements(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@ -19,11 +54,11 @@ func TestEnablements(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{"nil", nil, "null", `{"value":null,"magic":3236757504}`},
|
{"nil", nil, "null", `{"value":null,"magic":3236757504}`},
|
||||||
{"zero", hst.NewEnablements(0), `{}`, `{"value":{},"magic":3236757504}`},
|
{"zero", hst.NewEnablements(0), `{}`, `{"value":{},"magic":3236757504}`},
|
||||||
{"wayland", hst.NewEnablements(system.EWayland), `{"wayland":true}`, `{"value":{"wayland":true},"magic":3236757504}`},
|
{"wayland", hst.NewEnablements(hst.EWayland), `{"wayland":true}`, `{"value":{"wayland":true},"magic":3236757504}`},
|
||||||
{"x11", hst.NewEnablements(system.EX11), `{"x11":true}`, `{"value":{"x11":true},"magic":3236757504}`},
|
{"x11", hst.NewEnablements(hst.EX11), `{"x11":true}`, `{"value":{"x11":true},"magic":3236757504}`},
|
||||||
{"dbus", hst.NewEnablements(system.EDBus), `{"dbus":true}`, `{"value":{"dbus":true},"magic":3236757504}`},
|
{"dbus", hst.NewEnablements(hst.EDBus), `{"dbus":true}`, `{"value":{"dbus":true},"magic":3236757504}`},
|
||||||
{"pulse", hst.NewEnablements(system.EPulse), `{"pulse":true}`, `{"value":{"pulse":true},"magic":3236757504}`},
|
{"pulse", hst.NewEnablements(hst.EPulse), `{"pulse":true}`, `{"value":{"pulse":true},"magic":3236757504}`},
|
||||||
{"all", hst.NewEnablements(system.EWayland | system.EX11 | system.EDBus | system.EPulse), `{"wayland":true,"x11":true,"dbus":true,"pulse":true}`, `{"value":{"wayland":true,"x11":true,"dbus":true,"pulse":true},"magic":3236757504}`},
|
{"all", hst.NewEnablements(hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse), `{"wayland":true,"x11":true,"dbus":true,"pulse":true}`, `{"value":{"wayland":true,"x11":true,"dbus":true,"pulse":true},"magic":3236757504}`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@ -88,7 +123,7 @@ func TestEnablements(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("val", func(t *testing.T) {
|
t.Run("val", func(t *testing.T) {
|
||||||
if got := hst.NewEnablements(system.EWayland | system.EPulse).Unwrap(); got != system.EWayland|system.EPulse {
|
if got := hst.NewEnablements(hst.EWayland | hst.EPulse).Unwrap(); got != hst.EWayland|hst.EPulse {
|
||||||
t.Errorf("Unwrap: %v", got)
|
t.Errorf("Unwrap: %v", got)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
"hakurei.app/system"
|
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,7 +70,7 @@ func Template() *Config {
|
|||||||
"--ozone-platform=wayland",
|
"--ozone-platform=wayland",
|
||||||
},
|
},
|
||||||
|
|
||||||
Enablements: NewEnablements(system.EWayland | system.EDBus | system.EPulse),
|
Enablements: NewEnablements(EWayland | EDBus | EPulse),
|
||||||
|
|
||||||
SessionBus: &dbus.Config{
|
SessionBus: &dbus.Config{
|
||||||
See: nil,
|
See: nil,
|
||||||
|
@ -121,7 +121,7 @@ func TestApp(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Filter: true,
|
Filter: true,
|
||||||
},
|
},
|
||||||
Enablements: hst.NewEnablements(system.EWayland | system.EDBus | system.EPulse),
|
Enablements: hst.NewEnablements(hst.EWayland | hst.EDBus | hst.EPulse),
|
||||||
},
|
},
|
||||||
state.ID{
|
state.ID{
|
||||||
0xeb, 0xf0, 0x83, 0xd1,
|
0xeb, 0xf0, 0x83, 0xd1,
|
||||||
@ -229,7 +229,7 @@ func TestApp(t *testing.T) {
|
|||||||
&hst.Config{
|
&hst.Config{
|
||||||
ID: "org.chromium.Chromium",
|
ID: "org.chromium.Chromium",
|
||||||
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
|
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
|
||||||
Enablements: hst.NewEnablements(system.EWayland | system.EDBus | system.EPulse),
|
Enablements: hst.NewEnablements(hst.EWayland | hst.EDBus | hst.EPulse),
|
||||||
Shell: m("/run/current-system/sw/bin/zsh"),
|
Shell: m("/run/current-system/sw/bin/zsh"),
|
||||||
|
|
||||||
Container: &hst.ContainerConfig{
|
Container: &hst.ContainerConfig{
|
||||||
@ -288,7 +288,7 @@ func TestApp(t *testing.T) {
|
|||||||
Ensure("/tmp/hakurei.0/tmpdir/1", 01700).UpdatePermType(system.User, "/tmp/hakurei.0/tmpdir/1", acl.Read, acl.Write, acl.Execute).
|
Ensure("/tmp/hakurei.0/tmpdir/1", 01700).UpdatePermType(system.User, "/tmp/hakurei.0/tmpdir/1", acl.Read, acl.Write, acl.Execute).
|
||||||
Ensure("/run/user/1971/hakurei", 0700).UpdatePermType(system.User, "/run/user/1971/hakurei", acl.Execute).
|
Ensure("/run/user/1971/hakurei", 0700).UpdatePermType(system.User, "/run/user/1971/hakurei", acl.Execute).
|
||||||
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
|
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
|
||||||
UpdatePermType(system.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute).
|
UpdatePermType(hst.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute).
|
||||||
Ephemeral(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", 0700).UpdatePermType(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", acl.Execute).
|
Ephemeral(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", 0700).UpdatePermType(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", acl.Execute).
|
||||||
Link("/run/user/1971/pulse/native", "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse").
|
Link("/run/user/1971/pulse/native", "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse").
|
||||||
CopyFile(nil, "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
|
CopyFile(nil, "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
|
||||||
|
@ -241,7 +241,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, config *hst.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bind GPU stuff
|
// bind GPU stuff
|
||||||
if config.Enablements.Unwrap()&(system.EX11|system.EWayland) != 0 {
|
if config.Enablements.Unwrap()&(hst.EX11|hst.EWayland) != 0 {
|
||||||
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}})
|
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}})
|
||||||
}
|
}
|
||||||
// opportunistically bind kvm
|
// opportunistically bind kvm
|
||||||
@ -353,7 +353,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, config *hst.C
|
|||||||
k.env[term] = t
|
k.env[term] = t
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Enablements.Unwrap()&system.EWayland != 0 {
|
if config.Enablements.Unwrap()&hst.EWayland != 0 {
|
||||||
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
|
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
|
||||||
var socketPath *container.Absolute
|
var socketPath *container.Absolute
|
||||||
if name, ok := k.lookupEnv(wayland.WaylandDisplay); !ok {
|
if name, ok := k.lookupEnv(wayland.WaylandDisplay); !ok {
|
||||||
@ -382,11 +382,11 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, config *hst.C
|
|||||||
msg.Verbose("direct wayland access, PROCEED WITH CAUTION")
|
msg.Verbose("direct wayland access, PROCEED WITH CAUTION")
|
||||||
share.ensureRuntimeDir()
|
share.ensureRuntimeDir()
|
||||||
k.container.Bind(socketPath, innerPath, 0)
|
k.container.Bind(socketPath, innerPath, 0)
|
||||||
k.sys.UpdatePermType(system.EWayland, socketPath.String(), acl.Read, acl.Write, acl.Execute)
|
k.sys.UpdatePermType(hst.EWayland, socketPath.String(), acl.Read, acl.Write, acl.Execute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Enablements.Unwrap()&system.EX11 != 0 {
|
if config.Enablements.Unwrap()&hst.EX11 != 0 {
|
||||||
if d, ok := k.lookupEnv(display); !ok {
|
if d, ok := k.lookupEnv(display); !ok {
|
||||||
return newWithMessage("DISPLAY is not set")
|
return newWithMessage("DISPLAY is not set")
|
||||||
} else {
|
} else {
|
||||||
@ -410,7 +410,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, config *hst.C
|
|||||||
return &hst.AppError{Step: fmt.Sprintf("access X11 socket %q", socketPath), Err: err}
|
return &hst.AppError{Step: fmt.Sprintf("access X11 socket %q", socketPath), Err: err}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
k.sys.UpdatePermType(system.EX11, socketPath.String(), acl.Read, acl.Write, acl.Execute)
|
k.sys.UpdatePermType(hst.EX11, socketPath.String(), acl.Read, acl.Write, acl.Execute)
|
||||||
if !config.Container.HostAbstract {
|
if !config.Container.HostAbstract {
|
||||||
d = "unix:" + socketPath.String()
|
d = "unix:" + socketPath.String()
|
||||||
}
|
}
|
||||||
@ -423,7 +423,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, config *hst.C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Enablements.Unwrap()&system.EPulse != 0 {
|
if config.Enablements.Unwrap()&hst.EPulse != 0 {
|
||||||
// PulseAudio runtime directory (usually `/run/user/%d/pulse`)
|
// PulseAudio runtime directory (usually `/run/user/%d/pulse`)
|
||||||
pulseRuntimeDir := share.sc.RuntimePath.Append("pulse")
|
pulseRuntimeDir := share.sc.RuntimePath.Append("pulse")
|
||||||
// PulseAudio socket (usually `/run/user/%d/pulse/native`)
|
// PulseAudio socket (usually `/run/user/%d/pulse/native`)
|
||||||
@ -527,7 +527,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, config *hst.C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Enablements.Unwrap()&system.EDBus != 0 {
|
if config.Enablements.Unwrap()&hst.EDBus != 0 {
|
||||||
// ensure dbus session bus defaults
|
// ensure dbus session bus defaults
|
||||||
if config.SessionBus == nil {
|
if config.SessionBus == nil {
|
||||||
config.SessionBus = dbus.NewConfig(config.ID, true, true)
|
config.SessionBus = dbus.NewConfig(config.ID, true, true)
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
"hakurei.app/internal/app/state"
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
@ -146,7 +147,7 @@ func (ms mainState) beforeExit(isFault bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rt system.Enablement
|
var rt hst.Enablement
|
||||||
if states, err := c.Load(); err != nil {
|
if states, err := c.Load(); err != nil {
|
||||||
// it is impossible to continue from this point;
|
// it is impossible to continue from this point;
|
||||||
// revert per-process state here to limit damage
|
// revert per-process state here to limit damage
|
||||||
@ -182,7 +183,7 @@ func (ms mainState) beforeExit(isFault bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ec |= rt ^ (system.EWayland | system.EX11 | system.EDBus | system.EPulse)
|
ec |= rt ^ (hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse)
|
||||||
if ms.IsVerbose() {
|
if ms.IsVerbose() {
|
||||||
if ec > 0 {
|
if ec > 0 {
|
||||||
ms.Verbose("reverting operations scope", system.TypeString(ec))
|
ms.Verbose("reverting operations scope", system.TypeString(ec))
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,19 +17,19 @@ func (sys *I) UpdatePerm(path string, perms ...acl.Perm) *I {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePermType maintains [acl.Perms] on a file until its [Enablement] is no longer satisfied.
|
// UpdatePermType maintains [acl.Perms] on a file until its [Enablement] is no longer satisfied.
|
||||||
func (sys *I) UpdatePermType(et Enablement, path string, perms ...acl.Perm) *I {
|
func (sys *I) UpdatePermType(et hst.Enablement, path string, perms ...acl.Perm) *I {
|
||||||
sys.ops = append(sys.ops, &aclUpdateOp{et, path, perms})
|
sys.ops = append(sys.ops, &aclUpdateOp{et, path, perms})
|
||||||
return sys
|
return sys
|
||||||
}
|
}
|
||||||
|
|
||||||
// aclUpdateOp implements [I.UpdatePermType].
|
// aclUpdateOp implements [I.UpdatePermType].
|
||||||
type aclUpdateOp struct {
|
type aclUpdateOp struct {
|
||||||
et Enablement
|
et hst.Enablement
|
||||||
path string
|
path string
|
||||||
perms acl.Perms
|
perms acl.Perms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclUpdateOp) Type() Enablement { return a.et }
|
func (a *aclUpdateOp) Type() hst.Enablement { return a.et }
|
||||||
|
|
||||||
func (a *aclUpdateOp) apply(sys *I) error {
|
func (a *aclUpdateOp) apply(sys *I) error {
|
||||||
sys.msg.Verbose("applying ACL", a)
|
sys.msg.Verbose("applying ACL", a)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,9 +95,9 @@ func TestACLUpdateOp(t *testing.T) {
|
|||||||
}, stub.Expect{}},
|
}, stub.Expect{}},
|
||||||
|
|
||||||
{"wayland", 0xdeadbeef, func(_ *testing.T, sys *I) {
|
{"wayland", 0xdeadbeef, func(_ *testing.T, sys *I) {
|
||||||
sys.UpdatePermType(EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute)
|
sys.UpdatePermType(hst.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute)
|
||||||
}, []Op{
|
}, []Op{
|
||||||
&aclUpdateOp{EWayland, "/run/user/1971/wayland-0", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
|
&aclUpdateOp{hst.EWayland, "/run/user/1971/wayland-0", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
|
||||||
}, stub.Expect{}},
|
}, stub.Expect{}},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -106,34 +107,34 @@ func TestACLUpdateOp(t *testing.T) {
|
|||||||
|
|
||||||
{"et differs",
|
{"et differs",
|
||||||
&aclUpdateOp{
|
&aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-0",
|
hst.EWayland, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, &aclUpdateOp{
|
}, &aclUpdateOp{
|
||||||
EX11, "/run/user/1971/wayland-0",
|
hst.EX11, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, false},
|
}, false},
|
||||||
|
|
||||||
{"path differs", &aclUpdateOp{
|
{"path differs", &aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-0",
|
hst.EWayland, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, &aclUpdateOp{
|
}, &aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-1",
|
hst.EWayland, "/run/user/1971/wayland-1",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, false},
|
}, false},
|
||||||
|
|
||||||
{"perms differs", &aclUpdateOp{
|
{"perms differs", &aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-0",
|
hst.EWayland, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, &aclUpdateOp{
|
}, &aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-0",
|
hst.EWayland, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write},
|
[]acl.Perm{acl.Read, acl.Write},
|
||||||
}, false},
|
}, false},
|
||||||
|
|
||||||
{"equals", &aclUpdateOp{
|
{"equals", &aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-0",
|
hst.EWayland, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, &aclUpdateOp{
|
}, &aclUpdateOp{
|
||||||
EWayland, "/run/user/1971/wayland-0",
|
hst.EWayland, "/run/user/1971/wayland-0",
|
||||||
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
|
||||||
}, true},
|
}, true},
|
||||||
})
|
})
|
||||||
@ -160,23 +161,23 @@ func TestACLUpdateOp(t *testing.T) {
|
|||||||
`--x type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2"`},
|
`--x type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2"`},
|
||||||
|
|
||||||
{"wayland",
|
{"wayland",
|
||||||
&aclUpdateOp{EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", []acl.Perm{acl.Read, acl.Write}},
|
&aclUpdateOp{hst.EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", []acl.Perm{acl.Read, acl.Write}},
|
||||||
EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland",
|
hst.EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland",
|
||||||
`rw- type: wayland path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland"`},
|
`rw- type: wayland path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland"`},
|
||||||
|
|
||||||
{"x11",
|
{"x11",
|
||||||
&aclUpdateOp{EX11, "/tmp/.X11-unix/X0", []acl.Perm{acl.Read, acl.Execute}},
|
&aclUpdateOp{hst.EX11, "/tmp/.X11-unix/X0", []acl.Perm{acl.Read, acl.Execute}},
|
||||||
EX11, "/tmp/.X11-unix/X0",
|
hst.EX11, "/tmp/.X11-unix/X0",
|
||||||
`r-x type: x11 path: "/tmp/.X11-unix/X0"`},
|
`r-x type: x11 path: "/tmp/.X11-unix/X0"`},
|
||||||
|
|
||||||
{"dbus",
|
{"dbus",
|
||||||
&aclUpdateOp{EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", []acl.Perm{acl.Write, acl.Execute}},
|
&aclUpdateOp{hst.EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", []acl.Perm{acl.Write, acl.Execute}},
|
||||||
EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus",
|
hst.EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus",
|
||||||
`-wx type: dbus path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus"`},
|
`-wx type: dbus path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus"`},
|
||||||
|
|
||||||
{"pulseaudio",
|
{"pulseaudio",
|
||||||
&aclUpdateOp{EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
|
&aclUpdateOp{hst.EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
|
||||||
EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse",
|
hst.EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse",
|
||||||
`rwx type: pulseaudio path: "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse"`},
|
`rwx type: pulseaudio path: "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse"`},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ type dbusProxyOp struct {
|
|||||||
system bool
|
system bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbusProxyOp) Type() Enablement { return Process }
|
func (d *dbusProxyOp) Type() hst.Enablement { return Process }
|
||||||
|
|
||||||
func (d *dbusProxyOp) apply(sys *I) error {
|
func (d *dbusProxyOp) apply(sys *I) error {
|
||||||
sys.msg.Verbosef("session bus proxy on %q for upstream %q", d.final.Session[1], d.final.Session[0])
|
sys.msg.Verbosef("session bus proxy on %q for upstream %q", d.final.Session[1], d.final.Session[0])
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
"hakurei.app/system/internal/xcb"
|
"hakurei.app/system/internal/xcb"
|
||||||
@ -26,7 +27,7 @@ func call(name string, args stub.ExpectArgs, ret any, err error) stub.Call {
|
|||||||
type opBehaviourTestCase struct {
|
type opBehaviourTestCase struct {
|
||||||
name string
|
name string
|
||||||
uid int
|
uid int
|
||||||
ec Enablement
|
ec hst.Enablement
|
||||||
op Op
|
op Op
|
||||||
|
|
||||||
apply []stub.Call
|
apply []stub.Call
|
||||||
@ -142,7 +143,7 @@ type opMetaTestCase struct {
|
|||||||
name string
|
name string
|
||||||
op Op
|
op Op
|
||||||
|
|
||||||
wantType Enablement
|
wantType hst.Enablement
|
||||||
wantPath string
|
wantPath string
|
||||||
wantString string
|
wantString string
|
||||||
}
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enablement represents an optional host service to export to the target user.
|
|
||||||
type Enablement byte
|
|
||||||
|
|
||||||
const (
|
|
||||||
EWayland Enablement = 1 << iota
|
|
||||||
EX11
|
|
||||||
EDBus
|
|
||||||
EPulse
|
|
||||||
|
|
||||||
EM
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e Enablement) String() string {
|
|
||||||
switch e {
|
|
||||||
case 0:
|
|
||||||
return "(no enablements)"
|
|
||||||
case EWayland:
|
|
||||||
return "wayland"
|
|
||||||
case EX11:
|
|
||||||
return "x11"
|
|
||||||
case EDBus:
|
|
||||||
return "dbus"
|
|
||||||
case EPulse:
|
|
||||||
return "pulseaudio"
|
|
||||||
default:
|
|
||||||
buf := new(strings.Builder)
|
|
||||||
buf.Grow(32)
|
|
||||||
|
|
||||||
for i := Enablement(1); i < EM; i <<= 1 {
|
|
||||||
if e&i != 0 {
|
|
||||||
buf.WriteString(", " + i.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if buf.Len() == 0 {
|
|
||||||
return fmt.Sprintf("e%x", byte(e))
|
|
||||||
}
|
|
||||||
return strings.TrimPrefix(buf.String(), ", ")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package system_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEnablementString(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
flags system.Enablement
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{0, "(no enablements)"},
|
|
||||||
{system.EWayland, "wayland"},
|
|
||||||
{system.EX11, "x11"},
|
|
||||||
{system.EDBus, "dbus"},
|
|
||||||
{system.EPulse, "pulseaudio"},
|
|
||||||
{system.EWayland | system.EX11, "wayland, x11"},
|
|
||||||
{system.EWayland | system.EDBus, "wayland, dbus"},
|
|
||||||
{system.EWayland | system.EPulse, "wayland, pulseaudio"},
|
|
||||||
{system.EX11 | system.EDBus, "x11, dbus"},
|
|
||||||
{system.EX11 | system.EPulse, "x11, pulseaudio"},
|
|
||||||
{system.EDBus | system.EPulse, "dbus, pulseaudio"},
|
|
||||||
{system.EWayland | system.EX11 | system.EDBus, "wayland, x11, dbus"},
|
|
||||||
{system.EWayland | system.EX11 | system.EPulse, "wayland, x11, pulseaudio"},
|
|
||||||
{system.EWayland | system.EDBus | system.EPulse, "wayland, dbus, pulseaudio"},
|
|
||||||
{system.EX11 | system.EDBus | system.EPulse, "x11, dbus, pulseaudio"},
|
|
||||||
{system.EWayland | system.EX11 | system.EDBus | system.EPulse, "wayland, x11, dbus, pulseaudio"},
|
|
||||||
|
|
||||||
{1 << 5, "e20"},
|
|
||||||
{1 << 6, "e40"},
|
|
||||||
{1 << 7, "e80"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.want, func(t *testing.T) {
|
|
||||||
if got := tc.flags.String(); got != tc.want {
|
|
||||||
t.Errorf("String: %q, want %q", got, tc.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,24 +2,26 @@ package system
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Link calls LinkFileType with the [Process] criteria.
|
// Link calls LinkFileType with the [Process] criteria.
|
||||||
func (sys *I) Link(oldname, newname string) *I { return sys.LinkFileType(Process, oldname, newname) }
|
func (sys *I) Link(oldname, newname string) *I { return sys.LinkFileType(Process, oldname, newname) }
|
||||||
|
|
||||||
// LinkFileType maintains a hardlink until its [Enablement] is no longer satisfied.
|
// LinkFileType maintains a hardlink until its [Enablement] is no longer satisfied.
|
||||||
func (sys *I) LinkFileType(et Enablement, oldname, newname string) *I {
|
func (sys *I) LinkFileType(et hst.Enablement, oldname, newname string) *I {
|
||||||
sys.ops = append(sys.ops, &hardlinkOp{et, newname, oldname})
|
sys.ops = append(sys.ops, &hardlinkOp{et, newname, oldname})
|
||||||
return sys
|
return sys
|
||||||
}
|
}
|
||||||
|
|
||||||
// hardlinkOp implements [I.LinkFileType].
|
// hardlinkOp implements [I.LinkFileType].
|
||||||
type hardlinkOp struct {
|
type hardlinkOp struct {
|
||||||
et Enablement
|
et hst.Enablement
|
||||||
dst, src string
|
dst, src string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *hardlinkOp) Type() Enablement { return l.et }
|
func (l *hardlinkOp) Type() hst.Enablement { return l.et }
|
||||||
|
|
||||||
func (l *hardlinkOp) apply(sys *I) error {
|
func (l *hardlinkOp) apply(sys *I) error {
|
||||||
sys.msg.Verbose("linking", l)
|
sys.msg.Verbose("linking", l)
|
||||||
|
@ -4,32 +4,33 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHardlinkOp(t *testing.T) {
|
func TestHardlinkOp(t *testing.T) {
|
||||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||||
{"link", 0xdeadbeef, 0xff, &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
{"link", 0xdeadbeef, 0xff, &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
||||||
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
||||||
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, stub.UniqueError(1)),
|
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, stub.UniqueError(1)),
|
||||||
}, &OpError{Op: "hardlink", Err: stub.UniqueError(1)}, nil, nil},
|
}, &OpError{Op: "hardlink", Err: stub.UniqueError(1)}, nil, nil},
|
||||||
|
|
||||||
{"remove", 0xdeadbeef, 0xff, &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
{"remove", 0xdeadbeef, 0xff, &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
||||||
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
||||||
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, nil),
|
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("verbosef", stub.ExpectArgs{"removing hard link %q", []any{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"removing hard link %q", []any{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}}, nil, nil),
|
||||||
call("remove", stub.ExpectArgs{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, stub.UniqueError(0)),
|
call("remove", stub.ExpectArgs{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, stub.UniqueError(0)),
|
||||||
}, &OpError{Op: "hardlink", Err: stub.UniqueError(0), Revert: true}},
|
}, &OpError{Op: "hardlink", Err: stub.UniqueError(0), Revert: true}},
|
||||||
|
|
||||||
{"success skip", 0xdeadbeef, EWayland | EX11, &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
{"success skip", 0xdeadbeef, hst.EWayland | hst.EX11, &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
||||||
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
||||||
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, nil),
|
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("verbosef", stub.ExpectArgs{"skipping hard link %q", []any{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"skipping hard link %q", []any{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"success", 0xdeadbeef, 0xff, &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
{"success", 0xdeadbeef, 0xff, &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}, []stub.Call{
|
||||||
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
call("verbose", stub.ExpectArgs{[]any{"linking", &hardlinkOp{hst.EPulse, "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse", "/run/user/1000/pulse/native"}}}, nil, nil),
|
||||||
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, nil),
|
call("link", stub.ExpectArgs{"/run/user/1000/pulse/native", "/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}, nil, nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("verbosef", stub.ExpectArgs{"removing hard link %q", []any{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"removing hard link %q", []any{"/run/user/1000/hakurei/9663730666a44cfc2a81610379e02ed6/pulse"}}, nil, nil),
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure ensures the existence of a directory.
|
// Ensure ensures the existence of a directory.
|
||||||
@ -13,20 +15,20 @@ func (sys *I) Ensure(name string, perm os.FileMode) *I {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ephemeral ensures the existence of a directory until its [Enablement] is no longer satisfied.
|
// Ephemeral ensures the existence of a directory until its [Enablement] is no longer satisfied.
|
||||||
func (sys *I) Ephemeral(et Enablement, name string, perm os.FileMode) *I {
|
func (sys *I) Ephemeral(et hst.Enablement, name string, perm os.FileMode) *I {
|
||||||
sys.ops = append(sys.ops, &mkdirOp{et, name, perm, true})
|
sys.ops = append(sys.ops, &mkdirOp{et, name, perm, true})
|
||||||
return sys
|
return sys
|
||||||
}
|
}
|
||||||
|
|
||||||
// mkdirOp implements [I.Ensure] and [I.Ephemeral].
|
// mkdirOp implements [I.Ensure] and [I.Ephemeral].
|
||||||
type mkdirOp struct {
|
type mkdirOp struct {
|
||||||
et Enablement
|
et hst.Enablement
|
||||||
path string
|
path string
|
||||||
perm os.FileMode
|
perm os.FileMode
|
||||||
ephemeral bool
|
ephemeral bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mkdirOp) Type() Enablement { return m.et }
|
func (m *mkdirOp) Type() hst.Enablement { return m.et }
|
||||||
|
|
||||||
func (m *mkdirOp) apply(sys *I) error {
|
func (m *mkdirOp) apply(sys *I) error {
|
||||||
sys.msg.Verbose("ensuring directory", m)
|
sys.msg.Verbose("ensuring directory", m)
|
||||||
|
@ -7,11 +7,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// User type is reverted at final instance exit.
|
// User type is reverted at final instance exit.
|
||||||
User = EM << iota
|
User = hst.EM << iota
|
||||||
// Process type is unconditionally reverted on exit.
|
// Process type is unconditionally reverted on exit.
|
||||||
Process
|
Process
|
||||||
|
|
||||||
@ -19,21 +20,21 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Criteria specifies types of Op to revert.
|
// Criteria specifies types of Op to revert.
|
||||||
type Criteria Enablement
|
type Criteria hst.Enablement
|
||||||
|
|
||||||
func (ec *Criteria) hasType(t Enablement) bool {
|
func (ec *Criteria) hasType(t hst.Enablement) bool {
|
||||||
// nil criteria: revert everything except User
|
// nil criteria: revert everything except User
|
||||||
if ec == nil {
|
if ec == nil {
|
||||||
return t != User
|
return t != User
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enablement(*ec)&t != 0
|
return hst.Enablement(*ec)&t != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Op is a reversible system operation.
|
// Op is a reversible system operation.
|
||||||
type Op interface {
|
type Op interface {
|
||||||
// Type returns [Op]'s enablement type, for matching a revert criteria.
|
// Type returns [Op]'s enablement type, for matching a revert criteria.
|
||||||
Type() Enablement
|
Type() hst.Enablement
|
||||||
|
|
||||||
apply(sys *I) error
|
apply(sys *I) error
|
||||||
revert(sys *I, ec *Criteria) error
|
revert(sys *I, ec *Criteria) error
|
||||||
@ -44,7 +45,7 @@ type Op interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TypeString extends [Enablement.String] to support [User] and [Process].
|
// TypeString extends [Enablement.String] to support [User] and [Process].
|
||||||
func TypeString(e Enablement) string {
|
func TypeString(e hst.Enablement) string {
|
||||||
switch e {
|
switch e {
|
||||||
case User:
|
case User:
|
||||||
return "user"
|
return "user"
|
||||||
|
@ -10,18 +10,19 @@ import (
|
|||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/internal/xcb"
|
"hakurei.app/system/internal/xcb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCriteria(t *testing.T) {
|
func TestCriteria(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
ec, t Enablement
|
ec, t hst.Enablement
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{"nil", 0xff, EWayland, true},
|
{"nil", 0xff, hst.EWayland, true},
|
||||||
{"nil user", 0xff, User, false},
|
{"nil user", 0xff, User, false},
|
||||||
{"all", EWayland | EX11 | EDBus | EPulse | User | Process, Process, true},
|
{"all", hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse | User | Process, Process, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@ -40,18 +41,18 @@ func TestCriteria(t *testing.T) {
|
|||||||
|
|
||||||
func TestTypeString(t *testing.T) {
|
func TestTypeString(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
e Enablement
|
e hst.Enablement
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{EWayland, EWayland.String()},
|
{hst.EWayland, hst.EWayland.String()},
|
||||||
{EX11, EX11.String()},
|
{hst.EX11, hst.EX11.String()},
|
||||||
{EDBus, EDBus.String()},
|
{hst.EDBus, hst.EDBus.String()},
|
||||||
{EPulse, EPulse.String()},
|
{hst.EPulse, hst.EPulse.String()},
|
||||||
{User, "user"},
|
{User, "user"},
|
||||||
{Process, "process"},
|
{Process, "process"},
|
||||||
{User | Process, "user, process"},
|
{User | Process, "user, process"},
|
||||||
{EWayland | User | Process, "wayland, user, process"},
|
{hst.EWayland | User | Process, "wayland, user, process"},
|
||||||
{EX11 | Process, "x11, process"},
|
{hst.EX11 | Process, "x11, process"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@ -176,7 +177,7 @@ func TestCommitRevert(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
f func(sys *I)
|
f func(sys *I)
|
||||||
ec Enablement
|
ec hst.Enablement
|
||||||
|
|
||||||
commit []stub.Call
|
commit []stub.Call
|
||||||
wantErrCommit error
|
wantErrCommit error
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CopyFile reads up to n bytes from src and writes the resulting byte slice to payloadP.
|
// CopyFile reads up to n bytes from src and writes the resulting byte slice to payloadP.
|
||||||
@ -26,7 +28,7 @@ type tmpfileOp struct {
|
|||||||
buf *bytes.Buffer
|
buf *bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tmpfileOp) Type() Enablement { return Process }
|
func (t *tmpfileOp) Type() hst.Enablement { return Process }
|
||||||
|
|
||||||
func (t *tmpfileOp) apply(sys *I) error {
|
func (t *tmpfileOp) apply(sys *I) error {
|
||||||
if t.payload == nil {
|
if t.payload == nil {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/wayland"
|
"hakurei.app/system/wayland"
|
||||||
)
|
)
|
||||||
@ -32,7 +33,7 @@ type waylandOp struct {
|
|||||||
conn waylandConn
|
conn waylandConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *waylandOp) Type() Enablement { return Process }
|
func (w *waylandOp) Type() hst.Enablement { return Process }
|
||||||
|
|
||||||
func (w *waylandOp) apply(sys *I) error {
|
func (w *waylandOp) apply(sys *I) error {
|
||||||
if w.sync == nil {
|
if w.sync == nil {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/internal/xcb"
|
"hakurei.app/system/internal/xcb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ func (sys *I) ChangeHosts(username string) *I {
|
|||||||
// xhostOp implements [I.ChangeHosts].
|
// xhostOp implements [I.ChangeHosts].
|
||||||
type xhostOp string
|
type xhostOp string
|
||||||
|
|
||||||
func (x xhostOp) Type() Enablement { return EX11 }
|
func (x xhostOp) Type() hst.Enablement { return hst.EX11 }
|
||||||
|
|
||||||
func (x xhostOp) apply(sys *I) error {
|
func (x xhostOp) apply(sys *I) error {
|
||||||
sys.msg.Verbosef("inserting entry %s to X11", x)
|
sys.msg.Verbosef("inserting entry %s to X11", x)
|
||||||
|
@ -4,17 +4,18 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/internal/xcb"
|
"hakurei.app/system/internal/xcb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestXHostOp(t *testing.T) {
|
func TestXHostOp(t *testing.T) {
|
||||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||||
{"xcbChangeHosts revert", 0xbeef, EX11, xhostOp("chronos"), []stub.Call{
|
{"xcbChangeHosts revert", 0xbeef, hst.EX11, xhostOp("chronos"), []stub.Call{
|
||||||
call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil),
|
||||||
call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, stub.UniqueError(1)),
|
call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, stub.UniqueError(1)),
|
||||||
}, &OpError{Op: "xhost", Err: stub.UniqueError(1)}, nil, nil},
|
}, &OpError{Op: "xhost", Err: stub.UniqueError(1)}, nil, nil},
|
||||||
|
|
||||||
{"xcbChangeHosts revert", 0xbeef, EX11, xhostOp("chronos"), []stub.Call{
|
{"xcbChangeHosts revert", 0xbeef, hst.EX11, xhostOp("chronos"), []stub.Call{
|
||||||
call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil),
|
||||||
call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil),
|
call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
@ -29,7 +30,7 @@ func TestXHostOp(t *testing.T) {
|
|||||||
call("verbosef", stub.ExpectArgs{"skipping entry %s in X11", []any{xhostOp("chronos")}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"skipping entry %s in X11", []any{xhostOp("chronos")}}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"success", 0xbeef, EX11, xhostOp("chronos"), []stub.Call{
|
{"success", 0xbeef, hst.EX11, xhostOp("chronos"), []stub.Call{
|
||||||
call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil),
|
||||||
call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil),
|
call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
@ -52,6 +53,6 @@ func TestXHostOp(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
checkOpMeta(t, []opMetaTestCase{
|
checkOpMeta(t, []opMetaTestCase{
|
||||||
{"xhost", xhostOp("chronos"), EX11, "/tmp/.X11-unix", "SI:localuser:chronos"},
|
{"xhost", xhostOp("chronos"), hst.EX11, "/tmp/.X11-unix", "SI:localuser:chronos"},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user