aboutsummaryrefslogtreecommitdiffhomepage
path: root/hst/enablement.go
blob: 71ddecab38cc801e4e4cb236717ab4289db03a78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package hst

import (
	"encoding/json"
	"fmt"
	"strings"
	"syscall"
)

// Enablement represents an optional host service to export to the target user.
type Enablement byte

const (
	// 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
	// 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

	// EM is a noop.
	EM
)

// String returns a string representation of the flags set on [Enablement].
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 EPipeWire:
		return "pipewire"
	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) }

// Enablements is the [json] adapter for [Enablement].
type Enablements Enablement

// enablementsJSON is the [json] representation of [Enablements].
type enablementsJSON = struct {
	Wayland  bool `json:"wayland,omitempty"`
	X11      bool `json:"x11,omitempty"`
	DBus     bool `json:"dbus,omitempty"`
	PipeWire bool `json:"pipewire,omitempty"`
	Pulse    bool `json:"pulse,omitempty"`
}

// Unwrap returns the underlying [Enablement].
func (e *Enablements) Unwrap() Enablement {
	if e == nil {
		return 0
	}
	return Enablement(*e)
}

func (e *Enablements) MarshalJSON() ([]byte, error) {
	if e == nil {
		return nil, syscall.EINVAL
	}
	return json.Marshal(&enablementsJSON{
		Wayland:  Enablement(*e)&EWayland != 0,
		X11:      Enablement(*e)&EX11 != 0,
		DBus:     Enablement(*e)&EDBus != 0,
		PipeWire: Enablement(*e)&EPipeWire != 0,
		Pulse:    Enablement(*e)&EPulse != 0,
	})
}

func (e *Enablements) UnmarshalJSON(data []byte) error {
	if e == nil {
		return syscall.EINVAL
	}

	v := new(enablementsJSON)
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	var ve Enablement
	if v.Wayland {
		ve |= EWayland
	}
	if v.X11 {
		ve |= EX11
	}
	if v.DBus {
		ve |= EDBus
	}
	if v.PipeWire {
		ve |= EPipeWire
	}
	if v.Pulse {
		ve |= EPulse
	}
	*e = Enablements(ve)
	return nil
}