Fix kill switch not cleared on reinstall; guard midclt delete; tighten sitecustomize imports
install.sh: running install.sh after a recover.sh left /data/truecloud-patch/disabled in place, so apply.sh silently skipped all patching and middlewared restarted without the patch. Clear the kill switch file before running apply.sh. uninstall.sh: midclt initshutdownscript.delete was unguarded under set -euo pipefail, so a delete failure (already-removed entry, transient API error) aborted the script before sitecustomize.py was cleaned up or /data/truecloud-patch/ was removed. Now guarded with an if/else that warns and continues. sitecustomize.py: move importlib.machinery/.util imports inside the if block in find_spec so they only execute when intercepting our two target modules, not on every module import across the whole process. In _install(), import os before importlib.util so the kill switch check (cheap) runs before the importlib import (slightly heavier on first use). Remove the unused orig variable in _patch_restic. patch_ui.py: add explicit encoding="utf-8" to both open() calls. errors="replace" on read so malformed bytes in a bundle don't silently skip a candidate file.
This commit is contained in:
@@ -73,6 +73,14 @@ else
|
|||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# ── Clear kill switch if set ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if [ -f "$PATCH_DIR/disabled" ]; then
|
||||||
|
rm "$PATCH_DIR/disabled"
|
||||||
|
echo "Removed kill switch ($PATCH_DIR/disabled) left from a previous recovery."
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Apply now ─────────────────────────────────────────────────────────────────
|
# ── Apply now ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
echo "Applying patches ..."
|
echo "Applying patches ..."
|
||||||
|
|||||||
+2
-2
@@ -60,7 +60,7 @@ def find_bundle(webui):
|
|||||||
continue
|
continue
|
||||||
path = os.path.join(root, name)
|
path = os.path.join(root, name)
|
||||||
try:
|
try:
|
||||||
with open(path) as fh:
|
with open(path, encoding="utf-8", errors="replace") as fh:
|
||||||
content = fh.read()
|
content = fh.read()
|
||||||
if FIND.search(content):
|
if FIND.search(content):
|
||||||
matches.append((path, content))
|
matches.append((path, content))
|
||||||
@@ -112,7 +112,7 @@ def main():
|
|||||||
patched, count = FIND.subn(REPLACE, content)
|
patched, count = FIND.subn(REPLACE, content)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(path, "w") as fh:
|
with open(path, "w", encoding="utf-8") as fh:
|
||||||
fh.write(patched)
|
fh.write(patched)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
print(f"[truecloud-patch] ERROR: Could not write {path}: {exc}")
|
print(f"[truecloud-patch] ERROR: Could not write {path}: {exc}")
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ class _Finder:
|
|||||||
self._done = set() # modules already patched
|
self._done = set() # modules already patched
|
||||||
|
|
||||||
def find_spec(self, fullname, path, target=None): # noqa: ARG002
|
def find_spec(self, fullname, path, target=None): # noqa: ARG002
|
||||||
import importlib.machinery
|
|
||||||
import importlib.util
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
fullname in self._targets
|
fullname in self._targets
|
||||||
and fullname not in self._done
|
and fullname not in self._done
|
||||||
and fullname not in self._loading
|
and fullname not in self._loading
|
||||||
):
|
):
|
||||||
|
import importlib.machinery
|
||||||
|
import importlib.util
|
||||||
|
|
||||||
# Find the real file spec HERE, before Python adds the module to
|
# Find the real file spec HERE, before Python adds the module to
|
||||||
# sys.modules. If we deferred this to exec_module, find_spec would
|
# sys.modules. If we deferred this to exec_module, find_spec would
|
||||||
# short-circuit via sys.modules[fullname].__spec__ (our own spec) and
|
# short-circuit via sys.modules[fullname].__spec__ (our own spec) and
|
||||||
@@ -135,8 +135,7 @@ def _patch_b2(module):
|
|||||||
|
|
||||||
|
|
||||||
def _patch_restic(module):
|
def _patch_restic(module):
|
||||||
orig = module.get_restic_config
|
if getattr(module.get_restic_config, "_truecloud_patched", False):
|
||||||
if getattr(orig, "_truecloud_patched", False):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# ResticConfig is safe to capture now (it's a dataclass defined in the module).
|
# ResticConfig is safe to capture now (it's a dataclass defined in the module).
|
||||||
@@ -182,10 +181,10 @@ _PATCHES = {
|
|||||||
# ── Entry point ───────────────────────────────────────────────────────────────
|
# ── Entry point ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def _install():
|
def _install():
|
||||||
import importlib.util
|
|
||||||
import os
|
import os
|
||||||
if os.path.exists("/data/truecloud-patch/disabled"):
|
if os.path.exists("/data/truecloud-patch/disabled"):
|
||||||
return # kill switch: touch /data/truecloud-patch/disabled to bypass this hook
|
return # kill switch: touch /data/truecloud-patch/disabled to bypass this hook
|
||||||
|
import importlib.util
|
||||||
if importlib.util.find_spec("middlewared") is None:
|
if importlib.util.find_spec("middlewared") is None:
|
||||||
return # not a middlewared Python process; nothing to do
|
return # not a middlewared Python process; nothing to do
|
||||||
sys.meta_path.append(_Finder())
|
sys.meta_path.append(_Finder())
|
||||||
|
|||||||
+4
-1
@@ -32,8 +32,11 @@ for s in json.load(sys.stdin):
|
|||||||
|
|
||||||
if [ -n "$IDS" ]; then
|
if [ -n "$IDS" ]; then
|
||||||
for id in $IDS; do
|
for id in $IDS; do
|
||||||
midclt call initshutdownscript.delete "$id" > /dev/null
|
if midclt call initshutdownscript.delete "$id" > /dev/null; then
|
||||||
echo " Removed initshutdownscript id=$id"
|
echo " Removed initshutdownscript id=$id"
|
||||||
|
else
|
||||||
|
echo " WARNING: could not delete id=$id (already gone?)"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
echo " No entry found (already removed or never installed)."
|
echo " No entry found (already removed or never installed)."
|
||||||
|
|||||||
Reference in New Issue
Block a user