Skip to content

vms-98c: lib$spawn spawns a REAL DCL subprocess (exec-drive prereq A) - #451

Merged
baron-3dl merged 2 commits into
mainfrom
vms-98c-lib-spawn-dcl
Aug 13, 2026
Merged

baron-3dl merged 2 commits into
mainfrom
vms-98c-lib-spawn-dcl

Conversation

@baron-3dl

Copy link
Copy Markdown
Contributor

What

lib$spawn was a Rule-9 / INV-6 facade: it fork+exec'd /bin/sh -c <command> — the Unix Bourne shell, not a DCL command interpreter — and returned SS$_NORMAL for a SHOW TIME that no DCL ever saw. This replaces it with a genuine DCL subprocess.

Prereq A of the vms-ec70 self-host spine #4 exec-drive (making MMK.EXE actually drive compile/link).

How the DCL child really runs the command

  • Resolve SYS$SYSTEM:DCL.EXE through the VMS filespec translator (vmsfs_to_linux_path) — the same CLI image JOB_CONTROL and PROVISION exec to hand a user a session, so a redefined SYS$SYSTEM is honored.
  • fork(), redirect SYS$INPUT/SYS$OUTPUT, then execl(dcl, "DCL", "-c", command) — DCL executes the one command and exits (dcl_main.c -c mode). No command → interactive DCL on SYS$INPUT.
  • CLI$M_NOWAIT honored (create-and-return); wait mode HIBERNATEs on the child and returns its completion status.

Honest boundary (Rule 9 / INV-6)

If the CLI image cannot be resolved or is not an executable regular file, lib$spawn returns an authentic SS$_NOSUCHFILE and runs nothing — no /bin/sh fallback, never a fake success for a command that did not run. A real child image needs no /dev/vms.

Test (tests/libvms/test_lib_spawn_dcl.c)

Redirects SYS$SYSTEM to a private temp root, stages the build's own DCL image there as DCL.EXE, and drives the real lib$spawn resolve+fork+exec path (no monkeypatch, hermetic, no shared /vms, no /dev/vms):

  1. Observable effect from a real DCL childlib$spawn("SHOW TIME") with SYS$OUTPUT redirected; asserts the captured file carries the current year (oracle: this process's own clock). Captured 13-AUG-2026 06:13:44.05 — genuine DCL SHOW TIME. /bin/sh -c "SHOW TIME" would print a SHOW: not found error, so the pre-fix body fails this.
  2. Honest failure, no fallback — with the CLI image absent, asserts even (failure) status and that no output file was created.

vmsdcl -c runs without the executive (cf. test_dcl_basic.sh), so the whole spawn→DCL→SHOW TIME path is provable on a host ctest.

Results

  • test_libvms_lib_spawn_dcl PASS; 34/34 libvms tests green.
  • Rule-9 runtime_target_gate + runtime_target_negctl + dcl-integration green.
  • Full tree builds clean.
  • No new cross-image symbol (lib$spawn already exported; helper is static) → libvms_shr vector unchanged, native-link unaffected.

Deferred (prereqs B/C — vms-e0b mailbox, vms-9003 write-attention AST)

The efn/AST completion notification, named-subprocess ($CREPRC) registration, and the persistent DCL subprocess + mailbox + write-attention-AST protocol MMK's build_target.c uses (stream many commands into one long-lived DCL, read each command's full $STATUS from an end-of-command marker) are accepted-and-documented, not faked. This PR is the create+run primitive that rides under that protocol. Note: DCL's -c mode collapses $STATUS to shell 0/1, so full $STATUS fidelity comes via the B/C mailbox EOM markers, not this path.

Clean-room (Rule 8): LIB$SPAWN semantics from the public VSI OpenVMS RTL Library (LIB$) Routines Reference Manual and the DCL Dictionary (SPAWN / SHOW TIME).

🤖 Generated with Claude Code

alice and others added 2 commits August 13, 2026 06:14
…exec-drive prereq A)

