aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/app/doc.go
blob: 8c5397fd254b7f696efbe8dc88d3f6edd1b73fad (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*
The app program is a proof-of-concept frontend for cmd/hakurei.

This program is not covered by the compatibility promise. The command line
interface and configuration syntax may change at any time.

# Installation

Compile cmd/app with these arguments:

	go build -trimpath \
		-ldflags='-s -w
			-buildid=
			-X hakurei.app/internal/info.hsuPath=/usr/local/bin/hsu' \
		./cmd/app

Replace /usr/local/bin/hsu with the hakurei installation's absolute hsu
pathname.

# Sharing files

Sharing files between apps is only possible with the permissionless shared
filesystem ([cmd/sharefs]), as apps generally do not share credentials. It can
be built without any special linker flags. Create a symlink at
/usr/bin/mount.fuse.sharefs pointing to the sharefs binary when mounting sharefs
via fstab:

	sharefs	/sdcard	fuse.sharefs	rw,noexec,nosuid,nodev,noatime,allow_other,mkdir,source=/var/lib/sdcard,setuid=1023,setgid=1023 0 0

Replace /var/lib/sdcard with the location of the backing directory. User and
group id must be specified in numerical form, it must own the backing directory.
The mount point does not have to be /sdcard.

# General setup

The entire directory structure containing persistent app data must be created
manually for now, due to the different ownership requirements being impossible
to set up directly through cmd/hsu.

The environment variable ROSA_APP_PATH should be set to the absolute pathname of
the persistent state directory. This document will use $ROSA_APP_PATH to refer
to the persistent state directory. The $ROSA_APP_PATH directory should be owned
by the user declared in /etc/hsurc and invoking cmd/app, and must be readable
and executable by all subordinate users. This can be done by making it
world-readable and executable, or by adding a group directive to the common
file.

The $ROSA_APP_PATH/app directory contains app configuration files, named after
their reverse-DNS style application identifier string. It should be owned by
the user invoking cmd/app.

The $ROSA_APP_PATH/initial directory contains the read-only base of every
app template. Everything within it, including the directory itself, should be
owned by the reserved user, its user and group id obtained by the command:

	app id

This document assumes a [Void Linux rootfs tarball] is unpacked here. It is
possible to use other Linux distributions; Void linux is selected here because
its package manager works correctly out of the box in the hakurei container
environment. If the use case does not require glibc, [Alpine Linux] or
[Chimera Linux] might be more suitable.

Once the tarball is unpacked at $ROSA_APP_PATH/initial, create a directory named
chronos in $ROSA_APP_PATH/initial/home, and directories block, bus, class, dev,
and devices in $ROSA_APP_PATH/initial/sys. Then, recursively change ownerships
of files and directories in $ROSA_APP_PATH/initial to the reserved user/group.

The $ROSA_APP_PATH/lock directory contains lock files guarding entry into
mutable and app containers of every template. It must be owned by the user
invoking cmd/app.

The $ROSA_APP_PATH/state directory contains app home directories, named after
their reverse-DNS style application identifier string. The directory itself
should be owned by the user invoking cmd/app; each directory inside must be
owned by the subordinate user/group id of its app, obtained by the command:

	app id "$APPID"

where "$APPID" is the second component of the first line in the configuration
file of the corresponding app. It is considered good practice, but not required,
for these directory to have the permission bits set to 0700.

The $ROSA_APP_PATH/template directory contains templates that apps are based
on, which are all derived from the initial layer. The directory itself
should be owned by the user invoking cmd/app, and each directory inside should
be owned by the reserved user/group. Their names are used in the first component
of the first line in the configuration file of each app, to specify that the
file is derived from that template.

The $ROSA_APP_PATH/work directory contains overlay work directories for mutable
containers. It must contain one manually created, empty directory for each
template, named after the template directory itself, owned by the reserved
user/group. The directory itself and its contents should have the permission
bits set to 0700.

# Snapshots and cloning

To reduce disk space used by templates, [ZFS clones] or an equivalent can be
used. In such a setup, where each template occupies a different filesystem, the
"merge" build tag is required, and the work directory can be omitted during
directory creation. Instead, the individual template directories contain both
upper and work directories.

# Configuring the base template

This section describes basic setup required for the typical desktop use case.
Generally, multiple templates are created to mitigate the global nature of
conventional package managers. The setup described in this section applies to
all templates. For convenience, a "base" template should be created, containing
this setup, and all future templates should be copied from the base template.
This section assumes the template is named "base".

Create an empty directory at $ROSA_APP_PATH/template/base, owned by the reserved
user, with permission bits set to 0755. Create its corresponding work directory
at $ROSA_APP_PATH/work/base, also owned by the reserved user, with permission
bits set to 0700. Once this is complete, enter its mutable container with the
command:

	app enter --shell=/bin/sh base

This command overrides the container configuration to use the shell program at
/bin/sh. Normally, cmd/app uses zsh, which is not yet installed.

Once in the container, populate /etc/resolv.conf with some well-known DNS
service, for example:

	nameserver 8.8.8.8
	nameserver 8.8.4.4

The mutable container does not bind the host /etc/resolv.conf. It is generally
recommended to populate it with a well-known service here to avoid trouble in
future template changes. A later section configures regular app containers to
use host configuration.

After populating nameserver configuration, install zsh using the package manager
provided by the distribution unpacked earlier. On Void Linux, this is done by
the command:

	xbps-install zsh

Wait for the package installation to complete, configure zsh if necessary, then
exit from the shell, and re-enter the container without overriding the login
shell:

	app enter base

Some packages are generally required in the container for the typical desktop
use case: xdg-user-dirs to reconfigure "well known" user directories to point
to the inner sharefs mount point, mesa to interact with the GPU, dconf to
configure GTK, xdg-desktop-portal-gtk to have gtk talk to dconf. Fonts generally
need to be installed as well. Additionally, a text editor can be installed for
editing configuration files later on. On Void Linux, these packages are
installed by the command:

	xbps-install \
		vim \
		mesa \
		mesa-dri \
		mesa-intel-dri \
		mesa-vaapi \
		mesa-vulkan-intel \
		mesa-vulkan-radeon \
		mesa-vulkan-overlay-layer \
		dconf \
		xdg-user-dirs \
		xdg-desktop-portal-gtk \
		noto-fonts-ttf \
		noto-fonts-ttf-variable \
		noto-fonts-ttf-extra \
		noto-fonts-emoji \
		noto-fonts-cjk \
		noto-fonts-cjk-variable \
		noto-fonts-cjk-sans \
		noto-fonts-cjk-sans-variable \
		noto-fonts-cjk-serif \
		noto-fonts-cjk-serif-variable

Add -32bit variants of mesa packages if multilib support is required. Adjust
the package selection based on use case.

Edit /etc/xdg/user-dirs.defaults and point directories to the inner sharefs
mount point as required. The resulting file should look like this:

	# Default settings for user directories
	#
	# The values are relative pathnames from the home directory and
	# will be translated on a per-path-element basis into the users locale
	DESKTOP=../../sdcard/Desktop
	DOWNLOAD=../../sdcard/Download
	TEMPLATES=../../sdcard/Templates
	PUBLICSHARE=../../sdcard/Public
	DOCUMENTS=../../sdcard/Documents
	MUSIC=../../sdcard/Music
	PICTURES=../../sdcard/Pictures
	VIDEOS=../../sdcard/Movies
	PROJECTS=../../sdcard/Projects
	# Another alternative is:
	#MUSIC=Documents/Music
	#PICTURES=Documents/Pictures
	#VIDEOS=Documents/Videos

If this is configured, it must be applied to the home directory of each app
individually. This can be done for all apps via the shell expression:

	app run | xargs -n 1 echo app run --command=xdg-user-dirs-update

This must also be done for every newly created app.

The /etc/dconf directory can be set up to provide defaults across all apps. To
do so, edit /etc/dconf/profile/user:

	user-db:user
	system-db:local
	system-db:site
	system-db:distro

Then, place files in /etc/dconf/db/local.d containing dconf configuration. For
example:

	[org/gnome/desktop/interface]
	gtk-enable-primary-paste=true
	color-scheme='prefer-dark'
	gtk-theme='adw-gtk3-dark'
	icon-theme='Papirus-Dark'

Themes must be installed in the container. Change colour-scheme and themes
accordingly. Setting gtk-enable-primary-paste restores clipboard behaviour that
GNOME maintainers decided to break.

After editing these configuration files, update dconf system databases:

	dconf update

# Common configuration

The optional $ROSA_APP_PATH/common file contains common configuration included
after the specific configuration of each app. Some bind mounts are required for
almost every graphical program, and many widely used libraries are configured
through the environment. For most setups, these directives are generally
required:

	; for libudev
	ro "/sys/block"
	ro "/sys/bus"
	ro "/sys/class"
	ro "/sys/dev"
	ro "/sys/devices"

	env EDITOR=vim
	; for apps to play nice with xdg-dbus-proxy
	ro+ "/etc/machine-id"
	; template must have a /etc/resolv.conf file
	ro+ "/etc/resolv.conf"
	; group name of the sharefs group configured on host
	group media_rw
	; for sharefs
	rw "/sdcard"
	; refer to /usr/share/zoneinfo
	env TZ=Asia/Tokyo

	; must be installed first
	env XCURSOR_THEME=volantes_cursors
	; must be generated first if using glibc
	env LANG=en_GB.UTF-8
	env LC_COLLATE=C

# Installing an app

An app is defined by a configuration file in $ROSA_APP_PATH/app, and a
persistent state directory in $ROSA_APP_PATH/state. Before creating an app, its
identity must be decided. Different apps should generally not share an identity.
The next unused identity can be found using the command:

	app next

If the -v argument is added before the "next" command, cmd/app will additionally
show apps sharing the same identity.

Once the identity is decided, the subordinate user/group id can be obtained by
the command:

	app id "$APPID"

where "$APPID" is the identity of this app. A directory must be created under
$ROSA_APP_PATH/state, owned by this user and group id. Its permission bits
should be set to 0700. A configuration file with the same name, owned by the
user invoking cmd/app, must be placed in $ROSA_APP_PATH/app. Its contents are
described in the next section. The reverse-DNS style application identifier
string is submitted to the Wayland display server, and used as part of the
dbus preset if enabled, so the correct identifier must be obtained. If no such
identifier exist, use the domain of the app home page.

# Configuring an app

The configuration file starts with two structural directives, and the remaining
lines are freestanding directives applied in order.

The first structural directive is a line containing two components separated by
the ':' byte. The first component is the template used by the app. the second
component is the decimal representation of the app identity. The second
structural directive is a shell expression passed to the shell serving as the
initial process of the app.

After the structural directives, each line contains exactly one directive or
comment. Comment lines begin with a ';' byte: these lines are not interpreted by
cmd/app in any way.

The following section documents currently available freestanding directives.

# Directives

	interactive         start initial process as an interactive shell
	gpu                 expose GPU devices to the container
	system_bus          enable system bus in the dbus proxy

	wayland             expose a Wayland pathname socket via security-context-v1
	x11                 expose the X11 pathname socket
	dbus                enable the per-container xdg-dbus-proxy daemon
	pipewire            expose a pipewire pathname socket via SecurityContext

	multiarch           unblock system calls required for multiarch to work on
	                    multiarch-enabled targets (amd64, arm64)
	devel               unblock ptrace and friends
	userns              unblock userns creation and container setup syscalls
	net                 enable network access
	abstract            enable access to external abstract unix sockets
	tty                 unblock dangerous terminal I/O (faking input)
	mapuid              map the target user id to the user id of the user
	                    invoking cmd/app in the container user namespace
	device              mount /dev/ from the init mount namespace as is in the
	                    container mount namespace

	share_runtime       share XDG_RUNTIME_DIR between containers under the same
	                    identity
	share_tmpdir        share TMPDIR between containers under the same identity

	username <name>     set username of the emulated user
	hostname <name>     set container hostname
	env KEY=VALUE       set an environment variable for the initial process

	ro "pathname"       make a host path available to the container; the string
	                    must be presented in Go string literal syntax, to
	                    specify a different inner pathname, end the outer
	                    pathname with NUL and specify the inner pathname after
	                    the NUL byte
	rw "pathname"       like ro, but the resulting mount entry is made writable
	ro+ "pathname"      like ro, but is skipped if pathname does not exist
	rw+ "pathname"      like ro+, but the resulting mount entry is made writable

	own name            add an own policy for the dbus proxy
	own_system name     like own, but for the system bus if enabled
	talk name           add a talk policy for the dbus proxy
	talk_system name    like talk, but for the system bus if enabled

[cmd/sharefs]: https://pkg.go.dev/hakurei.app/cmd/sharefs
[Void Linux rootfs tarball]: https://voidlinux.org/download
[Alpine Linux]: https://alpinelinux.org
[Chimera Linux]: https://chimera-linux.org
[ZFS clones]: https://openzfs.github.io/openzfs-docs/man/v2.4/8/zfs-clone.8.html
*/
package main