2025-09-25 22:29:24 -03:00
#!/usr/bin/env bash
SCRIPT_PATH=$(dirname $(realpath -s $0))
MUVM_PATH=$(dirname $(which muvm))
PASST_PATH=$(dirname $(which passt))
2025-09-25 22:29:24 -03:00
HOST_OPENGL_DRIVER=/run/opengl-driver
2025-12-05 00:31:24 -03:00
: "${MICROVM_DEFAULT_COMMAND:=bash}"
2025-09-25 22:29:24 -03:00
MICROVM_CLOSURE=
MICROVM_COMMAND=()
2025-09-25 22:29:24 -03:00
MICROVM_UID=1337
MICROVM_GID=1337
2025-09-25 22:29:24 -03:00
BWRAP_ARGS=()
MUVM_ARGS=()
2026-02-27 02:51:07 -03:00
SIDEBUS_ARGS=()
2025-09-25 22:29:24 -03:00
GPU=1
WAYLAND=1
PIPEWIRE=1
X11=0
2026-01-30 05:47:28 -03:00
ENV_DEFAULTS=1
2026-01-30 04:35:25 -03:00
USING_PUBLISH=0
2025-09-25 22:29:24 -03:00
export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C
2025-09-25 22:29:24 -03:00
2025-11-27 21:59:05 -03:00
if [ ! -e "$HOST_OPENGL_DRIVER" ]; then
HOST_OPENGL_DRIVER="$FALLBACK_OPENGL_DRIVER"
fi
2025-09-25 22:29:24 -03:00
while [ "$#" -gt 0 ]; do
case "$1" in
2025-09-25 22:29:24 -03:00
-u|--uid) MICROVM_UID="$2"; shift 2;;
-g|--gid) MICROVM_GID="$2"; shift 2;;
2025-09-25 22:29:24 -03:00
--no-gpu) GPU=0; shift 1;;
--no-wayland) WAYLAND=0; shift 1;;
--no-pipewire) PIPEWIRE=0; shift 1;;
2026-01-30 05:47:28 -03:00
--no-env-defaults) ENV_DEFAULTS=0; shift 1;;
2025-09-25 22:29:24 -03:00
--x11) X11=1; shift 1;;
2026-02-27 02:51:07 -03:00
-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;;
2026-01-30 04:35:25 -03:00
-p|--publish) USING_PUBLISH=1; MUVM_ARGS+=("--publish=$2"); shift 2;;
2025-09-25 22:29:24 -03:00
--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;;
2025-09-26 06:09:41 -03:00
--) shift 1; MICROVM_COMMAND+=("$@"); break;;
2025-09-25 22:29:24 -03:00
-*) 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
2025-11-27 20:33:07 -03:00
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
2025-11-27 21:59:05 -03:00
if [ ! -e "$HOST_OPENGL_DRIVER" ]; then
echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2
exit 1
fi
2025-11-03 17:57:08 +01:00
# Resolve symlinks automatically
MICROVM_CLOSURE=$(realpath "$MICROVM_CLOSURE")
2025-09-25 22:29:24 -03:00
if [ ${#MICROVM_COMMAND[@]} -eq 0 ]; then
2025-12-05 00:31:24 -03:00
MICROVM_COMMAND=("$MICROVM_DEFAULT_COMMAND")
2025-09-25 22:29:24 -03:00
fi
if [ "$GPU" -eq 1 ]; then
BWRAP_ARGS+=(
"--dev-bind" "/dev/dri" "/dev/dri"
"--ro-bind" "$HOST_OPENGL_DRIVER" "/run/opengl-driver"
)
2025-09-25 22:36:39 -03:00
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
2025-11-27 20:33:44 -03:00
amdgpu|msm_dpu) # TODO: i915
2025-09-25 22:36:39 -03:00
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")
2025-09-25 22:29:24 -03:00
else
BWRAP_ARGS+=("--dir" "/dev/dri")
2025-09-25 22:36:39 -03:00
MUVM_ARGS+=("--gpu-mode=software")
2025-09-25 22:29:24 -03:00
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"
)
2026-01-30 05:47:28 -03:00
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
2025-09-25 22:29:24 -03:00
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")
2026-01-30 05:47:28 -03:00
if [ "$ENV_DEFAULTS" -eq 1 ]; then
MUVM_ARGS+=(
"-e" "SDL_AUDIO_DRIVER=pipewire"
)
fi
2025-09-25 22:29:24 -03:00
fi
if [ "$X11" -eq 1 ]; then
BWRAP_ARGS+=(
"--bind" "/tmp/.X11-unix" "/tmp/.X11-unix"
"--ro-bind" "$XAUTHORITY" "$XAUTHORITY"
)
else
unset DISPLAY XAUTHORITY
fi
2025-11-14 06:20:44 -03:00
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/*
2026-02-27 02:51:07 -03:00
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 &
2025-11-14 06:20:44 -03:00
BG_PIDS+=("$!")
while [ ! -S "$HOST_RUNTIME_DIR/port.sock" ]; do sleep 0.1; done
2026-02-27 02:51:07 -03:00
BWRAP_ARGS=( # prepend home mount before other mounts to not override custom bind mounts under /home
--bind "$HOST_RUNTIME_DIR/home" /home
"${BWRAP_ARGS[@]}"
2025-11-14 06:20:44 -03:00
--bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal
2026-02-27 02:51:07 -03:00
--setenv "RUTABAGA_DBUS_CLIENT_SOCKET" /mnt/munix-doc-portal/port.sock
2025-11-14 06:20:44 -03:00
)
2026-01-30 05:47:28 -03:00
if [ "$ENV_DEFAULTS" -eq 1 ]; then
MUVM_ARGS+=(
"-e" "GTK_USE_PORTAL=1" # GTK 3 including Firefox
"-e" "QT_QPA_PLATFORMTHEME=xdgdesktopportal"
)
fi
2025-11-14 06:20:44 -03:00
2026-01-30 04:35:25 -03:00
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
2026-02-20 04:12:54 -03:00
# xxx: some time is lost to the starting process..
[[ "$(</proc/uptime)" =~ ([0-9]+)\.([0-9]+) ]]
BOOT_TIME_OFFSET="${BASH_REMATCH[1]} $(( ${BASH_REMATCH[2]} * 1000000 ))"
2025-11-14 06:20:44 -03:00
# do not 'exec' because of cleanup :)
bwrap --unshare-all --share-net \
2025-09-25 22:29:24 -03:00
--uid $MICROVM_UID --gid $MICROVM_GID \
2025-09-25 22:29:24 -03:00
--tmpfs / \
2025-12-04 06:59:50 -03:00
--dir /run --dir /var --symlink /run /var/run --dir /tmp --dir /mnt --dir /bin --dir /usr/bin \
2025-09-25 22:29:24 -03:00
--proc /proc --ro-bind /sys /sys \
2025-09-25 22:29:24 -03:00
--dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm \
2025-09-25 22:29:24 -03:00
--ro-bind "$MUVM_PATH" /run/munix/muvm \
--ro-bind "$PASST_PATH" /run/munix/passt \
2025-12-04 06:59:50 -03:00
--ro-bind "$SCRIPT_PATH/micro-activate" /opt/bin/micro-activate \
2025-10-31 04:44:28 -03:00
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \
2026-02-27 02:51:07 -03:00
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-dbusbridge \
2025-12-04 06:59:50 -03:00
--symlink "$MICROVM_CLOSURE/etc" /etc \
--symlink "$MICROVM_CLOSURE/sw/bin/sh" /bin/sh \
--symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \
--symlink "$MICROVM_CLOSURE" /run/current-system \
2025-09-25 22:29:24 -03:00
--ro-bind /nix/store /nix/store \
2025-12-04 06:59:50 -03:00
--file 13 /run/resolv.conf \
2026-02-13 14:55:52 -03:00
--file 14 /run/localtime \
2025-09-25 22:29:24 -03:00
--dir "$XDG_RUNTIME_DIR" \
2025-09-25 22:29:24 -03:00
--setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \
"${BWRAP_ARGS[@]}" \
2025-09-25 22:29:24 -03:00
muvm \
2026-02-27 02:51:07 -03:00
--custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console" \
2025-09-25 22:29:24 -03:00
"${MUVM_ARGS[@]}" \
2025-10-31 04:44:28 -03:00
-e container=munix \
2025-10-03 01:37:22 -03:00
-e MICROVM_CLOSURE="$MICROVM_CLOSURE" \
-e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \
2026-02-20 04:12:54 -03:00
-e BOOT_TIME_OFFSET="$BOOT_TIME_OFFSET" \
2026-01-15 17:09:43 +01:00
-i -t -- "${MICROVM_COMMAND[@]}" \
2026-02-13 14:55:52 -03:00
13< /etc/resolv.conf \
14< /etc/localtime