aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-03-11 19:21:55 +0900
committerOphestra <cat@gensokyo.uk>2026-03-11 19:21:55 +0900
commit330a344845aa8653772a9be6c085f4fdb602a028 (patch)
tree7ed7f60ad70121be51289cbe9043c003d1940e19
parent48cdf8bf852234ea3dad8dad3d571bb1d9546c32 (diff)
hst: improve doc comments
These now read a lot better both in source and on pkgsite. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--hst/config.go120
-rw-r--r--hst/container.go51
-rw-r--r--hst/dbus.go46
-rw-r--r--hst/enablement.go8
-rw-r--r--hst/fs.go15
-rw-r--r--hst/fslink.go4
-rw-r--r--hst/fsoverlay.go6
-rw-r--r--hst/hst.go60
-rw-r--r--hst/instance.go15
9 files changed, 211 insertions, 114 deletions
diff --git a/hst/config.go b/hst/config.go
index 0c66c274..51ac62ec 100644
--- a/hst/config.go
+++ b/hst/config.go
@@ -8,74 +8,97 @@ import (
"hakurei.app/container/check"
)
-// Config configures an application container, implemented in internal/app.
+// Config configures an application container.
type Config struct {
// Reverse-DNS style configured arbitrary identifier string.
- // Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
+ //
+ // This value is passed as is to Wayland security-context-v1 and used as
+ // part of defaults in D-Bus session proxy. The zero value causes a default
+ // value to be derived from the container instance.
ID string `json:"id,omitempty"`
// System services to make available in the container.
Enablements *Enablements `json:"enablements,omitempty"`
// Session D-Bus proxy configuration.
- // If set to nil, session bus proxy assume built-in defaults.
+ //
+ // Has no effect if [EDBus] but is not set in Enablements. The zero value
+ // assumes built-in defaults derived from ID.
SessionBus *BusConfig `json:"session_bus,omitempty"`
// System D-Bus proxy configuration.
- // If set to nil, system bus proxy is disabled.
+ //
+ // Has no effect if [EDBus] but is not set in Enablements. The zero value
+ // disables system bus proxy.
SystemBus *BusConfig `json:"system_bus,omitempty"`
- // Direct access to wayland socket, no attempt is made to attach security-context-v1
- // and the bare socket is made available to the container.
+ // Direct access to Wayland socket, no attempt is made to attach
+ // security-context-v1 and the bare socket is made available to the
+ // container.
//
- // This option is unsupported and most likely enables full control over the Wayland
- // session. Do not set this to true unless you are sure you know what you are doing.
+ // This option is unsupported and will most likely enable full control over
+ // the Wayland session from within the container. Do not set this to true
+ // unless you are sure you know what you are doing.
DirectWayland bool `json:"direct_wayland,omitempty"`
- // Direct access to the PipeWire socket established via SecurityContext::Create, no
- // attempt is made to start the pipewire-pulse server.
+
+ // Direct access to the PipeWire socket established via SecurityContext::Create,
+ // no attempt is made to start the pipewire-pulse server.
+ //
+ // The SecurityContext machinery is fatally flawed, it unconditionally sets
+ // read and execute bits on all objects for clients with the lowest achievable
+ // privilege level (by setting PW_KEY_ACCESS to "restricted" or by satisfying
+ // all conditions of [the /.flatpak-info hack]). This enables them to call
+ // any method targeting any object, and since Registry::Destroy checks for
+ // the read and execute bit, allows the destruction of any object other than
+ // PW_ID_CORE as well.
//
- // The SecurityContext machinery is fatally flawed, it blindly sets read and execute
- // bits on all objects for clients with the lowest achievable privilege level (by
- // setting PW_KEY_ACCESS to "restricted"). This enables them to call any method
- // targeting any object, and since Registry::Destroy checks for the read and execute bit,
- // allows the destruction of any object other than PW_ID_CORE as well. This behaviour
- // is implemented separately in media-session and wireplumber, with the wireplumber
- // implementation in Lua via an embedded Lua vm. In all known setups, wireplumber is
- // in use, and there is no known way to change its behaviour and set permissions
- // differently without replacing the Lua script. Also, since PipeWire relies on these
- // permissions to work, reducing them is not possible.
+ // This behaviour is implemented separately in media-session and wireplumber,
+ // with the wireplumber implementation in Lua via an embedded Lua vm. In all
+ // known setups, wireplumber is in use, and in that case, no option for
+ // configuring this behaviour exists, without replacing the Lua script.
+ // Also, since PipeWire relies on these permissions to work, reducing them
+ // was never possible in the first place.
//
- // Currently, the only other sandboxed use case is flatpak, which is not aware of
- // PipeWire and blindly exposes the bare PulseAudio socket to the container (behaves
- // like DirectPulse). This socket is backed by the pipewire-pulse compatibility daemon,
- // which obtains client pid via the SO_PEERCRED option. The PipeWire daemon, pipewire-pulse
- // daemon and the session manager daemon then separately performs the /.flatpak-info hack
- // described in https://git.gensokyo.uk/security/hakurei/issues/21. Under such use case,
- // since the client has no direct access to PipeWire, insecure parts of the protocol are
- // obscured by pipewire-pulse simply not implementing them, and thus hiding the flaws
- // described above.
+ // Currently, the only other sandboxed use case is flatpak, which is not
+ // aware of PipeWire and blindly exposes the bare PulseAudio socket to the
+ // container (behaves like DirectPulse). This socket is backed by the
+ // pipewire-pulse compatibility daemon, which obtains client pid via the
+ // SO_PEERCRED option. The PipeWire daemon, pipewire-pulse daemon and the
+ // session manager daemon then separately performs [the /.flatpak-info hack].
+ // Under such use case, since the client has no direct access to PipeWire,
+ // insecure parts of the protocol are obscured by the absence of an
+ // equivalent API in PulseAudio, or pipewire-pulse simply not implementing
+ // them.
//
- // Hakurei does not rely on the /.flatpak-info hack. Instead, a socket is sets up via
- // SecurityContext. A pipewire-pulse server connected through it achieves the same
- // permissions as flatpak does via the /.flatpak-info hack and is maintained for the
- // life of the container.
+ // Hakurei does not rely on [the /.flatpak-info hack]. Instead, a socket is
+ // sets up via SecurityContext. A pipewire-pulse server connected through it
+ // achieves the same permissions as flatpak does via [the /.flatpak-info hack]
+ // and is maintained for the life of the container.
+ //
+ // This option is unsupported and enables a denial-of-service attack as the
+ // sandboxed client is able to destroy any client object and thus
+ // disconnecting them from PipeWire, or destroy the SecurityContext object,
+ // preventing any further container creation.
//
- // This option is unsupported and enables a denial-of-service attack as the sandboxed
- // client is able to destroy any client object and thus disconnecting them from PipeWire,
- // or destroy the SecurityContext object preventing any further container creation.
// Do not set this to true, it is insecure under any configuration.
+ //
+ // [the /.flatpak-info hack]: https://git.gensokyo.uk/security/hakurei/issues/21
DirectPipeWire bool `json:"direct_pipewire,omitempty"`
- // Direct access to PulseAudio socket, no attempt is made to establish pipewire-pulse
- // server via a PipeWire socket with a SecurityContext attached and the bare socket
- // is made available to the container.
+
+ // Direct access to PulseAudio socket, no attempt is made to establish
+ // pipewire-pulse server via a PipeWire socket with a SecurityContext
+ // attached, and the bare socket is made available to the container.
//
- // This option is unsupported and enables arbitrary code execution as the PulseAudio
- // server. Do not set this to true, it is insecure under any configuration.
+ // This option is unsupported and enables arbitrary code execution as the
+ // PulseAudio server.
+ //
+ // Do not set this to true, it is insecure under any configuration.
DirectPulse bool `json:"direct_pulse,omitempty"`
// Extra acl updates to perform before setuid.
ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"`
- // Numerical application id, passed to hsu, used to derive init user namespace credentials.
+ // Numerical application id, passed to hsu, used to derive init user
+ // namespace credentials.
Identity int `json:"identity"`
// Init user namespace supplementary groups inherited by all container processes.
Groups []string `json:"groups"`
@@ -85,17 +108,20 @@ type Config struct {
}
var (
- // ErrConfigNull is returned by [Config.Validate] for an invalid configuration that contains a null value for any
- // field that must not be null.
+ // ErrConfigNull is returned by [Config.Validate] for an invalid configuration
+ // that contains a null value for any field that must not be null.
ErrConfigNull = errors.New("unexpected null in config")
- // ErrIdentityBounds is returned by [Config.Validate] for an out of bounds [Config.Identity] value.
+ // ErrIdentityBounds is returned by [Config.Validate] for an out of bounds
+ // [Config.Identity] value.
ErrIdentityBounds = errors.New("identity out of bounds")
- // ErrEnviron is returned by [Config.Validate] if an environment variable name contains '=' or NUL.
+ // ErrEnviron is returned by [Config.Validate] if an environment variable
+ // name contains '=' or NUL.
ErrEnviron = errors.New("invalid environment variable name")
- // ErrInsecure is returned by [Config.Validate] if the configuration is considered insecure.
+ // ErrInsecure is returned by [Config.Validate] if the configuration is
+ // considered insecure.
ErrInsecure = errors.New("configuration is insecure")
)
diff --git a/hst/container.go b/hst/container.go
index f9cc95ed..8696d85b 100644
--- a/hst/container.go
+++ b/hst/container.go
@@ -16,18 +16,20 @@ const PrivateTmp = "/.hakurei"
var AbsPrivateTmp = check.MustAbs(PrivateTmp)
const (
- // WaitDelayDefault is used when WaitDelay has its zero value.
+ // WaitDelayDefault is used when WaitDelay has the zero value.
WaitDelayDefault = 5 * time.Second
- // WaitDelayMax is used if WaitDelay exceeds its value.
+ // WaitDelayMax is used when WaitDelay exceeds its value.
WaitDelayMax = 30 * time.Second
)
const (
// ExitFailure is returned if the container fails to start.
ExitFailure = iota + 1
- // ExitCancel is returned if the container is terminated by a shim-directed signal which cancels its context.
+ // ExitCancel is returned if the container is terminated by a shim-directed
+ // signal which cancels its context.
ExitCancel
- // ExitOrphan is returned when the shim is orphaned before priv side delivers a signal.
+ // ExitOrphan is returned when the shim is orphaned before priv side process
+ // delivers a signal.
ExitOrphan
// ExitRequest is returned when the priv side process requests shim exit.
@@ -38,10 +40,12 @@ const (
type Flags uintptr
const (
- // FMultiarch unblocks syscalls required for multiarch to work on applicable targets.
+ // FMultiarch unblocks system calls required for multiarch to work on
+ // multiarch-enabled targets (amd64, arm64).
FMultiarch Flags = 1 << iota
- // FSeccompCompat changes emitted seccomp filter programs to be identical to that of Flatpak.
+ // FSeccompCompat changes emitted seccomp filter programs to be identical to
+ // that of Flatpak in enabled rulesets.
FSeccompCompat
// FDevel unblocks ptrace and friends.
FDevel
@@ -54,12 +58,15 @@ const (
// FTty unblocks dangerous terminal I/O (faking input).
FTty
- // FMapRealUID maps the target user uid to the privileged user uid in the container user namespace.
- // Some programs fail to connect to dbus session running as a different uid,
- // this option works around it by mapping priv-side caller uid in container.
+ // FMapRealUID maps the target user uid to the privileged user uid in the
+ // container user namespace.
+ //
+ // Some programs fail to connect to dbus session running as a different uid,
+ // this option works around it by mapping priv-side caller uid in container.
FMapRealUID
- // FDevice mount /dev/ from the init mount namespace as-is in the container mount namespace.
+ // FDevice mount /dev/ from the init mount namespace as is in the container
+ // mount namespace.
FDevice
// FShareRuntime shares XDG_RUNTIME_DIR between containers under the same identity.
@@ -112,30 +119,37 @@ func (flags Flags) String() string {
}
}
-// ContainerConfig describes the container configuration to be applied to an underlying [container].
+// ContainerConfig describes the container configuration to be applied to an
+// underlying [container]. It is validated by [Config.Validate].
type ContainerConfig struct {
// Container UTS namespace hostname.
Hostname string `json:"hostname,omitempty"`
// Duration in nanoseconds to wait for after interrupting the initial process.
- // Defaults to [WaitDelayDefault] if zero, or [WaitDelayMax] if greater than [WaitDelayMax].
- // Values lesser than zero is equivalent to zero, bypassing [WaitDelayDefault].
+ //
+ // Defaults to [WaitDelayDefault] if zero, or [WaitDelayMax] if greater than
+ // [WaitDelayMax]. Values lesser than zero is equivalent to zero, bypassing
+ // [WaitDelayDefault].
WaitDelay time.Duration `json:"wait_delay,omitempty"`
// Initial process environment variables.
Env map[string]string `json:"env"`
- /* Container mount points.
-
- If the first element targets /, it is inserted early and excluded from path hiding. */
+ // Container mount points.
+ //
+ // If the first element targets /, it is inserted early and excluded from
+ // path hiding. Otherwise, an anonymous instance of tmpfs is set up on /.
Filesystem []FilesystemConfigJSON `json:"filesystem"`
- // String used as the username of the emulated user, validated against the default NAME_REGEX from adduser.
+ // String used as the username of the emulated user, validated against the
+ // default NAME_REGEX from adduser.
+ //
// Defaults to passwd name of target uid or chronos.
Username string `json:"username,omitempty"`
// Pathname of shell in the container filesystem to use for the emulated user.
Shell *check.Absolute `json:"shell"`
- // Directory in the container filesystem to enter and use as the home directory of the emulated user.
+ // Directory in the container filesystem to enter and use as the home
+ // directory of the emulated user.
Home *check.Absolute `json:"home"`
// Pathname to executable file in the container filesystem.
@@ -148,6 +162,7 @@ type ContainerConfig struct {
}
// ContainerConfigF is [ContainerConfig] stripped of its methods.
+//
// The [ContainerConfig.Flags] field does not survive a [json] round trip.
type ContainerConfigF ContainerConfig
diff --git a/hst/dbus.go b/hst/dbus.go
index 6dd1a2c3..5c4620cc 100644
--- a/hst/dbus.go
+++ b/hst/dbus.go
@@ -5,8 +5,26 @@ import (
"strings"
)
-// BadInterfaceError is returned when Interface fails an undocumented check in xdg-dbus-proxy,
-// which would have cause a silent failure.
+// BadInterfaceError is returned when Interface fails an undocumented check in
+// xdg-dbus-proxy, which would have cause a silent failure.
+//
+// xdg-dbus-proxy fails without output when this condition is not met:
+//
+// char *dot = strrchr (filter->interface, '.');
+// if (dot != NULL)
+// {
+// *dot = 0;
+// if (strcmp (dot + 1, "*") != 0)
+// filter->member = g_strdup (dot + 1);
+// }
+//
+// trim ".*" since they are removed before searching for '.':
+//
+// if (g_str_has_suffix (name, ".*"))
+// {
+// name[strlen (name) - 2] = 0;
+// wildcard = TRUE;
+// }
type BadInterfaceError struct {
// Interface is the offending interface string.
Interface string
@@ -19,7 +37,8 @@ func (e *BadInterfaceError) Error() string {
if e == nil {
return "<nil>"
}
- return "bad interface string " + strconv.Quote(e.Interface) + " in " + e.Segment + " bus configuration"
+ return "bad interface string " + strconv.Quote(e.Interface) +
+ " in " + e.Segment + " bus configuration"
}
// BusConfig configures the xdg-dbus-proxy process.
@@ -76,31 +95,14 @@ func (c *BusConfig) Interfaces(yield func(string) bool) {
}
}
-// CheckInterfaces checks for invalid interface strings based on an undocumented check in xdg-dbus-error,
-// returning [BadInterfaceError] if one is encountered.
+// CheckInterfaces checks for invalid interface strings based on an undocumented
+// check in xdg-dbus-error, returning [BadInterfaceError] if one is encountered.
func (c *BusConfig) CheckInterfaces(segment string) error {
if c == nil {
return nil
}
for iface := range c.Interfaces {
- /*
- xdg-dbus-proxy fails without output when this condition is not met:
- char *dot = strrchr (filter->interface, '.');
- if (dot != NULL)
- {
- *dot = 0;
- if (strcmp (dot + 1, "*") != 0)
- filter->member = g_strdup (dot + 1);
- }
-
- trim ".*" since they are removed before searching for '.':
- if (g_str_has_suffix (name, ".*"))
- {
- name[strlen (name) - 2] = 0;
- wildcard = TRUE;
- }
- */
if strings.IndexByte(strings.TrimSuffix(iface, ".*"), '.') == -1 {
return &BadInterfaceError{iface, segment}
}
diff --git a/hst/enablement.go b/hst/enablement.go
index 9024078d..71ddecab 100644
--- a/hst/enablement.go
+++ b/hst/enablement.go
@@ -11,15 +11,17 @@ import (
type Enablement byte
const (
- // EWayland exposes a wayland pathname socket via security-context-v1.
+ // EWayland exposes a Wayland pathname socket via security-context-v1.
EWayland Enablement = 1 << iota
- // EX11 adds the target user via X11 ChangeHosts and exposes the X11 pathname socket.
+ // EX11 adds the target user via X11 ChangeHosts and exposes the X11
+ // pathname socket.
EX11
// EDBus enables the per-container xdg-dbus-proxy daemon.
EDBus
// EPipeWire exposes a pipewire pathname socket via SecurityContext.
EPipeWire
- // EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the PulseAudio socket.
+ // EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the
+ // PulseAudio socket.
EPulse
// EM is a noop.
diff --git a/hst/fs.go b/hst/fs.go
index 3cecac88..3f0f6017 100644
--- a/hst/fs.go
+++ b/hst/fs.go
@@ -24,7 +24,8 @@ type FilesystemConfig interface {
fmt.Stringer
}
-// The Ops interface enables [FilesystemConfig] to queue container ops without depending on the container package.
+// The Ops interface enables [FilesystemConfig] to queue container ops without
+// depending on the container package.
type Ops interface {
// Tmpfs appends an op that mounts tmpfs on a container path.
Tmpfs(target *check.Absolute, size int, perm os.FileMode) Ops
@@ -41,12 +42,15 @@ type Ops interface {
// Link appends an op that creates a symlink in the container filesystem.
Link(target *check.Absolute, linkName string, dereference bool) Ops
- // Root appends an op that expands a directory into a toplevel bind mount mirror on container root.
+ // Root appends an op that expands a directory into a toplevel bind mount
+ // mirror on container root.
Root(host *check.Absolute, flags int) Ops
- // Etc appends an op that expands host /etc into a toplevel symlink mirror with /etc semantics.
+ // Etc appends an op that expands host /etc into a toplevel symlink mirror
+ // with /etc semantics.
Etc(host *check.Absolute, prefix string) Ops
- // Daemon appends an op that starts a daemon in the container and blocks until target appears.
+ // Daemon appends an op that starts a daemon in the container and blocks
+ // until target appears.
Daemon(target, path *check.Absolute, args ...string) Ops
}
@@ -61,7 +65,8 @@ type ApplyState struct {
// ErrFSNull is returned by [json] on encountering a null [FilesystemConfig] value.
var ErrFSNull = errors.New("unexpected null in mount point")
-// FSTypeError is returned when [ContainerConfig.Filesystem] contains an entry with invalid type.
+// FSTypeError is returned when [ContainerConfig.Filesystem] contains an entry
+// with invalid type.
type FSTypeError string
func (f FSTypeError) Error() string { return fmt.Sprintf("invalid filesystem type %q", string(f)) }
diff --git a/hst/fslink.go b/hst/fslink.go
index 2a1e3795..57c1ffc7 100644
--- a/hst/fslink.go
+++ b/hst/fslink.go
@@ -18,7 +18,9 @@ type FSLink struct {
Target *check.Absolute `json:"dst"`
// Arbitrary linkname value store in the symlink.
Linkname string `json:"linkname"`
- // Whether to treat Linkname as an absolute pathname and dereference before creating the link.
+
+ // Whether to treat Linkname as an absolute pathname and dereference before
+ // creating the link.
Dereference bool `json:"dereference,omitempty"`
}
diff --git a/hst/fsoverlay.go b/hst/fsoverlay.go
index de4e14dd..72df1deb 100644
--- a/hst/fsoverlay.go
+++ b/hst/fsoverlay.go
@@ -19,9 +19,11 @@ type FSOverlay struct {
// Any filesystem, does not need to be on a writable filesystem, must not be nil.
Lower []*check.Absolute `json:"lower"`
- // The upperdir is normally on a writable filesystem, leave as nil to mount Lower readonly.
+ // The upperdir is normally on a writable filesystem, leave as nil to mount
+ // Lower readonly.
Upper *check.Absolute `json:"upper,omitempty"`
- // The workdir needs to be an empty directory on the same filesystem as Upper, must not be nil if Upper is populated.
+ // The workdir needs to be an empty directory on the same filesystem as
+ // Upper, must not be nil if Upper is populated.
Work *check.Absolute `json:"work,omitempty"`
}
diff --git a/hst/hst.go b/hst/hst.go
index 439f4b2d..45f1eb83 100644
--- a/hst/hst.go
+++ b/hst/hst.go
@@ -44,11 +44,13 @@ func (e *AppError) Message() string {
type Paths struct {
// Temporary directory returned by [os.TempDir], usually equivalent to [fhs.AbsTmp].
TempDir *check.Absolute `json:"temp_dir"`
- // Shared directory specific to the hsu userid, usually (`/tmp/hakurei.%d`, [Info.User]).
+ // Shared directory specific to the hsu userid, usually
+ // (`/tmp/hakurei.%d`, [Info.User]).
SharePath *check.Absolute `json:"share_path"`
// Checked XDG_RUNTIME_DIR value, usually (`/run/user/%d`, uid).
RuntimePath *check.Absolute `json:"runtime_path"`
- // Shared directory specific to the hsu userid located in RuntimePath, usually (`/run/user/%d/hakurei`, uid).
+ // Shared directory specific to the hsu userid located in RuntimePath,
+ // usually (`/run/user/%d/hakurei`, uid).
RunDirPath *check.Absolute `json:"run_dir_path"`
}
@@ -74,10 +76,23 @@ func Template() *Config {
SessionBus: &BusConfig{
See: nil,
- Talk: []string{"org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
- "org.freedesktop.secrets", "org.kde.kwalletd5", "org.kde.kwalletd6", "org.gnome.SessionManager"},
- Own: []string{"org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
- "org.mpris.MediaPlayer2.chromium.*"},
+ Talk: []string{
+ "org.freedesktop.Notifications",
+ "org.freedesktop.FileManager1",
+ "org.freedesktop.ScreenSaver",
+ "org.freedesktop.secrets",
+
+ "org.kde.kwalletd5",
+ "org.kde.kwalletd6",
+
+ "org.gnome.SessionManager",
+ },
+ Own: []string{
+ "org.chromium.Chromium.*",
+
+ "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
+ "org.mpris.MediaPlayer2.chromium.*",
+ },
Call: map[string]string{"org.freedesktop.portal.*": "*"},
Broadcast: map[string]string{"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"},
Log: false,
@@ -112,7 +127,12 @@ func Template() *Config {
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT",
},
Filesystem: []FilesystemConfigJSON{
- {&FSBind{Target: fhs.AbsRoot, Source: fhs.AbsVarLib.Append("hakurei/base/org.debian"), Write: true, Special: true}},
+ {&FSBind{
+ Target: fhs.AbsRoot,
+ Source: fhs.AbsVarLib.Append("hakurei/base/org.debian"),
+ Write: true,
+ Special: true,
+ }},
{&FSBind{Target: fhs.AbsEtc, Source: fhs.AbsEtc, Special: true}},
{&FSEphemeral{Target: fhs.AbsTmp, Write: true, Perm: 0755}},
{&FSOverlay{
@@ -121,11 +141,27 @@ func Template() *Config {
Upper: fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
Work: fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/work"),
}},
- {&FSLink{Target: fhs.AbsRun.Append("current-system"), Linkname: "/run/current-system", Dereference: true}},
- {&FSLink{Target: fhs.AbsRun.Append("opengl-driver"), Linkname: "/run/opengl-driver", Dereference: true}},
- {&FSBind{Source: fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
- Target: check.MustAbs("/data/data/org.chromium.Chromium"), Write: true, Ensure: true}},
- {&FSBind{Source: fhs.AbsDev.Append("dri"), Device: true, Optional: true}},
+ {&FSLink{
+ Target: fhs.AbsRun.Append("current-system"),
+ Linkname: "/run/current-system",
+ Dereference: true,
+ }},
+ {&FSLink{
+ Target: fhs.AbsRun.Append("opengl-driver"),
+ Linkname: "/run/opengl-driver",
+ Dereference: true,
+ }},
+ {&FSBind{
+ Source: fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
+ Target: check.MustAbs("/data/data/org.chromium.Chromium"),
+ Write: true,
+ Ensure: true,
+ }},
+ {&FSBind{
+ Source: fhs.AbsDev.Append("dri"),
+ Device: true,
+ Optional: true,
+ }},
},
Username: "chronos",
diff --git a/hst/instance.go b/hst/instance.go
index b59a7684..282472ae 100644
--- a/hst/instance.go
+++ b/hst/instance.go
@@ -12,10 +12,12 @@ import (
// An ID is a unique identifier held by a running hakurei container.
type ID [16]byte
-// ErrIdentifierLength is returned when encountering a [hex] representation of [ID] with unexpected length.
+// ErrIdentifierLength is returned when encountering a [hex] representation of
+// [ID] with unexpected length.
var ErrIdentifierLength = errors.New("identifier string has unexpected length")
-// IdentifierDecodeError is returned by [ID.UnmarshalText] to provide relevant error descriptions.
+// IdentifierDecodeError is returned by [ID.UnmarshalText] to provide relevant
+// error descriptions.
type IdentifierDecodeError struct{ Err error }
func (e IdentifierDecodeError) Unwrap() error { return e.Err }
@@ -23,7 +25,10 @@ func (e IdentifierDecodeError) Error() string {
var invalidByteError hex.InvalidByteError
switch {
case errors.As(e.Err, &invalidByteError):
- return fmt.Sprintf("got invalid byte %#U in identifier", rune(invalidByteError))
+ return fmt.Sprintf(
+ "got invalid byte %#U in identifier",
+ rune(invalidByteError),
+ )
case errors.Is(e.Err, hex.ErrLength):
return "odd length identifier hex string"
@@ -41,7 +46,9 @@ func (a *ID) CreationTime() time.Time {
}
// NewInstanceID creates a new unique [ID].
-func NewInstanceID(id *ID) error { return newInstanceID(id, uint64(time.Now().UnixNano())) }
+func NewInstanceID(id *ID) error {
+ return newInstanceID(id, uint64(time.Now().UnixNano()))
+}
// newInstanceID creates a new unique [ID] with the specified timestamp.
func newInstanceID(id *ID, p uint64) error {