#!/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" 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 # Load app control file because some apps require run-time customization # TODO: Maybe these things should really be container labels? [ -f "$script_path/apps/$1/control" ] && . "$script_path/apps/$1/control" if [ "$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 # Make sure we have Sommelier running first ensure_sommelier # 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 extra_args="" # 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 # 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 \ --mount type=tmpfs,destination=/tmp/.X11-unix \ `# Pass through Sommelier Wayland socket` \ `# Note that XDG_RUNTIME_DIR is already set in the image` \ -v "$DOBU_TMP/xdg_runtime/wayland-1":/xdg_runtime/wayland-0 \ -e WAYLAND_DISPLAY=wayland-0 \ `# Pass through Sommelier X11 socket` \ -v "$DOBU_TMP/X11-unix/X1":/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"