From 8f2472507869e3cbae76c47837981cdf3fa610a2 Mon Sep 17 00:00:00 2001 From: sudolulo Date: Mon, 15 Jun 2026 02:35:55 +0000 Subject: [PATCH] Add kill switch and recover.sh for emergency recovery If the patch ever prevents middlewared from starting, users now have a clear escape hatch that requires no knowledge of Python internals: bash /data/truecloud-patch/recover.sh Or at a bare shell prompt: touch /data/truecloud-patch/disabled systemctl restart middlewared sitecustomize.py checks for /data/truecloud-patch/disabled at Python startup and skips the import hook entirely when the file exists. apply.sh does the same so the PREINIT script also does nothing on reboot. recover.sh is copied to /data/truecloud-patch/ by install.sh so it is available even without the original repo directory. README gains an "Emergency recovery" section above Troubleshooting. --- README.md | 30 ++++++++++++++++++++++++++++++ install.sh | 3 ++- patch/apply.sh | 9 +++++++++ patch/sitecustomize.py | 3 +++ recover.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100755 recover.sh diff --git a/README.md b/README.md index a5a0df5..c602cda 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,36 @@ restart. --- +## Emergency recovery + +If middlewared stops starting after installing this patch, run this from the +TrueNAS shell (local console, SSH, or the debug shell in the UI): + +```bash +bash /data/truecloud-patch/recover.sh +``` + +That creates a kill-switch file (`/data/truecloud-patch/disabled`) that +`sitecustomize.py` checks at startup. With the switch set, the import hook is +skipped entirely and middlewared starts clean. Your system returns to +Storj-only TrueCloud Backup — nothing else is affected. + +If you cannot run a script and only have a bare shell prompt: + +```bash +touch /data/truecloud-patch/disabled +systemctl restart middlewared +``` + +To re-enable the patch after investigating: + +```bash +rm /data/truecloud-patch/disabled +bash /data/truecloud-patch/apply.sh +``` + +--- + ## Troubleshooting **Apply log** (check after each reboot or install): diff --git a/install.sh b/install.sh index 20f3245..d3c4310 100755 --- a/install.sh +++ b/install.sh @@ -43,7 +43,8 @@ cp "$REPO_DIR/patch/sitecustomize.py" "$PATCH_DIR/" cp "$REPO_DIR/patch/patch_ui.py" "$PATCH_DIR/" cp "$REPO_DIR/patch/apply.sh" "$PATCH_DIR/" cp "$REPO_DIR/patch/create_task.py" "$PATCH_DIR/" -chmod +x "$PATCH_DIR/apply.sh" "$PATCH_DIR/create_task.py" +cp "$REPO_DIR/recover.sh" "$PATCH_DIR/" +chmod +x "$PATCH_DIR/apply.sh" "$PATCH_DIR/create_task.py" "$PATCH_DIR/recover.sh" echo "Done." echo "" diff --git a/patch/apply.sh b/patch/apply.sh index 7028123..bf6dcb5 100755 --- a/patch/apply.sh +++ b/patch/apply.sh @@ -29,6 +29,15 @@ fi exec >> "$LOG" 2>&1 echo "=== $(date -Iseconds) ===" +# Kill switch: if this file exists, skip all patching and exit cleanly. +# Recovery: touch /data/truecloud-patch/disabled (then reboot or restart middlewared). +if [ -f "$PATCH_DIR/disabled" ]; then + echo "Kill switch active ($PATCH_DIR/disabled exists) — patch not applied." + echo "To re-enable: rm $PATCH_DIR/disabled" + echo "=== done ===" + exit 0 +fi + # ── Helpers ─────────────────────────────────────────────────────────────────── warn() { echo "WARNING: $*"; } diff --git a/patch/sitecustomize.py b/patch/sitecustomize.py index a958cf0..b1f853d 100644 --- a/patch/sitecustomize.py +++ b/patch/sitecustomize.py @@ -183,6 +183,9 @@ _PATCHES = { def _install(): import importlib.util + import os + if os.path.exists("/data/truecloud-patch/disabled"): + return # kill switch: touch /data/truecloud-patch/disabled to bypass this hook if importlib.util.find_spec("middlewared") is None: return # not a middlewared Python process; nothing to do sys.meta_path.append(_Finder()) diff --git a/recover.sh b/recover.sh new file mode 100755 index 0000000..e62623e --- /dev/null +++ b/recover.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# recover.sh — emergency recovery if middlewared won't start after installing truecloud-patch. +# +# Run this from the TrueNAS shell (local console, SSH, or debug shell): +# +# bash /data/truecloud-patch/recover.sh +# +# What it does: +# 1. Creates /data/truecloud-patch/disabled — sitecustomize.py checks for this +# file at startup and skips the import hook entirely, so middlewared starts +# clean without any of our code running. +# 2. Restarts middlewared. +# +# To re-enable the patch after investigating: +# rm /data/truecloud-patch/disabled +# bash /data/truecloud-patch/apply.sh + +PATCH_DIR="/data/truecloud-patch" + +if [ "$(id -u)" -ne 0 ]; then + echo "ERROR: must be run as root." >&2 + exit 1 +fi + +if [ ! -d "$PATCH_DIR" ]; then + echo "ERROR: $PATCH_DIR not found — truecloud-patch may not be installed." >&2 + exit 1 +fi + +touch "$PATCH_DIR/disabled" +echo "Kill switch set: $PATCH_DIR/disabled created." +echo "Restarting middlewared ..." +systemctl restart middlewared +echo "" +echo "middlewared restarted without the truecloud-patch hook." +echo "Your system should be back to normal (Storj-only TrueCloud Backup)." +echo "" +echo "To re-enable the patch once you have investigated:" +echo " rm $PATCH_DIR/disabled" +echo " bash $PATCH_DIR/apply.sh"