#!/bin/bash
# An AppImage imported from the front end (AppImageManager), extracted once at import into
#   /opt/appimages/user/<id>/app
# and started from there: proot has no FUSE to mount the image, and extracting it at every
# start (APPIMAGE_EXTRACT_AND_RUN) would cost the whole image in /tmp each time.
#   bannerlator-appimage-run /opt/appimages/user/<id> [args...]
set -u
dir=${1:?usage: bannerlator-appimage-run <imported AppImage directory> [args...]}
shift
export APPDIR=$dir/app
# APPIMAGE is left unset on purpose: with it an app believes it runs from an image file and offers
# to add itself to the menu (DuckStation) or update the file in place - DroidDeck already does the
# one, and there is no image file for the other.
unset APPIMAGE
export ARGV0=$(cat "$dir/name" 2>/dev/null || basename "$dir")
if [ ! -x "$APPDIR/AppRun" ]; then
  echo "bannerlator-appimage-run: $APPDIR/AppRun is missing; import the AppImage again" >&2
  exit 127
fi
# Browsers sandbox their own children with namespaces and a setuid helper, neither of which proot
# can give them (the Flatpak sandboxes get the same; see BwrapSpawner): Firefox and its forks (Zen,
# LibreWolf) by these switches, Electron and Chromium builds by --no-sandbox. Chromium on Wayland
# also asks the render node for a DRM version KGSL cannot give, so with an X server up it stays on
# X11, which it picks from the session type.
export MOZ_DISABLE_CONTENT_SANDBOX=1 MOZ_DISABLE_GMP_SANDBOX=1 MOZ_DISABLE_RDD_SANDBOX=1
export MOZ_DISABLE_SOCKET_PROCESS_SANDBOX=1 MOZ_DISABLE_UTILITY_SANDBOX=1
flags=()
if [ -e "$APPDIR/chrome-sandbox" ] || compgen -G "$APPDIR/*/chrome-sandbox" >/dev/null; then
  flags+=(--no-sandbox)
  if [ -n "${DISPLAY:-}" ]; then
    export XDG_SESSION_TYPE=x11
    unset WAYLAND_DISPLAY
    flags+=(--ozone-platform=x11)
  fi
fi
echo "== appimage $ARGV0 ($APPDIR) ${flags[*]}"
cd "$APPDIR" || exit 1
# Apps expect a session bus; Electron's main process traps (SIGTRAP) on an address it cannot
# parse. A run mode has none, so one is started for the app, as for Flatpak apps.
case ${DBUS_SESSION_BUS_ADDRESS:-} in
  unix:*) "$APPDIR/AppRun" "${flags[@]}" "$@" ;;
  *) unset DBUS_SESSION_BUS_ADDRESS
     if command -v dbus-run-session >/dev/null 2>&1; then
       dbus-run-session -- "$APPDIR/AppRun" "${flags[@]}" "$@"
     else
       "$APPDIR/AppRun" "${flags[@]}" "$@"
     fi ;;
esac
rc=$?
# The program a session was started for may hand over to another process and exit: Electron apps
# relaunch themselves (Obsidian on its first start), launchers fork their real program. The
# session ends with this script, and takes the rest with it - so it waits while anything running
# from the image is still up.
image_running() {
  local p exe
  for p in /proc/[0-9]*; do
    exe=$(readlink "$p/exe" 2>/dev/null) || continue
    case $exe in "$APPDIR"/*) return 0 ;; esac
  done
  return 1
}
while image_running; do sleep 2; done
exit $rc
