104 lines
3.6 KiB
Bash
Executable File
104 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
die() {
|
|
echo "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
exit() {
|
|
rm -rf "$container_xdg_runtime"
|
|
if [ "$CONTAINER_USE_USERNS" = true ]; then
|
|
setfacl -x u:$((private_users + 1000)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY
|
|
xhost -si:localuser:\#$((private_users + 1000))
|
|
fi
|
|
}
|
|
|
|
[ -z "$CONTAINER_NAME" ] && die "\$CONTAINER_NAME not set"
|
|
[ -z "$DISPLAY" ] && die "\$DISPLAY not set (you must run the script in a desktop environment"
|
|
|
|
# Source configuration files if any
|
|
config="$HOME/.config/app_containers/$CONTAINER_NAME.sh"
|
|
if [ -f "$config" ]; then
|
|
source "$config"
|
|
fi
|
|
|
|
# Create a XDG_RUNTIME_DIR for guest on host
|
|
container_xdg_runtime="$(mktemp -d -p /var/tmp)"
|
|
trap exit EXIT
|
|
|
|
# Link the current wayland session to the container's xdg runtime
|
|
# Note that the session itself must be bind-mounted first
|
|
ln -s /run/host/$WAYLAND_DISPLAY $container_xdg_runtime/$WAYLAND_DISPLAY
|
|
|
|
# From <https://liolok.com/run-desktop-app-with-systemd-nspawn-container>
|
|
if [[ -n $DBUS_SESSION_BUS_ADDRESS ]]; then # remove prefix
|
|
host_bus=${DBUS_SESSION_BUS_ADDRESS#unix:path=}
|
|
else # default guess
|
|
host_bus=$XDG_RUNTIME_DIR/bus
|
|
fi
|
|
|
|
if [[ -n $PULSE_SERVER ]]; then # remove prefix
|
|
host_pulse=${PULSE_SERVER#unix:}
|
|
else # default guess
|
|
host_pulse=$XDG_RUNTIME_DIR/pulse/native
|
|
fi
|
|
|
|
[ -S $host_pulse ] || die "PulseAudio UNIX socket not found"
|
|
|
|
# Default username (assume `user` always has the same uid as the host user)
|
|
run_as=user
|
|
homedir=/home/user
|
|
if [ "$CONTAINER_RUN_AS_ROOT" = true ]; then
|
|
run_as=root
|
|
homedir=/root
|
|
fi
|
|
|
|
# Userns-related config
|
|
# Default to identity mapping, which does not provide uid isolation but does for capabilities
|
|
private_users=identity
|
|
bind_opts=""
|
|
if [ "$CONTAINER_USE_USERNS" = true ]; then
|
|
private_users=$(shuf -i 65536-$((2147483647 - 65536)) -n1) # Pick a random starting offset
|
|
bind_opts="idmap" # Note: custom mounts specified by the user are expected to incldue the idmap option as well
|
|
# Grant the user inside the namespace access to the Wayland / Xorg display
|
|
setfacl -m u:$((private_users + 1000)):rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY
|
|
xhost +si:localuser:\#$((private_users + 1000))
|
|
fi
|
|
|
|
SUDO_ASKPASS=$HOME/.local/bin/askpass-bemenu sudo -A systemd-nspawn -M $CONTAINER_NAME \
|
|
--private-users=$private_users --private-users-ownership=map \
|
|
`# DNS (when containers do not have their own netns)` \
|
|
--bind-ro=/run/systemd/resolve/stub-resolv.conf:/etc/resolv.conf \
|
|
`# GPU` \
|
|
--bind=/dev/dri \
|
|
--property=DeviceAllow='char-drm rw' \
|
|
`# Input devices` \
|
|
--bind-ro=/dev/input \
|
|
--property=DeviceAllow='char-input r' \
|
|
`# Xdg runtime` \
|
|
--bind=$container_xdg_runtime:/run/xdg:$bind_opts \
|
|
--setenv=XDG_RUNTIME_DIR=/run/xdg \
|
|
`# Xorg / Xwayland` \
|
|
--bind=/tmp/.X11-unix \
|
|
--setenv=DISPLAY=$DISPLAY \
|
|
`# Wayland (note the symlink created before in xdg runtime)` \
|
|
--bind-ro=$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/run/host/$WAYLAND_DISPLAY \
|
|
--setenv=WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
|
|
`# PulseAudio` \
|
|
--bind-ro=$host_pulse:/run/host/pulse/native \
|
|
--setenv=PULSE_SERVER=unix:/run/host/pulse/native \
|
|
`# DBus` \
|
|
--bind-ro=$host_bus:/run/host/bus \
|
|
--setenv=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/host/bus \
|
|
`# Scaling (GDK_SCALE is needed for Java as well)`\
|
|
--setenv=GDK_SCALE="$GDK_SCALE" \
|
|
`# Make applications prefer Wayland when possible` \
|
|
--setenv=XDG_SESSION_TYPE=wayland \
|
|
`# Hacks for Proton (enable logging, disable futex-based synchronization)` \
|
|
--setenv=PROTON_LOG=1 \
|
|
--setenv=PROTON_NO_FSYNC=1 \
|
|
`# Extra params` \
|
|
$SYSTEMD_NSPAWN_EXTRA_ARGS \
|
|
`# Launch app` \
|
|
--user=$run_as --chdir=$homedir --as-pid2 $@
|