dobu/dobu-run.sh

143 lines
4.9 KiB
Bash
Executable file

#!/usr/bin/env bash
script_path="$(dirname "$(realpath "$0")")"
. "$script_path/functions.sh"
assert_prerequisites
[ -z "$1" ] && die "Expecting 1 argument"
image_name="$(relative_path_to_image_name "apps/$1")"
# image_name is of the form dobu/xxxx, while for containers we want dobu-xxx
container_name="${image_name/\//-}"
home_path="$HOMEDIR_STORAGE/$1"
log "Image name: $image_name"
log "Container name: $container_name"
log "Home directory path: $home_path"
assert_image_exists "$image_name"
remove_stale_container "$container_name"
if container_exists "$container_name"; then
log "$container_name is already running; re-executing entrypoint command"
log "If this is not desired, please stop the application or run \`podman stop $container_name\` manually"
podman exec -d "$container_name" $(container_entrypoint "$container_name")
exit 0
fi
if [ "$(get_image_label "$image_name" net.typeblog.dobu.unsafe_i_know_what_i_am_doing_allow_namespaces)" == "true" ]; then
log "Enabling sub-namespaces support inside this container"
log "This is considered UNSAFE; DO NOT USE if the app inside container does not do its own sandboxing"
log "DO NOT USE if you don't trust sandboxing done by the app inside"
update_podman_security_args "seccomp_unsafe.json"
fi
if [[ -n $PULSE_SERVER ]]; then # remove prefix
host_pulse=${PULSE_SERVER#unix:}
else # default guess
host_pulse=$XDG_RUNTIME_DIR/pulse/native
fi
if is_in_array "$1" "${DISPLAY_SERVER_APP_ALLOWLIST[@]}"; then
log "Allowing app $1 full access to Wayland / X11 sockets"
WAYLAND_SRC="${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}"
if [ -z "$DISPLAY" ]; then
# TODO: Maybe we can just ignore Xorg in these cases
die "$$DISPLAY must be set for apps granted full Wayland / Xorg access"
fi
XORG_SRC="/tmp/.X11-unix/X${DISPLAY/:/}"
if [ ! -S "${XORG_SRC}" ] || [ ! -S "${WAYLAND_SRC}" ]; then
die "Wayland / Xorg sockets do not exist"
fi
else
# Make sure we have Sommelier running first
ensure_sommelier
WAYLAND_SRC="$DOBU_TMP/xdg_runtime/wayland-1"
XORG_SRC="$DOBU_TMP/X11-unix/X1"
fi
# Prepare $HOME for the container
if [ ! -d "$home_path" ]; then
if [ "$HOMEDIR_IS_BTRFS" == "true" ]; then
log "Creating $home_path as a btrfs subvolume"
btrfs subvol create "$home_path"
else
log "Creating $home_path"
mkdir -p "$home_path"
fi
fi
# Some containers want these default XDG directories to exist; make sure they do
mkdir -p "$home_path/.config"
mkdir -p "$home_path/.cache"
mkdir -p "$home_path/.local/share"
extra_args=""
# Expose Pipewire socket if it exists
if [ -S "$XDG_RUNTIME_DIR/pipewire-0" ]; then
extra_args="$extra_args -v $XDG_RUNTIME_DIR/pipewire-0:/xdg_runtime/pipewire-0"
fi
# Check if we should allow /dev/input access
if is_in_array "$1" "${DEV_INPUT_APP_ALLOWLIST[@]}"; then
if [ -z "${DEV_INPUT_DEVICE_ALLOWLIST+x}" ]; then
log "Granting full /dev/input access"
log "Set DEV_INPUT_DEVICE_ALLOWLIST for more fine-grained control"
extra_args="$extra_args -v /dev/input:/dev/input"
else
for device in "${DEV_INPUT_DEVICE_ALLOWLIST[@]}"; do
device=$(realpath /dev/input/"$device")
[[ ! "$device" =~ ^/dev/input/ ]] && continue
log "Granting access to input device $device"
extra_args="$extra_args -v $device:$device"
done
fi
fi
# Extra bind mounts
bind_mount_var_name="EXTRA_BIND_MOUNTS_${1//-/_}"
if [[ "$(declare -p ${bind_mount_var_name} 2>&1)" =~ "declare -a" ]]; then
bind_mount_var="${bind_mount_var_name}[@]"
for mount in "${!bind_mount_var}"; do
extra_args="$extra_args -v $mount"
done
fi
# The fun part: start the container!
# Don't detach like we did with Sommelier, though
podman run --rm "${podman_security_args[@]}" --name "$container_name" \
`# Create tmpfs mountpoints for runtime directories` \
--mount type=tmpfs,destination=/xdg_runtime,chown,tmpfs-mode=0700 \
--mount type=tmpfs,destination=/tmp/.X11-unix,chown,tmpfs-mode=0700 \
`# Pass through Sommelier Wayland socket` \
`# Note that XDG_RUNTIME_DIR is already set in the image` \
-v "${WAYLAND_SRC}":/xdg_runtime/wayland-0 \
-e WAYLAND_DISPLAY=wayland-0 \
`# Pass through Sommelier X11 socket` \
-v "${XORG_SRC}":/tmp/.X11-unix/X0 \
-e DISPLAY=:0 \
`# DRM render nodes` \
-v /dev/dri:/dev/dri \
`# Pass through PulseAudio` \
-v "$host_pulse":/xdg_runtime/pulse/native \
-e PULSE_SERVER=unix:/xdg_runtime/pulse/native \
`# $HOME` \
-v "$home_path":/home/user \
`# Miscellaneous` \
-e XDG_SESSION_TYPE=wayland \
-e TZ="$(date +%Z)" \
`# SHM is needed by some browser engines (such as CEF used by Steam)`\
--shm-size=1G \
`# Scaling parameters` \
-e GDK_SCALE="$GDK_SCALE" \
-e QT_SCALE_FACTOR="$QT_SCALE_FACTOR" \
-e QT_SCREEN_SCALE_FACTORS="$QT_SCREEN_SCALE_FACTORS" \
-e QT_AUTO_SCREEN_SCALE_FACTOR="$QT_AUTO_SCREEN_SCALE_FACTOR" \
`# Use podman's init stub inside the container for better control` \
--init \
$extra_args "$image_name"