Files
pyMC_Repeater/repeater/service_utils.py
2026-04-23 11:05:59 -04:00

111 lines
4.2 KiB
Python

"""
Service management utilities for pyMC Repeater.
Provides functions for service control operations like restart.
"""
import logging
import os
import subprocess
from typing import Tuple
logger = logging.getLogger("ServiceUtils")
INIT_SCRIPT = "/etc/init.d/S80pymc-repeater"
def is_buildroot() -> bool:
if os.path.exists("/etc/pymc-image-build-id"):
return True
if os.path.exists("/etc/os-release"):
try:
with open("/etc/os-release", "r", encoding="utf-8") as handle:
return any(line.strip() == "ID=buildroot" for line in handle)
except OSError:
return False
return False
def restart_service() -> Tuple[bool, str]:
"""
Restart the pymc-repeater service.
On Buildroot/Luckfox, use the shipped init script directly.
On systemd hosts, try polkit-based restart first (plain systemctl), then
fall back to sudo-based restart (requires sudoers.d rule installed by
manage.sh).
Returns:
Tuple[bool, str]: (success, message)
"""
if is_buildroot():
if not os.path.exists(INIT_SCRIPT):
logger.error("Buildroot init script not found: %s", INIT_SCRIPT)
return False, f"init script not found: {INIT_SCRIPT}"
try:
subprocess.Popen(
["/bin/sh", "-c", f"sleep 1; exec {INIT_SCRIPT} restart >/dev/null 2>&1"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
stdin=subprocess.DEVNULL,
start_new_session=True,
)
logger.info("Service restart scheduled via Buildroot init script")
return True, "Service restart initiated"
except Exception as exc:
logger.error(f"Buildroot restart failed: {exc}")
return False, f"Restart failed: {exc}"
# Try polkit-based restart first (works on bare metal / VMs with polkit running)
try:
result = subprocess.run(
["systemctl", "restart", "pymc-repeater"], capture_output=True, text=True, timeout=5
)
if result.returncode == 0:
logger.info("Service restart via polkit succeeded")
return True, "Service restart initiated"
stderr = result.stderr or ""
if "Access denied" in stderr or "authorization" in stderr.lower():
logger.info("Polkit denied restart, trying sudo fallback...")
else:
# Some other error, still try sudo
logger.warning(f"systemctl restart failed ({result.returncode}): {stderr.strip()}")
except subprocess.TimeoutExpired:
# Timeout likely means it's restarting - that's success
logger.warning("Service restart command timed out (service may be restarting)")
return True, "Service restart initiated (timeout - likely restarting)"
except FileNotFoundError:
logger.error("systemctl not found")
return False, "systemctl not available"
except Exception as e:
logger.warning(f"Polkit restart attempt failed: {e}")
# Fallback: use sudo (requires /etc/sudoers.d/pymc-repeater rule)
try:
result = subprocess.run(
['sudo', '--non-interactive', 'systemctl', 'restart', 'pymc-repeater'],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
logger.info("Service restart via sudo succeeded")
return True, "Service restart initiated"
else:
error_msg = result.stderr or "Unknown error"
logger.error(f"Service restart via sudo failed: {error_msg}")
return False, f"Restart failed: {error_msg}"
except subprocess.TimeoutExpired:
logger.warning("Sudo restart timed out (service likely restarting)")
return True, "Service restart initiated (timeout - likely restarting)"
except FileNotFoundError:
logger.error("sudo not found - cannot restart service")
return False, "Neither polkit nor sudo available for service restart"
except Exception as e:
logger.error(f"Error executing sudo restart: {e}")
return False, f"Restart command failed: {str(e)}"