lib$spawn was a Rule-9 / INV-6 facade: it fork+exec'd `/bin/sh -c <command>`
(the Unix Bourne shell, NOT a DCL command interpreter) and returned SS$_NORMAL
for a "SHOW TIME" no DCL ever saw. Replace it with a genuine DCL subprocess:
resolve SYS$SYSTEM:DCL.EXE through the VMS filespec translator (the same image
JOB_CONTROL and PROVISION exec) and fork+exec it against the command via DCL's
-c mode, with SYS$INPUT/SYS$OUTPUT redirection.

Honest boundary (Rule 9 / INV-6): if the CLI image cannot be resolved or is not
an executable regular file, return an authentic VMS error (SS$_NOSUCHFILE) and
run NOTHING -- no /bin/sh fallback, never a fake success for a command that did
not run. Running a real child image needs no /dev/vms.

CLI$M_NOWAIT is honored (create-and-return); wait mode HIBERNATEs on the child
and returns its completion status. The efn/AST completion notification, named-
subprocess registration, and the persistent-subprocess + mailbox + write-
attention-AST protocol MMK's build_target.c uses are prereqs B/C (vms-e0b,
vms-9003) -- accepted-and-documented here, not faked.

Test: tests/libvms/test_lib_spawn_dcl.c redirects SYS$SYSTEM to a private root,
stages the build's own DCL image there, and drives the real lib$spawn path.
Asserts (1) SHOW TIME's redirected SYS$OUTPUT carries the current year (oracle:
this process's clock) -- proving a real DCL child ran it; (2) with the CLI image
absent, lib$spawn fails even-status and creates nothing (no /bin/sh fallback).
Hermetic, no shared /vms, no /dev/vms. 34/34 libvms tests green; Rule-9 runtime-
target gate + dcl-integration green; full tree builds.

No new cross-image symbol (lib$spawn already exported; helper is static), so the
libvms_shr vector is unchanged.

Doc pins (VSI OpenVMS, public): RTL Library (LIB$) Routines Reference Manual,
LIB$SPAWN; DCL Dictionary, SPAWN / SHOW TIME.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ixes kif_caller_census)

The kif_caller_census authenticity gate went red on CI (Build & Test), not from
any lib$spawn behavior regression -- test_libvms_lib_spawn_dcl itself passed on
CI -- but because its CMake handed the DCL image path to the test as a quoted
string compile definition (VMSDCL_PATH="$<TARGET_FILE:vmsdcl>"). That put the
only backslash-escaped entry in the whole compile_commands.json, and the census
reader parses compile_commands.json and does not implement backslash unescaping.

Hand the path over at RUNTIME via a CTest ENVIRONMENT property
(OVMX_TEST_DCL_IMAGE=$<TARGET_FILE:vmsdcl>) instead. compile_commands.json is
clean again (0 backslash escapes) and the test stays hermetic against the image
the build produced. If the variable is ever absent (standalone run) the test
skips honestly via SKIP_RETURN_CODE 77 rather than faking a pass.

Verified locally: kif_caller_census PASS, test_libvms_lib_spawn_dcl PASS, full
ctest 172/172 (e2e QEMU/docker suites skipped as on CI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@baron-3dl
baron-3dl merged commit d6fc55e into main Aug 13, 2026
61 checks passed
baron-3dl added a commit that referenced this pull request Aug 13, 2026
…456)

Bump OVMX_PRODUCT_VERSION V0.4-1 → V0.4-2. 10 PRs since V0.4-1, toward the
0.5 milestone:

  owns-kernel    #450 OVMX builds its own pinned linux-6.12.103 LTS from source
                 (byte-reproducible, boots 17/17+24/24) — vms-19e beachhead
  self-host #4   #446 MMK.EXE parses descrip.mms + emits TCC→LINK plan
                 (exec-drive facilities, all proven vs real /dev/vms:)
                 #451 lib$spawn real DCL (facade killed) · #452 mailbox IPC
                 #453 write-attention AST · #454 exec-drive design record
  UX fidelity    #447 DIRECTORY format+versions · #448 Ctrl-T status line
                 #449 hierarchical HELP engine · #455 SHOW MEMORY (drop
                 buffers+cached fabrication)
  + swept other threads' merged work

MMK does not yet DRIVE builds (spine #4 needs async AST delivery + IO$M_NOW
+ DCL-mailbox-SYS$INPUT — filed vms-feb/5df/786, faithful path in flight).

Co-authored-by: alice <alice@workspace.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant