143 lines
4.9 KiB
Bash
Executable file
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"
|