mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 09:03:46 +08:00
80fbb4f6db
Register vehicle controls, planner modes, UI actions and Galaxy services after their providers exist. Wire the shared runtime entrypoints and cover their combined behavior. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Kacper Rączy <gfw.kra@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: haraschax <6804392+haraschax@users.noreply.github.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
102 lines
3.1 KiB
Python
102 lines
3.1 KiB
Python
"""The local crash collector and report cleanup share one retained directory lock."""
|
|
from contextlib import contextmanager
|
|
import errno
|
|
import fcntl
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import stat
|
|
import time
|
|
|
|
|
|
DIR_FLAGS = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
|
|
|
|
|
|
def open_directory(root: Path, *, create=False):
|
|
if not root.is_absolute() or '..' in root.parts:
|
|
raise OSError(errno.EINVAL, 'Invalid crash directory')
|
|
directory = os.open('/', DIR_FLAGS)
|
|
try:
|
|
for part in root.parts[1:]:
|
|
if create:
|
|
try:
|
|
os.mkdir(part, 0o755, dir_fd=directory)
|
|
except FileExistsError:
|
|
pass
|
|
child = os.open(part, DIR_FLAGS, dir_fd=directory)
|
|
os.close(directory)
|
|
directory = child
|
|
return directory
|
|
except BaseException:
|
|
os.close(directory)
|
|
raise
|
|
|
|
|
|
def acquire_lock(directory, *, exclusive=True, timeout=1.0):
|
|
lock = os.open('.lock', os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW | os.O_NONBLOCK, 0o600, dir_fd=directory)
|
|
try:
|
|
opened = os.fstat(lock)
|
|
if not stat.S_ISREG(opened.st_mode) or opened.st_nlink != 1 or opened.st_uid != os.geteuid() or opened.st_mode & 0o077:
|
|
raise OSError(errno.EPERM, 'Invalid crash storage lock')
|
|
deadline = time.monotonic() + timeout
|
|
while True:
|
|
try:
|
|
fcntl.flock(lock, (fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH) | fcntl.LOCK_NB)
|
|
break
|
|
except BlockingIOError:
|
|
remaining = deadline - time.monotonic()
|
|
if remaining <= 0:
|
|
raise
|
|
time.sleep(min(.01, remaining))
|
|
current = os.stat('.lock', dir_fd=directory, follow_symlinks=False)
|
|
if (opened.st_dev, opened.st_ino) != (current.st_dev, current.st_ino):
|
|
raise OSError(errno.ESTALE, 'Crash storage lock changed')
|
|
return lock
|
|
except BaseException:
|
|
os.close(lock)
|
|
raise
|
|
|
|
|
|
@contextmanager
|
|
def writer(root: Path):
|
|
directory = open_directory(root, create=True)
|
|
lock = None
|
|
try:
|
|
lock = acquire_lock(directory)
|
|
yield directory
|
|
os.fsync(directory)
|
|
finally:
|
|
if lock is not None:
|
|
os.close(lock)
|
|
os.close(directory)
|
|
|
|
|
|
def _output(directory, name):
|
|
if name in ('', '.', '..', '.lock') or '/' in name or '\\' in name or '\0' in name:
|
|
raise ValueError('Invalid crash report name')
|
|
fd = os.open(name, os.O_WRONLY | os.O_CREAT | os.O_NOFOLLOW | os.O_NONBLOCK, 0o666, dir_fd=directory)
|
|
try:
|
|
info = os.fstat(fd)
|
|
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_uid != os.geteuid():
|
|
raise OSError(errno.EPERM, 'Invalid crash report file')
|
|
os.ftruncate(fd, 0)
|
|
return fd
|
|
except BaseException:
|
|
os.close(fd)
|
|
raise
|
|
|
|
|
|
def write_text(directory, name, text):
|
|
with os.fdopen(_output(directory, name), 'w', encoding='utf-8') as output:
|
|
output.write(text)
|
|
output.flush()
|
|
os.fsync(output.fileno())
|
|
|
|
|
|
def copy_report(directory, name, source):
|
|
with open(source, 'rb') as input_file, os.fdopen(_output(directory, name), 'wb') as output:
|
|
shutil.copyfileobj(input_file, output, length=1024 * 1024)
|
|
output.flush()
|
|
os.fchmod(output.fileno(), stat.S_IMODE(os.fstat(input_file.fileno()).st_mode))
|
|
os.fsync(output.fileno())
|