# GENERATED by packaging/gen-variant-scripts.sh — DO NOT EDIT THIS FILE.
#   regenerate: sh packaging/gen-variant-scripts.sh          check: … --check
#
# Jihad BrowserServer (UXP/Goanna daemon) — Enyo 2 + Mochi variant. Installed to /etc/event.d/jihad-mochi.
#
# This is THIS VARIANT'S OWN upstart job. It does not touch the stock `browserserver` job, and
# it does not touch the other Jihad variants' jobs: stock /usr/bin/BrowserServer keeps serving
# /tmp/yapserver.browser for every other app, and each Jihad variant serves exactly one socket
# (/tmp/yapserver.jihad-browser-mochi here), reached only by the card whose WebView asks for that variant's
# plugin MIME. upstart supervises this (respawn) so the browser survives a daemon crash.
#
# RUNS IN PLACE. The daemon, libxul, the bundled glibc-2.23 loader and the GRE resources are
# executed straight out of the app's own cryptofs deviceroot — nothing was ever copied to
# /media/internal (the user's vfat USB storage). Verified live 2026-07-31: /media/cryptofs is
# fuse.cryptofs (rw,nosuid,nodev), NOT noexec, and a binary in an app dir executes there. Model
# adapted from the Atlas browser (atlas-browser-app/packaging/ipk-postinst.sh, Apache-2.0,
# Herman van Hazendonk / Herrie82), which runs its WPE engine in place the same way.
#
# ── HARD-WON: LD_LIBRARY_PATH IS SET ONLY VIA `env`, ON THE EXEC LINE ────────────────────────
# It must NEVER be exported into this script's shell. The bundled gcc9 glibc-2.23 is not
# compatible with the device's 2.8 userland, so an exported LD_LIBRARY_PATH makes /bin/rm,
# mkdir, touch — every command below — load the wrong libc and segfault before the daemon ever
# execs. Keep it on the `exec env` line and nowhere else.
start on stopped fontconfig_cache
stop on started start_update
# ── AND stop when the system is going down, EARLY ────────────────────────────────────────────
# Without this we are killed by the late generic sweep at reboot, which runs at the same moment
# cryptofs is torn down — and the engine profile lives on cryptofs. Our SIGTERM handler flushes
# the add-on database and prefs, so it was writing and mmap-reading files whose backing store
# was disappearing: two daemons took SIGBUS (signal 7) on 2026-08-05, wrote crash dumps onto a
# /var that was unmounting, and the device would not boot again.
#
# The stock browserserver has only the start_update clause and gets away with it because it does
# no work on SIGTERM — it just dies. We do work, so we have to be asked earlier. Runlevel 0 is
# halt and 6 is reboot; `stop on runlevel [06]` is the platform's own idiom for this (ntpdate-sync
# uses it), and it fires while the filesystems are still mounted, which is the whole point.
# Boot runlevels are 2/3, so this never interferes with starting.
stop on runlevel [06]

description "Jihad BrowserServer (Goanna) — Enyo 2 + Mochi"

script
	APP=/media/cryptofs/apps/usr/palm/applications/net.riverstonerelay.jihad-browser-mochi
	HL=$APP/deviceroot/hl
	STATE=/var/palm/jihad/mochi

	# The state dir is created root-owned 0755 by postinst; recreate it best-effort because a
	# device reset / GC wipes /var. If it is genuinely unavailable (e.g. a read-only rootfs at
	# this point in boot) fall back to /dev/null rather than letting a failed redirect kill the
	# job and spin the respawn limit — the daemon itself is still perfectly able to run.
	mkdir -p "$STATE" 2>/dev/null || true
	LOG=$STATE/daemon.log
	touch "$LOG" 2>/dev/null || LOG=/dev/null

	# Cap the log. /var is a 62 MB partition shared with db8, luna preferences and tokens, and
	# on 2026-08-06 the three variants' logs reached 55 MB of it and took /var to 100% full.
	# A full /var does not announce itself: every fprintf(stderr) in the daemon then fails with
	# ENOSPC SILENTLY, so the log freezes at a byte count while the daemon keeps serving pages
	# normally — and a frozen log reads exactly like a live one. A stale line read out of one
	# cost the previous session a whole false diagnosis. Rotate at 2 MB keeping one generation,
	# so the worst case across three variants is 12 MB rather than the whole partition.
	#
	# THIS CHECK ONLY RUNS AT JOB START, and a daemon stays up for days: two idle daemons wrote
	# 10 MB each in 3.6 days (2026-10-01). So the same cap is ALSO enforced by the daemon while
	# it runs (render/browserserver/Main.cpp, log_cap_cb: every 30 s, copy to daemon.log.old
	# then truncate in place, because plugin-container inherits this descriptor). The numbers:
	#   per variant, at any uptime   daemon.log <= 2 MB (+ ~70 KB overshoot) and one kept
	#                                generation <= 2 MB                          => ~4 MB
	#   three variants               ~12 MB of the 62 MB /var, worst case
	#   idle (no card connected)     nothing is written at all
	# Keep LOGMAX here and the daemon's default cap equal; $JIHAD_LOG_MAX lowers the daemon's
	# for a test.
	if [ "$LOG" != /dev/null ]; then
		LOGMAX=2097152
		# `tr -d ' '`: some wc builds pad the count, and a padded value makes `[ -ge ]` fail
		# with "integer expression expected" — which would abort this script and, because it
		# runs before the exec, take the whole job down. Never let logging kill the daemon.
		SZ=$(wc -c < "$LOG" 2>/dev/null | tr -d ' \t') || SZ=0
		case "$SZ" in ''|*[!0-9]*) SZ=0 ;; esac
		if [ "$SZ" -ge "$LOGMAX" ]; then
			mv -f "$LOG" "$LOG.old" 2>/dev/null || true
			: > "$LOG" 2>/dev/null || true
		fi
	fi
	exec >>"$LOG" 2>&1

	# Only this variant's own socket — an exact path, never `…jihad-browser*`, which would
	# delete the other variants' sockets out from under their running daemons.
	rm -f /tmp/yapserver.jihad-browser-mochi

	cd "$HL" || exit 1
	# NB: do NOT set JIHAD_DUMP in normal operation — it makes every paint write a ~2.2 MB PPM
	# char-by-char (fputc), which added ~400 ms of latency PER KEYSTROKE. Set it only when
	# debugging what the engine renders, and point it INSIDE the state dir, never at
	# /media/internal (env JIHAD_DUMP=$STATE/frame.ppm).
	# JIHAD_BS_NAME is this variant's YAP service name — it is what makes the socket, and
	# therefore the whole daemon<->adapter channel, unique per variant.
	# JIHAD_STATE_DIR tells the daemon where its operational state (the log and the debug
	# channels) belongs; it must never fall back to the user's storage. The engine PROFILE and
	# CACHE are NOT here — they go to $APP/profile and $APP/cache on cryptofs, where isis and
	# Atlas both put them, because /var has 49.6 MB free and is shared with system state (see
	# RuntimeProfileDir()/RuntimeCacheDir() in render/goanna/JihadRuntimePaths.h).
	# ICU_DATA is REQUIRED, not a nicety. libxul loads its Unicode tables from icudt78l.dat at
	# XPCOM startup; the path compiled into the engine is the BUILD machine's, which does not
	# exist here, and ICU has no notion of "next to the library". Without this the daemon aborts
	# on every single start with
	#     ###!!! ABORT: u_init() failed: file .../xpcom/build/XPCOMInit.cpp, line 698
	# and upstart respawns it forever. Diagnosed on-device 2026-07-31: identical invocation, the
	# only difference being ICU_DATA, gets past u_init() and on into fontconfig.
	# HOME IS LOAD-BEARING, not hygiene. UXP reads it via
	# `nsDependentCString(PR_GetEnv("HOME"))` with NO null check (xpcom/io/
	# SpecialSystemDirectory.cpp GetUnixHomeDir, xpcom/io/nsAppFileLocationProvider.cpp),
	# so an unset HOME is strlen(NULL) and an instant SIGSEGV at address 0 during
	# engine startup. An upstart job inherits init's environment, which on webOS 3 has
	# no HOME — which is why this crashed 100% on device and never in the container
	# (podman always passes -e HOME=...). Diagnosed 2026-08-01 from the daemon's own
	# fault report. The daemon also sets this itself if it is missing, so hand-launched
	# runs are covered; it is repeated here because this is where the daemon's
	# environment is actually defined, and a reader must not have to know the C++ to
	# see it. Pointed at the state dir so anything Gecko writes under $HOME stays
	# inside the footprint this variant's prerm removes.
	# THE GPU PATH IS THE DEFAULT (cavekit-gpu-rendering R1, T-510, 2026-10-19): the engine
	# composites on the device's GPU in-process and the daemon reads the frames back
	# (JIHAD_GPU_COMPOSITOR), with the express lane making frames off the engine's main thread
	# (JIHAD_GPU_EXPRESS; render/goanna/JihadFrameLock.h). The software path is one switch away:
	# JIHAD_GPU_COMPOSITOR=0 here, or the pref jihad.gpu.enabled=false in the profile (the daemon
	# reads it before the engine starts). A GPU that fails at run time falls back to the software
	# path by itself (T-509). The daemon's log says which path it took ("rendering: ...").
	exec env LD_LIBRARY_PATH="$HL" ICU_DATA="$HL" HOME="$STATE" \
	         JIHAD_BS_NAME=jihad-browser-mochi JIHAD_OFFSCREEN=1 JIHAD_DISABLE_OMTC=1 \
	         JIHAD_GPU_COMPOSITOR=1 JIHAD_GPU_EXPRESS=1 \
	         JIHAD_STATE_DIR="$STATE" \
	    ./ld-2.23.so --library-path "$HL" ./jihad-browserserver "$HL"
end script

# The daemon raises the CPU governor's responsiveness while a plugin instance is alive and lowers
# it again on teardown (libxul patch 0027). Those are SYSTEM-WIDE tunables, so a daemon that dies
# holding the boost — a crash, an upstart kill, a `stop` mid-playback — would leave the WHOLE
# device tuned for battery burn with nothing owning it. This restores the stock values
# unconditionally on the way out; it is a no-op when the daemon already released them, and it must
# stay cheap and never fail the job.
#
# NEVER write scaling_governor here or anywhere else: switching away from `ondemandtcl` deadlocks
# cpufreq in the kernel and every later reader blocks in unkillable D state, which takes a forced
# reboot to clear. Writing the governor's own tunables, as below, is safe.
post-stop script
	D=/sys/devices/system/cpu/cpufreq/ondemandtcl
	[ -w "$D/up_threshold" ] && echo 95 > "$D/up_threshold" 2>/dev/null
	[ -w "$D/sampling_rate" ] && echo 200000 > "$D/sampling_rate" 2>/dev/null
	true
end script

respawn
respawn limit 10 5
