From cc3d91a91b385b26cb7e99bcc8481774bb49b500 Mon Sep 17 00:00:00 2001 From: malmert Date: Wed, 28 Jan 2026 19:57:17 +0100 Subject: [PATCH] fix status 5 --- backend/src/api/packet_scripting_api.py | 106 ++++++++++++++---------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/backend/src/api/packet_scripting_api.py b/backend/src/api/packet_scripting_api.py index 5f62b8c..2409dfb 100644 --- a/backend/src/api/packet_scripting_api.py +++ b/backend/src/api/packet_scripting_api.py @@ -121,80 +121,96 @@ def get_unit_fragment_path(service_name: str) -> Optional[str]: logger.exception("systemctl show FragmentPath failed for %s", service_name) return None -def parse_unit_execstart(service_name: str) -> Optional[Dict]: +def parse_unit_execstart(service_name: str) -> Dict: """ - Query systemd for ExecStart and parse the script name and qnum. - Handles: - - plain ExecStart strings - - systemd structured blobs like: - { path=... ; argv[]=/usr/bin/python /srv/fw-scripts/foo.py 5 ; ... } - - argv[] values containing spaces/newlines and quoted entries - Returns dict with keys: service, exec_start, name, script_path, qnum, extra + Parse ExecStart using systemctl --no-pager show (canonical). + Handles structured ExecStart blobs with argv[] entries. """ - unit = _systemctl_unit_name(service_name) + unit = service_name if service_name.endswith(".service") else service_name + ".service" + try: p = subprocess.run( - ["systemctl", "--no-pager","show", "-p", "ExecStart", "--value", unit], - capture_output=True, text=True, check=False, timeout=2 + ["systemctl", "--no-pager", "show", "-p", "ExecStart", "--value", unit], + capture_output=True, + text=True, + check=False, + timeout=3, ) - exec_start_raw = (p.stdout or "").strip() + raw = (p.stdout or "").strip() except Exception: logger.exception("systemctl show ExecStart failed for %s", service_name) - return {"service": service_name, "exec_start": None, "name": None, "script_path": None, "qnum": None, "extra": None} + return { + "service": service_name, + "exec_start": None, + "name": None, + "script_path": None, + "qnum": None, + "extra": None, + } - if not exec_start_raw: - return {"service": service_name, "exec_start": None, "name": None, "script_path": None, "qnum": None, "extra": None} + if not raw: + return { + "service": service_name, + "exec_start": None, + "name": None, + "script_path": None, + "qnum": None, + "extra": None, + } - exec_start = exec_start_raw + exec_start = raw - # If structured form with argv[] entries, extract and reconstruct the argv commandline. - if "argv[]=" in exec_start_raw: - # Capture argv[]=... entries up to the next semicolon (allow newlines). - # Accept quoted arguments too: "..." or '...' - argv_matches = re.findall(r'argv\[\]=(("(?:\\.|[^"])*"|\'(?:\\.|[^\'])*\'|[^;]*?))(?:\s*;|\s*$)', exec_start_raw, flags=re.DOTALL) - argv_parts = [] - for m in argv_matches: - val = m[0] - if not val: - continue - v = val.strip() - # strip surrounding quotes if present - if (v.startswith('"') and v.endswith('"')) or (v.startswith("'") and v.endswith("'")): - v = v[1:-1] - argv_parts.append(v) + # Handle structured ExecStart: { path=... ; argv[]=... ; ... } + if "argv[]=" in raw: + # extract argv[] entries safely, across spaces/newlines + argv_entries = re.findall(r'argv\[\]=([^;]+)', raw, flags=re.DOTALL) + argv_parts = [a.strip() for a in argv_entries if a.strip()] if argv_parts: - # join argv entries with space to form a single commandline exec_start = " ".join(argv_parts) - else: - # fallback: remove braces and keep raw - exec_start = exec_start_raw - # Now try to find the script path under /srv/fw-scripts - m = re.search(r'(/[^ \t\n\r"]*/srv/fw-scripts/(?P[A-Za-z0-9_.-]+)\.py)\b', exec_start) + # Extract script path + m = re.search( + r'(/[^ \t\n\r"]*/srv/fw-scripts/(?P[A-Za-z0-9_.-]+)\.py)\b', + exec_start, + ) if not m: - # return raw exec_start but no parsed metadata - return {"service": service_name, "exec_start": exec_start, "name": None, "script_path": None, "qnum": None, "extra": None} + return { + "service": service_name, + "exec_start": exec_start, + "name": None, + "script_path": None, + "qnum": None, + "extra": None, + } script_path = m.group(1) name = m.group("name") - # Find integer qnum after the script path (first integer token) + # Extract queue number (first integer after script path) after = exec_start[m.end():].strip() qnum = None extra = None + if after: - toks = after.split() - for i, t in enumerate(toks): + tokens = after.split() + for i, t in enumerate(tokens): try: val = int(t) if 0 <= val <= 65535: qnum = val - extra = " ".join(toks[i+1:]) if len(toks) > i+1 else "" + extra = " ".join(tokens[i + 1 :]) if i + 1 < len(tokens) else "" break - except Exception: + except ValueError: continue - return {"service": service_name, "exec_start": exec_start, "name": name, "script_path": script_path, "qnum": qnum, "extra": extra} + return { + "service": service_name, + "exec_start": exec_start, + "name": name, + "script_path": script_path, + "qnum": qnum, + "extra": extra, + } def is_unit_active(service_name: str) -> bool: