feat: capture complete DOS command diagnostics

This commit is contained in:
2026-08-16 16:48:47 +09:00
parent 5d9cd90299
commit dc2285b4d4
3 changed files with 113 additions and 21 deletions
+35 -6
View File
@@ -127,14 +127,43 @@ class Host:
def exec(self, command: str) -> dict[str, object]:
log_event(logging.INFO, "exec start", command=command)
response = self.request("EXEC " + command.encode("ascii", "replace").hex().upper())
fields = response.split(" ", 2)
code = int(fields[1]) if len(fields) > 1 else -1
output = bytes.fromhex(fields[2]).decode("cp437", "replace") if len(fields) > 2 else ""
started = time.monotonic()
with self.agent_lock:
if self.agent is None:
raise RuntimeError("TCPAGENT is not connected")
sock = self.agent
try:
encoded = command.encode("ascii", "replace").hex().upper()
sock.sendall(f"EXEC {encoded}\n".encode("ascii"))
header = self._read_line(sock).decode("ascii", "replace")
fields = header.split()
if len(fields) == 4 and fields[0] == "RESULT":
code, remaining, flags = int(fields[1]), int(fields[2]), int(fields[3])
chunks: list[bytes] = []
while remaining:
chunk = sock.recv(min(65536, remaining))
if not chunk:
raise ConnectionError("TCP agent closed during EXEC result")
chunks.append(chunk)
remaining -= len(chunk)
raw = b"".join(chunks)
elif fields and fields[0] == "OK":
# Compatibility with an installed pre-RESULT agent.
code = int(fields[1]); flags = 1
raw = bytes.fromhex(fields[2]) if len(fields) > 2 else b""
else:
raise RuntimeError("malformed EXEC response: " + header)
except OSError as exc:
if self.agent is sock:
self.agent = None
self.agent_ready.clear()
raise RuntimeError(f"TCPAGENT EXEC failed: {exc}") from exc
output = raw.decode("cp437", "replace")
for line in output.splitlines():
log_event(logging.INFO, "dos output", line=line)
log_event(logging.INFO, "exec finish", exit=code)
return {"exit": code, "output": output}
log_event(logging.INFO, "exec finish", exit=code, bytes=len(raw), flags=flags,
elapsed_ms=round((time.monotonic()-started)*1000))
return {"exit": code, "output": output, "bytes": len(raw), "flags": flags}
def put(self, source: str, destination: str) -> dict[str, object]:
data = Path(source).read_bytes()