#!/bin/sh
# GENERATED by packaging/gen-variant-scripts.sh — DO NOT EDIT THIS FILE.
#   regenerate: sh packaging/gen-variant-scripts.sh          check: … --check
#
# Jihad Browser — Enyo 1.0 variant (net.riverstonerelay.jihad-browser) — pre-removal. Runs as ROOT.
#
# ON A REAL REMOVAL it removes EXACTLY what this variant's postinst created, and nothing else:
#   /usr/lib/BrowserPlugins/BrowserAdapterJihad.so
#   /usr/lib/jihad/enyo/BrowserAdapterImpl.so   (+ the now-empty /usr/lib/jihad/enyo)
#   /usr/lib/jihad/enyo/InteractiveWidgetRect.schema
#   /etc/event.d/jihad
#   /var/palm/jihad/enyo/                       (the runtime state dir, log included)
#   $APP/profile/                                (the engine's DURABLE profile: cookies.sqlite,
#                                                 prefs.js, permissions — see below)
#   $APP/cache/                                  (the engine's DISPOSABLE local profile: cache2
#                                                 + startupCache — see below)
#   /tmp/yapserver.jihad-browser                       (this variant's socket)
# `/usr/lib/jihad` and `/var/palm/jihad` are only ever `rmdir`'d — that succeeds solely when the
# LAST variant is gone, and can never take a sibling's subdirectory with it.
#
# ON AN UPGRADE it removes NOTHING. See step 0.
#
# ── TWO PROPERTIES THIS SCRIPT EXISTS TO GUARANTEE ───────────────────────────────────────────
# NO REFCOUNT. The 2026-07-29 review (#4) added a loop that counted sibling
# net.riverstonerelay.jihad-browser* app dirs and skipped teardown while any survived, because
# all variants shared one runtime. Under R7 nothing is co-owned, so that loop is DELETED: this
# package unconditionally removes its own files, and no sibling can be affected either way.
#
# NO GLOBS ACROSS VARIANTS. `rm -f /tmp/yapserver.jihad-browser*` (the old code) deletes the
# Mochi and Mojo sockets; `killall jihad-browserserver` kills their daemons (all three variants
# ship a binary with that name). Every operation below names one exact path or matches one
# exact process.
#
# The engine, daemon, bundled glibc and GRE resources live in $APP/deviceroot and go away with
# the app directory, which the installer removes. There is nothing to clean under
# /media/internal because this package never wrote anything there. That teardown shape is
# adapted from the Atlas browser's atlas-browser-app/packaging/ipk-prerm.sh (Apache-2.0,
# Herman van Hazendonk / Herrie82).

V=enyo
APP=/media/cryptofs/apps/usr/palm/applications/net.riverstonerelay.jihad-browser
HL=$APP/deviceroot/hl
SHIM=/usr/lib/BrowserPlugins/BrowserAdapterJihad.so
IMPLDIR=/usr/lib/jihad/enyo
IMPL=$IMPLDIR/BrowserAdapterImpl.so
RECTSCHEMA=$IMPLDIR/InteractiveWidgetRect.schema
JOB=/etc/event.d/jihad
SOCK=/tmp/yapserver.jihad-browser
STATE=/var/palm/jihad/enyo
# The engine's profile, BOTH halves, in the app's own directory on cryptofs:
#   $APP/profile   Gecko's ProfD  — durable: cookies.sqlite, prefs.js, permissions
#   $APP/cache     Gecko's ProfLD — disposable: cache2, startupCache
# Not in $STATE: /var has 49.6 MB free and is shared with system state, and both isis
# (CookieJarPath/CachePath under /media/cryptofs/.browser) and Atlas (netdata/netcache/cookies.db
# in its app deviceroot) put these on cryptofs on this exact device — Atlas because /media/internal
# is VFAT, with no hard links and no real file locking, which breaks the network cache AND
# SQLite. See RuntimeProfileDir()/RuntimeCacheDir() in render/goanna/JihadRuntimePaths.h.
#
# The DAEMON creates both at runtime, so ipkg never tracked them and would leave the whole app
# directory behind as residue — exactly the "no residue" half of R8 that a full install->remove
# filesystem diff checks. They are therefore removed HERE, explicitly, on a real removal only:
# an upgrade must not throw away the user's cookies (F-6).
PROFILE=$APP/profile
CACHE=$APP/cache
# Two more directories the DAEMON creates at runtime inside the app's own directory, because a
# card may load a local file only from there (LunaSysMgr's file-access rule, measured
# 2026-10-02): bookmark thumbnails it renders on request, the readable details of a
# certificate while an SSL warning is open, and text the long-press menu's Copy is handing to
# the card (each such file lives fifteen seconds). Not in any package file list, so the
# installer does not know them; they go with the profile.
THUMBS=$APP/thumbnails
CERTINFO=$APP/certinfo
CLIP=$APP/clip
log() { echo "jihad-prerm($V): $*"; }

