#!/usr/bin/env bash SCRIPT_PATH=$(dirname $(realpath -s $0)) MUVM_PATH=$(dirname $(which muvm)) PASST_PATH=$(dirname $(which passt)) WL_PROXY_PATH=$(dirname $(which wl-cross-domain-proxy)) WL_BACKDROP_PATH=$(dirname $(which wl-backdrop)) HOST_OPENGL_DRIVER=/run/opengl-driver : "${MICROVM_DEFAULT_COMMAND:=bash}" : "${MUNIX_SYSTEMD_UNITS:="${SCRIPT_PATH}/systemd"}" MICROVM_CLOSURE= MICROVM_COMMAND=() MICROVM_UID=1337 MICROVM_GID=1337 BWRAP_ARGS=() MUVM_ARGS=() SIDEBUS_ARGS=() GPU=1 WAYLAND=1 PIPEWIRE=1 X11=0 ENV_DEFAULTS=1 USING_PUBLISH=0 export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C if [ ! -e "$HOST_OPENGL_DRIVER" ]; then HOST_OPENGL_DRIVER="$FALLBACK_OPENGL_DRIVER" fi # A little bit cursed: pre-pass to relaunch with new env var.. BG_COLOR= pargs=() while [ "$#" -gt 0 ]; do case "$1" in --bg-color) BG_COLOR="$2"; shift 2;; --wl-backdrop-bin-dir) WL_BACKDROP_PATH="$2"; shift 2;; *) pargs+=("$1"); shift;; esac done if [ "$BG_COLOR" = "" ]; then set -- "${pargs[@]}" else exec "$WL_BACKDROP_PATH/wl-backdrop" --background "$BG_COLOR" -- "$(readlink -f "$0")" "${pargs[@]}" fi while [ "$#" -gt 0 ]; do case "$1" in -u|--uid) MICROVM_UID="$2"; shift 2;; -g|--gid) MICROVM_GID="$2"; shift 2;; --no-gpu) GPU=0; shift 1;; --no-wayland) WAYLAND=0; shift 1;; --no-pipewire) PIPEWIRE=0; shift 1;; --no-env-defaults) ENV_DEFAULTS=0; shift 1;; --x11) X11=1; shift 1;; -b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;; --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;; -e|--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;; --ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;; -p|--publish) USING_PUBLISH=1; MUVM_ARGS+=("--publish=$2"); shift 2;; --host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;; --munix-bin-dir) SCRIPT_PATH="$2"; shift 2;; --muvm-bin-dir) MUVM_PATH="$2"; shift 2;; --passt-bin-dir) PASST_PATH="$2"; shift 2;; --wl-proxy-bin-dir) WL_PROXY_PATH="$2"; shift 2;; --wl-backdrop-bin-dir) shift 2;; --) shift 1; MICROVM_COMMAND+=("$@"); break;; -*) echo "munix: unknown option: $1" >&2; exit 1;; *) if [ "$MICROVM_CLOSURE" = "" ]; then MICROVM_CLOSURE="$1" else MICROVM_COMMAND+=("$1") fi shift 1;; esac done if [ "$MICROVM_CLOSURE" = "" ]; then echo "munix: provide a system closure path as a positional argument" >&2 exit 1 fi if [ "$MUVM_PATH" = "" ]; then echo "munix: muvm not found, provide a --muvm-bin-dir or fix \$PATH" >&2 exit 1 fi if [ "$PASST_PATH" = "" ]; then echo "munix: passt not found, provide a --passt-bin-dir or fix \$PATH" >&2 exit 1 fi if [ "$WL_PROXY_PATH" = "" ]; then echo "munix: wl-cross-domain-proxy not found, provide a --wl-proxy-bin-dir or fix \$PATH" >&2 exit 1 fi if [ "$WL_BACKDROP_PATH" = "" ]; then echo "munix: wl-backdrop not found, provide a --wl-backdrop-bin-dir or fix \$PATH" >&2 exit 1 fi if [ ! -e "$HOST_OPENGL_DRIVER" ]; then echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2 exit 1 fi # Resolve symlinks automatically MICROVM_CLOSURE=$(realpath "$MICROVM_CLOSURE") if [ ${#MICROVM_COMMAND[@]} -eq 0 ]; then MICROVM_COMMAND=("$MICROVM_DEFAULT_COMMAND") fi if [ "$GPU" -eq 1 ]; then BWRAP_ARGS+=( "--dev-bind" "/dev/dri" "/dev/dri" "--ro-bind" "$HOST_OPENGL_DRIVER" "/run/opengl-driver" ) GPU_MODE=venus kernel_ver="$(uname -r)" kernel_ver_arr=(${kernel_ver//./ }) kernel_major="${kernel_ver_arr:-0}" kernel_ver_arr=("${kernel_ver_arr[@]:1}") kernel_minor="${kernel_ver_arr:-0}" if [[ "$kernel_major" -gt 6 || ("$kernel_major" -eq 6 && "$kernel_minor" -gt 12) ]]; then for card in /dev/dri/card*; do driver_link="/sys/class/drm/${card##*/}/device/driver" if [ -L "$driver_link" ]; then driver_mod="$(readlink "$driver_link")" driver_name="${driver_mod##*/}" case "$driver_name" in amdgpu|msm_dpu) # TODO: i915 echo "munix: ${card##*/} gpu driver is '$driver_name', using vdrm" >&2; GPU_MODE=drm break;; *) echo "munix: ${card##*/} gpu driver is '$driver_name', using venus unless more gpus are found" >&2;; esac else echo "munix: ${card##*/} has no gpu driver" >&2; fi done else echo "munix: kernel version '$kernel_ver' is older than 6.13, not using gpu due to missing support" >&2; GPU_MODE=software fi MUVM_ARGS+=("--gpu-mode=$GPU_MODE") else BWRAP_ARGS+=("--dir" "/dev/dri") MUVM_ARGS+=("--gpu-mode=software") fi if [ "$WAYLAND" -eq 1 ]; then if [ "$XDG_RUNTIME_DIR" = "" ]; then echo "munix: wayland requested, but no XDG_RUNTIME_DIR set" >&2 exit 1 fi BWRAP_ARGS+=( "--bind" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "--setenv" "WAYLAND_DISPLAY" "$WAYLAND_DISPLAY" ) if [ "$ENV_DEFAULTS" -eq 1 ]; then MUVM_ARGS+=( "-e" "XDG_SESSION_TYPE=wayland" "-e" "SDL_VIDEODRIVER=wayland" "-e" "QT_QPA_PLATFORM=wayland" "-e" "_JAVA_AWT_WM_NONREPARENTING=1" # e.g. with xwayland-satellite "-e" "ELECTRON_OZONE_PLATFORM_HINT=wayland" # 28 < Electron < 39; newer should work by default ) fi fi if [ "$PIPEWIRE" -eq 1 ]; then if [ "$PIPEWIRE_RUNTIME_DIR" = "" ]; then PIPEWIRE_RUNTIME_DIR="$XDG_RUNTIME_DIR" fi if [ "$PIPEWIRE_RUNTIME_DIR" = "" ]; then PIPEWIRE_RUNTIME_DIR="$USERPROFILE" fi if [ "$PIPEWIRE_RUNTIME_DIR" = "" ]; then echo "munix: pipewire requested, but no PIPEWIRE_RUNTIME_DIR/XDG_RUNTIME_DIR/USERPROFILE set" >&2 exit 1 fi if [ "$PIPEWIRE_REMOTE" = "" ]; then PIPEWIRE_REMOTE=pipewire-0 fi BWRAP_ARGS+=("--bind" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE") if [ "$ENV_DEFAULTS" -eq 1 ]; then MUVM_ARGS+=( "-e" "SDL_AUDIO_DRIVER=pipewire" ) fi fi if [ "$X11" -eq 1 ]; then BWRAP_ARGS+=( "--bind" "/tmp/.X11-unix" "/tmp/.X11-unix" "--ro-bind" "$XAUTHORITY" "$XAUTHORITY" ) else unset DISPLAY XAUTHORITY fi declare -a BG_PIDS cleanup() { for pid in "${BG_PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then echo "Killing process $pid" kill -INT "$pid" wait "$pid" 2>/dev/null fi done exit } trap cleanup EXIT INT TERM HOST_RUNTIME_DIR="$XDG_RUNTIME_DIR/munix.$$" mkdir -p $HOST_RUNTIME_DIR rm $HOST_RUNTIME_DIR/* mkdir -p "$HOST_RUNTIME_DIR/home" RUST_LOG=debug sidebus-broker \ --path-mapping "/home=$HOST_RUNTIME_DIR/home" \ "${SIDEBUS_ARGS[@]}" \ --guest-mountpoint /mnt/munix-doc-portal/doc \ --runtime-dir "$HOST_RUNTIME_DIR" \ --unix-path "$HOST_RUNTIME_DIR/port.sock" & # >/dev/null 2>&1 & BG_PIDS+=("$!") while [ ! -S "$HOST_RUNTIME_DIR/port.sock" ]; do sleep 0.1; done BWRAP_ARGS=( # prepend home mount before other mounts to not override custom bind mounts under /home --bind "$HOST_RUNTIME_DIR/home" /home "${BWRAP_ARGS[@]}" --bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal --setenv "RUTABAGA_DBUS_CLIENT_SOCKET" /mnt/munix-doc-portal/port.sock ) if [ "$ENV_DEFAULTS" -eq 1 ]; then MUVM_ARGS+=( "-e" "GTK_USE_PORTAL=1" # GTK 3 including Firefox "-e" "QT_QPA_PLATFORMTHEME=xdgdesktopportal" ) fi if [ "$USING_PUBLISH" -eq 1 ]; then printf "\n\n\n\e[1mNote: due to a \e[31mBUG\e[39m with port publishing (-p) you have to send the first outgoing packet (e.g. ping -c1 8.8.8.8) before your ports start receiving traffic. Sorry for the inconvenience!\e[39;0m\n\n\n\n" >&2 fi # xxx: some time is lost to the starting process.. [[ "$(