mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 00:53:45 +08:00
50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
"""Shared plumbing for the root workers that unprivileged daemons lease over a pipe.
|
|
|
|
The daemon starts the worker with ``spawn``. EOF on the worker's stdin, a missed heartbeat or SIGTERM ends the
|
|
lease, and the worker then removes only what it created (interfaces it marked with its own alias).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import fcntl
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import threading
|
|
from pathlib import Path
|
|
|
|
|
|
def spawn(unit: str, module: str, popen=subprocess.Popen):
|
|
from openpilot.common.basedir import BASEDIR
|
|
return popen(['sudo', '-n', 'systemd-run', '--quiet', '--pipe', '--wait', '--collect', f'--unit={unit}',
|
|
'--property=TimeoutStopSec=8', '--property=KillMode=control-group', '--working-directory=' + str(BASEDIR),
|
|
sys.executable, '-u', '-m', module], cwd=BASEDIR,
|
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, close_fds=True)
|
|
|
|
|
|
def owned(interface: str, alias: str) -> bool:
|
|
try:
|
|
return Path(f'/sys/class/net/{interface}/ifalias').read_text().strip() == alias
|
|
except FileNotFoundError:
|
|
return False
|
|
|
|
|
|
def claim(runtime: Path, name: str) -> int:
|
|
"""Root check, a private runtime directory and its lock; returns the lock's file descriptor."""
|
|
if os.geteuid() != 0:
|
|
raise RuntimeError(f'{name} requires network administration privileges')
|
|
os.umask(0o077)
|
|
runtime.mkdir(mode=0o700, exist_ok=True)
|
|
if runtime.is_symlink() or runtime.stat().st_uid != 0:
|
|
raise RuntimeError(f'Unsafe {name} runtime directory')
|
|
fd = os.open(runtime / 'lock', os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600)
|
|
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
return fd
|
|
|
|
|
|
def stop_event() -> threading.Event:
|
|
stop = threading.Event()
|
|
signal.signal(signal.SIGTERM, lambda *_: stop.set())
|
|
signal.signal(signal.SIGINT, lambda *_: stop.set())
|
|
return stop
|