#!/bin/bash ################################################# ### Run app within a bubblewrap container ### dependencies: bubblewrap ### Synopsis ### [OPTION]... [APP]... [APP ARGS] ### DESCRIPTION ### --wayland_display $WAYLAND-DISPLAY ### --xdg_runtime_dir $XDG_RUNTIME_DIR ### --bind_dirs /dir_a:/dir_b set -euo pipefail # Defaults wayland_display="" xdg_runtime_dir="" bind_dirs="" APP="" # Parse named args while (( $# )); do case "$1" in --wayland_display) wayland_display="$2" shift 2 ;; --xdg_runtime_dir) xdg_runtime_dir="$2" shift 2 ;; --bind_dirs) bind_dirs="$2" shift 2 ;; --*) echo "Unknown option: $1" >&2 exit 1 ;; *) APP="$1" shift break ;; esac done APP_ARGS=("$@") if [[ -z "$APP" ]]; then echo "Usage: $0 [-wayland_display ] [-xdg_runtime_dir ] [-bind_dirs ] [args...]" >&2 exit 1 fi APP_NAME="$(basename "$APP")" tmpdir="$(mktemp -d /tmp/${APP_NAME}_sandbox.XXXXXX)" chmod 700 "$tmpdir" mkdir -p "$tmpdir"/{home,config,cache,downloads} cleanup() { rm -rf "$tmpdir" } trap cleanup EXIT bwrap_args=( --unshare-user --dev /dev --proc /proc --tmpfs /tmp --dir "$tmpdir/home" --dir "$tmpdir/config" --dir "$tmpdir/cache" --dir "$tmpdir/downloads" --setenv HOME "$tmpdir/home" --setenv XDG_CONFIG_HOME "$tmpdir/config" --setenv XDG_CACHE_HOME "$tmpdir/cache" --setenv XDG_DOWNLOAD_DIR "$tmpdir/downloads" ) if [[ -n "$wayland_display" && -n "$xdg_runtime_dir" ]]; then bwrap_args+=(--bind "${xdg_runtime_dir}/${wayland_display}" "${xdg_runtime_dir}/${wayland_display}") bwrap_args+=(--setenv WAYLAND_DISPLAY "$wayland_display") bwrap_args+=(--setenv XDG_RUNTIME_DIR "$xdg_runtime_dir") fi bwrap_args+=( --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /bin /bin --ro-bind /etc /etc ) # Add extra bind dirs if [[ -n "$bind_dirs" ]]; then IFS=':' read -r -a dirs <<< "$bind_dirs" for d in "${dirs[@]}"; do bwrap_args+=(--bind "$d" "$d") done fi bwrap_args+=("$APP") bwrap_args+=("${APP_ARGS[@]}") exec bwrap "${bwrap_args[@]}"