Files
IQ.Pilot/iqpilot/system/loggerd/crash_recovery.py
2026-09-02 15:07:09 -05:00

46 lines
1.5 KiB
Python

import os
from iqpilot.common.swaglog import cloudlog
from iqpilot.system.hardware.hw import Paths
PRESERVE_ATTR_NAME = b"user.preserve"
PRESERVE_ATTR_VALUE = b"1"
def recover_unclean_segments(log_root: str | None = None) -> list[str]:
# Segments with leftover .lock files are from a loggerd that never closed
# cleanly (power cut, crash). The video/log data in them is valid up to the
# last durable sync. Clear the stale locks so the deleter can manage them
# again, and preserve them: footage from an unclean shutdown is exactly the
# footage a dashcam must not throw away.
root = log_root if log_root is not None else Paths.log_root()
recovered = []
try:
dirs = os.listdir(root)
except OSError:
return recovered
for d in dirs:
seg_path = os.path.join(root, d)
if not os.path.isdir(seg_path):
continue
try:
locks = [f for f in os.listdir(seg_path) if f.endswith(".lock")]
if not locks:
continue
for lock in locks:
os.unlink(os.path.join(seg_path, lock))
setxattr = getattr(os, "setxattr", None) # not available on darwin
if setxattr is not None:
try:
setxattr(seg_path, PRESERVE_ATTR_NAME, PRESERVE_ATTR_VALUE)
except OSError:
pass
recovered.append(d)
except OSError:
cloudlog.exception(f"crash_recovery: failed to recover {seg_path}")
if recovered:
cloudlog.event("crash_recovery.recovered_unclean_segments", segments=sorted(recovered), error=True)
return recovered