DOS 콘솔에서 직접 보기 위한 네 가지 수정. 1. 컬러. Open Watcom의 conio.h에는 textattr()이 없고(cprintf/cputs/getch만 제공) 이 FreeDOS 콘솔은 ANSI 이스케이프도 해석하지 않는다. 그래서 cprintf가 줄을 배치하게 두고 -- 스크롤을 알아서 처리한다 -- 방금 쓴 셀의 VGA 속성 바이트만 다시 칠한다. 커서가 그 줄 다음 행의 0열에 있다는 점을 이용해 스크롤을 직접 추적하지 않고 대상 셀을 찾는다. 줄바꿈된 긴 줄도 처리한다. 2. GET, HASH, LIST, READ, WRITE, QUIT, 미지원 명령을 로깅한다. 이전에는 EXEC과 PUT만 보였다. PING은 wait-ready가 초당 두 번 폴링하므로 제외한다. LIST는 잘림 여부를, PUT은 short write를 구분해 남긴다. 3. put_path가 채워지기만 하고 쓰이지 않아 PUT 완료 줄에 경로가 없었다. 완료 경로가 둘(길이 0, 본문 수신 완료)이라 put_finished()로 합쳤다. 4. 틱->초 변환이 1.1% 빨랐다. BIOS 틱은 18.2065Hz이므로 delta/18이 아니라 delta*549/100 (하루치 틱에도 32비트를 넘지 않는다) 을 쓴다. REBUILD.BAT을 추가한다. BUILD.BAT은 현재 디렉터리에서 wmake만 실행하는데 호스트가 exec으로 부를 때의 시작 디렉터리가 거기가 아니다. QEMU FreeDOS에서 Open Watcom C++16으로 빌드하고(no warnings, -we 활성) 콘솔 스크린샷으로 색상, 줄바꿈 색칠, 명령별 로그를 확인했다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012PQm6oAvWX4Lp3iSN5AHGT
FreeDOS resident TCP agent
TCPAGENT.EXE is a foreground resident automation process. It uses the mTCP
packet-driver stack and maintains an outbound connection to the QEMU host at
10.0.2.2:5558.
The Windows-only Python ferro-vm daemon owns that listener. It logs metadata
and decoded command output to .qemu/ferro-vm.log; it does not expose an
observer/controller TCP port or emit binary payloads to the log. Local host
control uses a Windows named pipe.
Build in FreeDOS
- Obtain the GPLv3 mTCP source tree (tested with the jhpyle/mTCP 2022 fork).
- Copy this directory to
MTCP\APPS\TCPAGENTinside that tree. - Set
WATCOMfor Open Watcom and runBUILD.BAT. - Run
INSTALL.BAT; it installs the executable and adds startup lines after the existing packet-driver setup inC:\FDAUTO.BAT.
The build uses mTCP's compact memory model and Open Watcom C++16. The agent is therefore distributed under GPLv3 when linked with mTCP.
Protocol
PING, READ, WRITE, and LIST use text commands. EXEC captures both
stdout and stderr at the DOS handle level and returns an untruncated raw body:
EXEC <hex command>\n->RESULT <exit> <length> <flags>\r\n<raw bytes>
Fast transfer commands are:
PUT <hex DOS path> <byte length>\n<raw bytes>->OK\r\nGET <hex DOS path>\n->DATA <length>\r\n<raw bytes>HASH <hex DOS path>\n->STAT <length> <FNV1A32>\r\n
The host invokes them through:
uv run ferro-vm put host-file 'C:\DOS\FILE'
uv run ferro-vm get 'C:\DOS\FILE' host-file
Agent-side logging
The foreground agent prints one timestamped line per event on the VGA console
and keeps the same text in C:\TCPAGENT.LOG, rotating files larger than 256 KiB
to C:\TCPAGENT.OLD. Payloads and command output are never written to that
metadata log.
Every command is logged with a request line and a result line carrying byte
counts and elapsed time — EXEC, PUT, GET, HASH, LIST, READ, and
WRITE. PING is deliberately excluded because wait-ready polls it twice a
second. Connection events (connecting, connected, connect failed; retry N,
link lost) are logged too; those are invisible to the host by definition,
since they happen when the socket is down.
Lines are colored by writing VGA attribute bytes after cprintf lays out the
line: gray timestamps, cyan requests, yellow EXEC command text, green success,
red failure. Open Watcom's DOS conio.h has no textattr(), and ANSI escapes
are not interpreted on this FreeDOS console, so neither of the usual routes
works. Elapsed times come from the BIOS tick counter at 18.2065 Hz (~55 ms
resolution).
Note that mTCP is not driven while system() runs a child, so a DOS command
lasting tens of seconds can drop the TCP connection. The agent logs link lost
and reconnects on its own, but the host loses that command's result.
Rebuilding inside the VM
REBUILD.BAT compiles and installs the agent in a single exec. BUILD.BAT
only runs wmake in the current directory, which is not where a host-driven
ferro-vm exec starts.
uv run ferro-vm put tools/tcpagent/tcpagent.cpp 'C:\MTSRC\MTCP\APPS\TCPAGENT\TCPAGENT.CPP'
uv run ferro-vm put tools/tcpagent/REBUILD.BAT 'C:\REBUILD.BAT'
uv run ferro-vm exec 'C:\REBUILD.BAT'
uv run ferro-vm reset
The reset is required: the running agent holds the old image in memory, and
C:\FDAUTO.BAT starts it at boot.