# ── 0. is this a REMOVAL or an UPGRADE? ──────────────────────────────────────────────────────
# F-6: this script used to ignore its argument, so an UPGRADE ran the same `rm -rf
# /var/palm/jihad/enyo` as a removal — destroying the user's engine profile (cookies, logins,
# site permissions), the daemon log and anything else the state dir holds on EVERY version
# bump. And because ipkg defers control scripts, the new postinst that was supposed to put it
# all back may not run until much later, or at all: the data is gone first and unconditionally.
# ipkg/dpkg call prerm as one of:
#     prerm remove                     a real removal (also `remove in-favour <pkg>`)
#     prerm upgrade <new-version>      this package is being REPLACED, not removed
#     prerm failed-upgrade <old-ver>   an upgrade is being rolled back — still not a removal
#     prerm deconfigure in-favour …    a dependency shuffle — still not a removal
# Only the first purges. Everything else means THIS PACKAGE IS STAYING, so both the state dir
# and the rootfs files (which the new postinst rewrites in place anyway) are left alone — and
# leaving them means a deferred/failed new postinst degrades to "still running the old shim"
# rather than "nothing installed at all".
# No argument at all is treated as `remove`: callers that pass none are doing a plain uninstall,
# and an uninstall that leaves residue fails R8.
ACTION=$1
[ -n "$ACTION" ] || ACTION=remove
case "$ACTION" in
	remove|purge) PURGE=1 ;;
	*)            PURGE=0 ;;
esac

# ── 1. stop THIS variant's daemon ─────────────────────────────────────────────────────────────
# Unconditional, upgrade included: the running daemon owns the socket and holds the replaced
# files open, so the new install cannot come up cleanly until it is gone.
log "stopping the Enyo 1.0 daemon..."
stop jihad 2>/dev/null || true
# Fallback for a daemon upstart is not supervising (started by hand, or orphaned by a crash).
# It must not be `killall jihad-browserserver` — that is every variant's daemon. Instead match
# on argv: the upstart job execs `ld-2.23.so --library-path $HL ./jihad-browserserver $HL`, so
# only THIS variant's processes carry THIS app's bundle directory as an exact argument.
#
# The comparison is done in the shell, NOT with `grep -x`: this device ships BusyBox 1.17.3,
# whose grep supports only -HhnlLoqvsriwFE — there is no -x. `grep -qxF` therefore does not
# match-and-fail, it prints its usage text and returns non-zero for EVERY process, silently
# disabling this whole fallback. (Measured on-device 2026-07-31, after the real removal run
# dumped BusyBox's grep usage into the ipkg output.) A plain -F substring match would work
# today but is a trap for later: the Enyo app id is a prefix of the Mochi and Mojo ones, so it
# only stays safe because the path continues "/deviceroot" — one rename away from killing a
# sibling's daemon. An exact whole-argument comparison has no such edge.
for p in /proc/[0-9]*; do
	[ -r "$p/cmdline" ] || continue
	match=0
	while IFS= read -r arg; do
		[ "$arg" = "$HL" ] && { match=1; break; }
	done <<EOF
$(tr '\0' '\n' < "$p/cmdline" 2>/dev/null)
EOF
	[ "$match" = 1 ] && kill "$(basename "$p")" 2>/dev/null || true
done
rm -f "$SOCK"                       # exact socket path — never a glob (see header)

if [ "$PURGE" = 0 ]; then
	log "$ACTION — this package is staying; leaving the rootfs footprint and $STATE untouched"
	exit 0
fi

# ── 2. the rootfs + state removals: ONE rw window, closed on every exit path ──────────────────
log "removing this variant's rootfs components (rw)..."
# RESTORE WHAT WE FOUND, don't assume we own the mount state. When the installer (Preware's
# ipkgservice) drives this, `/` is ALREADY read-write for the duration of its own work — so
# unconditionally forcing it back to read-only here either fights the installer mid-install or
# fails outright. Measured 2026-08-05 on a supported install: our own honest warning,
# "could not restore / to read-only", and `/` left mounted rw afterwards, which is exactly the
# R8 violation this window exists to prevent. If it was already rw on entry, leave it to
# whoever made it so; only a window WE opened is a window we must close.
ROOTFS_WAS_RW=no
# The mount that counts is the LAST one on / that is not the initramfs "rootfs" (always rw, listed
# first): `mount | grep "on / .*rw"` matched that one, so a read-only root was taken for read-write
# and nothing was remounted (device 2026-10-12: "chmod: /usr/lib/jihad: Read-only file system").
if awk '$2 == "/" && $1 != "rootfs" { o = $4 } END { exit !(o ~ /^rw(,|$)/) }' /proc/mounts; then
	ROOTFS_WAS_RW=yes
fi
if [ "$ROOTFS_WAS_RW" = no ]; then
	trap 'mount -o remount,ro / 2>/dev/null || true' EXIT
	mount -o remount,rw /
else
	log "/ was already read-write (installer-driven) — leaving the mount state to the caller"
