Repair ClamAV runtime PID path
This commit is contained in:
@@ -59,6 +59,7 @@ class ScannerConfigurationTest(unittest.TestCase):
|
||||
original = (
|
||||
"# Distribution configuration\n"
|
||||
"LocalSocket /run/clamav/clamd.sock\n"
|
||||
"PidFile /run/clamd.pid\n"
|
||||
"TCPAddr 0.0.0.0\n"
|
||||
"TCPSocket 9999\n"
|
||||
"TCPAddr 192.0.2.2\n"
|
||||
@@ -66,6 +67,7 @@ class ScannerConfigurationTest(unittest.TestCase):
|
||||
)
|
||||
edited = edit_clamd_configuration(original)
|
||||
self.assertIn("LocalSocket /run/clamav/clamd.sock", edited)
|
||||
self.assertIn("PidFile /run/clamav/clamd.pid", edited)
|
||||
self.assertIn("LogTime yes", edited)
|
||||
self.assertIn("TCPAddr 127.0.0.1", edited)
|
||||
self.assertIn("TCPSocket 3310", edited)
|
||||
|
||||
@@ -30,7 +30,7 @@ import shutil
|
||||
import subprocess
|
||||
import time
|
||||
from dataclasses import dataclass, replace
|
||||
from pathlib import Path
|
||||
from pathlib import Path, PurePosixPath
|
||||
from typing import Callable, Mapping, Sequence
|
||||
|
||||
from .probes import ProbeResult, probe_clamav, probe_spamd
|
||||
@@ -230,9 +230,46 @@ def _read_configuration(path: Path) -> str:
|
||||
from error
|
||||
|
||||
|
||||
def _clamd_runtime_pid_file(content: str) -> str | None:
|
||||
"""Move a root-level runtime PID beside clamd's private socket.
|
||||
|
||||
Several distribution configurations still use ``/run/clamd.pid`` while
|
||||
telling clamd to drop privileges. The daemon can create that file while
|
||||
privileged, but cannot remove it during a clean shutdown. Reuse the
|
||||
distribution's existing LocalSocket directory instead of hard-coding a
|
||||
distro-specific runtime directory.
|
||||
"""
|
||||
values: dict[str, str] = {}
|
||||
for line in content.splitlines():
|
||||
if not line.strip() or line.lstrip().startswith("#"):
|
||||
continue
|
||||
try:
|
||||
fields = shlex.split(line, comments=True, posix=True)
|
||||
except ValueError:
|
||||
continue
|
||||
if len(fields) >= 2 and fields[0].lower() in {"localsocket", "pidfile"}:
|
||||
values.setdefault(fields[0].lower(), fields[1])
|
||||
|
||||
if "localsocket" not in values or "pidfile" not in values:
|
||||
return None
|
||||
socket = PurePosixPath(values["localsocket"])
|
||||
pid = PurePosixPath(values["pidfile"])
|
||||
if not socket.is_absolute() or not pid.is_absolute():
|
||||
return None
|
||||
runtime_roots = {PurePosixPath("/run"), PurePosixPath("/var/run")}
|
||||
if pid.parent not in runtime_roots or socket.parent in runtime_roots:
|
||||
return None
|
||||
if not any(root in socket.parents for root in runtime_roots):
|
||||
return None
|
||||
return str(socket.parent / "clamd.pid")
|
||||
|
||||
|
||||
def edit_clamd_configuration(content: str) -> str:
|
||||
"""Return clamd configuration with one safe active value per setting."""
|
||||
desired = dict(CLAMD_SETTINGS)
|
||||
runtime_pid_file = _clamd_runtime_pid_file(content)
|
||||
if runtime_pid_file is not None:
|
||||
desired["PidFile"] = runtime_pid_file
|
||||
canonical = {name.lower(): name for name in desired}
|
||||
seen: set[str] = set()
|
||||
output: list[str] = []
|
||||
|
||||
Reference in New Issue
Block a user