IQ.Pilot Prebuilt Release @ 27f668a
This commit is contained in:
45
iqpilot/system/loggerd/crash_recovery.py
Normal file
45
iqpilot/system/loggerd/crash_recovery.py
Normal file
@@ -0,0 +1,45 @@
|
||||
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
|
||||
Reference in New Issue
Block a user