fi
rm -f "$SHIM" "/usr/lib/BrowserPlugins/.BrowserAdapterJihad.so.new"     # .new: an interrupted postinst's temp
rm -f "$IMPL" "$IMPLDIR/.BrowserAdapterImpl.so.new"
rm -f "$RECTSCHEMA"
rmdir "$IMPLDIR" 2>/dev/null || true
rmdir /usr/lib/jihad 2>/dev/null || true    # succeeds only once the LAST variant is gone
# De-register this variant's db8 kinds — they are ours, and leaving them behind is residue of
# exactly the kind R8 forbids, just in a database rather than on a filesystem. delKind removes
# the kind AND its objects, which is right: the history belonged to the app being removed.
if [ -d "$APP/db/kinds" ]; then
	for kf in "$APP/db/kinds"/*; do
		[ -f "$kf" ] || continue
		kn=$(basename "$kf")
		luna-send -n 1 -a "net.riverstonerelay.jihad-browser" luna://com.palm.db/delKind "{\"id\":\"$kn:1\"}" >/dev/null 2>&1 \
			&& log "db8 kind removed: $kn:1" || log "db8 kind $kn:1 not present (already gone)"
	done
fi

rm -f "$JOB"
# This variant's Luna service name (exact paths, one variant's name — no glob could reach a
# sibling's). Leaving these behind would be rootfs residue that R8 forbids, and would leave the
# hub permitting a name nothing serves.
# A Luna service name CANNOT contain a hyphen — LS2 rejects it at the caller
# (`_UriParse: Not a valid service name`) and LSRegister fails with -1027. Our YAP names all
# have hyphens, so the Luna name is the camel-cased form, matching the platform's own idiom
# (com.palm.browserServer, com.palm.applicationManager). Kept as an explicit table rather than
# a sed transform: three variants, and busybox sed has no \U.
case "enyo" in
	enyo)  LSNAME=net.riverstonerelay.jihadBrowser ;;
	mochi) LSNAME=net.riverstonerelay.jihadBrowserMochi ;;
	mojo)  LSNAME=net.riverstonerelay.jihadBrowserMojo ;;
	*)     LSNAME=net.riverstonerelay.jihadBrowser ;;
esac
rm -f /usr/share/ls2/roles/prv/$LSNAME.json /usr/share/ls2/roles/pub/$LSNAME.json \
      /usr/share/dbus-1/system-services/$LSNAME.service \
      /usr/share/dbus-1/services/$LSNAME.service
rm -rf "$STATE"                             # this variant's state dir only
rmdir /var/palm/jihad 2>/dev/null || true   # ditto
sync
# The engine profile + cache are on cryptofs, not the rootfs, so they need no rw window — but
# they do need to go, for the reason at $PROFILE above. Exact paths, both inside THIS variant's
# own app directory; no glob could reach a sibling's.
rm -rf "$PROFILE" "$CACHE" "$THUMBS" "$CERTINFO" "$CLIP"
# F-9: a failed restore-to-read-only is REPORTED, never swallowed (R8 requires `/` back to ro on
# every exit path). It does not by itself fail the removal — the removal above already happened,
# and the EXIT trap gets one more attempt — but it does not get to be silent either.
if [ "$ROOTFS_WAS_RW" = yes ]; then
	log "leaving / read-write as found"
else
	# Retried for about ten seconds, as postinst does: a write still settling on / makes it busy.
	ro_try=0
	until mount -o remount,ro / 2>/dev/null; do
		ro_try=$((ro_try + 1))
		if [ "$ro_try" -ge 10 ]; then
			echo "jihad-prerm($V): WARNING: could not restore / to read-only" >&2
			break
		fi
		sync; sleep 1
	done
	[ "$ro_try" -lt 10 ] && trap - EXIT
fi

# ── 3. verify the removal ACTUALLY happened — believe the filesystem, not $? ──────────────────
# F-9: every step above is best-effort by design (a half-installed package must still be
# removable), and the script then reported success unconditionally. So a failed `mount -o
# remount,rw /` turned removal into a silent no-op while the installer recorded a clean
# uninstall — leaving a stale shim to register an NPAPI MIME on every boot and a stale upstart
# job to respawn against an app directory that no longer exists. postinst already refuses to
# report a deploy it cannot see on disk; this is the same rule applied to the reverse operation.
rc=0
for f in "$SHIM" "$IMPL" "$JOB" "$SOCK" "$STATE" "$PROFILE" "$CACHE" "$THUMBS" "$CERTINFO" "$CLIP"; do
	if [ -e "$f" ]; then log "ERROR: $f still present after removal"; rc=1; fi
done
if [ "$rc" != 0 ]; then
	echo "jihad-prerm($V): removal INCOMPLETE — refusing to report success" >&2
	exit 1
fi

# F-12: no `killall LunaSysMgr` here either — see this variant's postinst. It would take down
# every card of every app (R7's isolation, broken from the packaging side) to achieve a plugin
# re-scan that only a boot performs.
log "removal complete."
log "REBOOT to drop BrowserAdapterJihad.so from WebKit's NPAPI MIME database; until then it is registered but"
log "its backing file is gone, so a card asking for that MIME simply fails to instantiate."
exit 0
