- patch/apply.sh: replace sed with Python+env-var for PATCH_DIR
substitution into sitecustomize.py; sed's & and | metacharacters
silently corrupt or truncate the output for paths containing those
chars; Python str.replace has no metacharacter issues; also write to
a tmp file and mv atomically so a failed substitution never leaves
an empty sitecustomize.py at the destination
- recover.sh: fix re-enable hint from $PATCH_DIR/apply.sh to
$PATCH_DIR/patch/apply.sh (apply.sh moved into patch/ subdirectory)
- install.sh + uninstall.sh: match PREINIT hook on comment field
("TrueCloud provider patch (S3/B2)") instead of exact script path;
exact-path match breaks when the repo is moved after install —
uninstall leaves the stale hook registered (fires on every boot),
and reinstall creates a duplicate entry; install.sh now also updates
the script path on re-run so a moved repo self-corrects
152 lines
5.4 KiB
Bash
Executable File
152 lines
5.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# uninstall.sh — remove all traces of truecloud-patch from a TrueNAS box.
|
|
|
|
set -euo pipefail
|
|
|
|
PATCH_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
echo "=== TrueNAS TrueCloud Provider Patch — Uninstall ==="
|
|
echo ""
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "ERROR: must be run as root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v midclt &>/dev/null; then
|
|
echo "ERROR: midclt not found. Run this script on TrueNAS SCALE." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── Remove PREINIT hook ───────────────────────────────────────────────────────
|
|
|
|
echo "Removing PREINIT boot hook ..."
|
|
|
|
IDS=$(midclt call initshutdownscript.query '[]' | \
|
|
python3 -c "
|
|
import sys, json
|
|
for s in json.load(sys.stdin):
|
|
if s.get('comment') == 'TrueCloud provider patch (S3/B2)':
|
|
print(s['id'])
|
|
" 2>/dev/null || true)
|
|
|
|
if [ -n "$IDS" ]; then
|
|
for id in $IDS; do
|
|
if midclt call initshutdownscript.delete "$id" > /dev/null; then
|
|
echo " Removed initshutdownscript id=$id"
|
|
else
|
|
echo " WARNING: could not delete id=$id (already gone?)"
|
|
fi
|
|
done
|
|
else
|
|
echo " No entry found (already removed or never installed)."
|
|
fi
|
|
echo ""
|
|
|
|
# ── Remove sitecustomize.py ───────────────────────────────────────────────────
|
|
|
|
echo "Removing sitecustomize.py ..."
|
|
|
|
# Use the same Python detection logic as apply.sh
|
|
PYTHON="python3"
|
|
if [ -x /usr/bin/middlewared ]; then
|
|
shebang=$(dd if=/usr/bin/middlewared bs=256 count=1 2>/dev/null | head -1 || true)
|
|
if [[ "$shebang" =~ ^'#!'(/[^[:space:]]+python[^[:space:]]*) ]]; then
|
|
PYTHON="${BASH_REMATCH[1]}"
|
|
elif [[ "$shebang" =~ ^'#!/usr/bin/env '(python[^[:space:]]*) ]]; then
|
|
PYTHON=$(command -v "${BASH_REMATCH[1]}" 2>/dev/null || echo "python3")
|
|
fi
|
|
fi
|
|
|
|
if ! "$PYTHON" -c "import middlewared" 2>/dev/null; then
|
|
echo " WARNING: '$PYTHON' cannot import middlewared; falling back to python3"
|
|
PYTHON="python3"
|
|
if ! "$PYTHON" -c "import middlewared" 2>/dev/null; then
|
|
echo " WARNING: 'python3' also cannot import middlewared; sitecustomize.py may be removed from the wrong location."
|
|
fi
|
|
fi
|
|
|
|
SITE_PKG=$("$PYTHON" -c "import site; print(site.getsitepackages()[0])" 2>/dev/null || true)
|
|
|
|
if [ -n "$SITE_PKG" ] && [ -f "$SITE_PKG/sitecustomize.py" ]; then
|
|
if grep -q "truecloud-patch" "$SITE_PKG/sitecustomize.py" 2>/dev/null; then
|
|
if [ -f "$SITE_PKG/sitecustomize.py.pre-truecloud-patch" ]; then
|
|
# mv atomically overwrites our file with the vendor original —
|
|
# safer than rm-then-mv if /usr is transiently read-only.
|
|
mv "$SITE_PKG/sitecustomize.py.pre-truecloud-patch" \
|
|
"$SITE_PKG/sitecustomize.py"
|
|
echo " Restored previous sitecustomize.py"
|
|
else
|
|
rm "$SITE_PKG/sitecustomize.py"
|
|
echo " Removed $SITE_PKG/sitecustomize.py"
|
|
fi
|
|
else
|
|
echo " $SITE_PKG/sitecustomize.py is not ours; leaving it alone."
|
|
fi
|
|
else
|
|
echo " Not found (already removed or install didn't place it here)."
|
|
fi
|
|
|
|
# Handle orphaned backup when sitecustomize.py was removed (e.g. by a TrueNAS
|
|
# update) but the .pre-truecloud-patch file survived in the same directory.
|
|
if [ -n "$SITE_PKG" ] && [ ! -f "$SITE_PKG/sitecustomize.py" ] && \
|
|
[ -f "$SITE_PKG/sitecustomize.py.pre-truecloud-patch" ]; then
|
|
mv "$SITE_PKG/sitecustomize.py.pre-truecloud-patch" \
|
|
"$SITE_PKG/sitecustomize.py"
|
|
echo " Restored orphaned sitecustomize.py backup"
|
|
fi
|
|
echo ""
|
|
|
|
# ── Restore UI bundle ─────────────────────────────────────────────────────────
|
|
|
|
echo "Restoring UI bundle backup ..."
|
|
|
|
RESTORED=0
|
|
_restore_failed=0
|
|
while IFS= read -r backup; do
|
|
original="${backup%.pre-truecloud-patch}"
|
|
if mv "$backup" "$original"; then
|
|
echo " Restored: $original"
|
|
RESTORED=1
|
|
else
|
|
echo " WARNING: Could not restore $original — backup left at $backup"
|
|
_restore_failed=1
|
|
fi
|
|
# Keep these paths in sync with WEBUI_CANDIDATES in patch/patch_ui.py
|
|
done < <(find /usr/share/truenas /usr/share/truenas-ui /var/www/truenas \
|
|
-name "*.js.pre-truecloud-patch" 2>/dev/null)
|
|
|
|
if [ "$_restore_failed" -eq 1 ]; then
|
|
echo ""
|
|
echo "ERROR: One or more UI bundle backups could not be restored." >&2
|
|
echo " $PATCH_DIR has been left intact (recover.sh and patch files are safe)." >&2
|
|
echo " Restore the backup(s) manually, then re-run uninstall.sh." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$RESTORED" -eq 0 ]; then
|
|
echo " No backup files found."
|
|
echo " The UI patch will be undone automatically by the next TrueNAS update."
|
|
fi
|
|
echo ""
|
|
|
|
# ── Remove patch directory ────────────────────────────────────────────────────
|
|
|
|
if [ -d "$PATCH_DIR" ]; then
|
|
rm -rf "$PATCH_DIR"
|
|
echo "Removed $PATCH_DIR"
|
|
fi
|
|
echo ""
|
|
|
|
echo "Restarting middlewared ..."
|
|
if systemctl restart middlewared; then
|
|
echo ""
|
|
echo "Uninstall complete. Refresh your browser to see the restored UI."
|
|
else
|
|
echo ""
|
|
echo "WARNING: middlewared did not start cleanly after uninstall."
|
|
echo "Check the system log for details:"
|
|
echo " journalctl -u middlewared -n 50"
|
|
exit 1
|
|
fi
|