Skip to content

vms-54e: LIB$GET_FOREIGN returns the foreign-command tail, not stdin - #414

Merged
baron-3dl merged 1 commit into
mainfrom
vms-54e-lib-get-foreign
Aug 13, 2026
Merged

baron-3dl merged 1 commit into
mainfrom
vms-54e-lib-get-foreign

Conversation

@baron-3dl

Copy link
Copy Markdown
Contributor

Summary

Fixes LIB$GET_FOREIGN semantics (self-host MMK spine prereq, parent vms-801, per the vms-52c anchor docs/design-self-host-mmk-spine.md P5). It previously always read a line from stdin, so an image activated as a foreign command (FOO /qual target) could never retrieve its own invocation tail — the exact plumbing MMK needs (mmk.c calls lib$get_foreign to fetch its command line).

Semantics (grounded, clean-room)

Derived from the VSI OpenVMS RTL Library (LIB$) Manual and the corpus lib_get_foreign.c — no VSI/HPE source touched:

  • First call returns the CLI foreign command line if present.
  • No line (ordinary RUN, or an empty tail) and subsequent calls: prompt on SYS$INPUT exactly like LIB$GET_INPUT (RMS$_EOF at end of file).
  • A line longer than the resultant descriptor is truncated → LIB$_INPSTRTRU.

Where the tail now comes from

DCL's foreign-command dispatch (dcl_exec_foreign_command) publishes the raw untokenized command tail (cmd->raw_tail) in the VMS_FOREIGN_CMD environment variable before activation — the same env channel DCL already uses for VMS process context (VMS_DEFAULT_DIR, ...). It reaches both activation models: in-process activation (same process) and the fork()+execve() fallback (inherited env). RUN and DCL-driven utilities do not set it, so they correctly fall through to SYS$INPUT.

lib$get_foreign consumes the line on first read by clearing the variable, modelling VMS's one-shot CLI foreign line in per-activation state — deliberately not a static flag, which would leak between images under in-process activation (the LIB$ code lives in the resident producer shareable whose statics persist across activations).

Changes

  • libdef.h: add LIB$_INPSTRTRU (0x0015821C), grounded to the public $LIBDEF symbol table (FreeVMS starlet/src/libdef.h); encoding cross-checks against the already-verified LIB$_INSVIRMEM = 0x00158022.
  • mk_decc_shr.sh: append unsetenv to the DECC$SHR symbol vector (append-only, GSMATCH-compatible; getenv/setenv were already exported). Caught by reproducing OVMX_LINK_NATIVE locally — the STRICT native link failed on the unresolved external until the vector was updated.
  • test_lib_rtl_batch3.c: assert the exact tail is returned (not stdin), class-S space-padding, one-shot consumption (second call reads SYS$INPUT), and LIB$_INPSTRTRU truncation; make the EOF test deterministic by clearing VMS_FOREIGN_CMD first.

Test

  • Debug ctest: green — 146 run/pass, 12 docker-e2e skipped (exit 0).
  • x86_64 OVMX_LINK_NATIVE link_native_graph reproduced clean in alpine-musl: 9 artifacts, all EM_X86_64, zero DT_NEEDED.

🤖 Generated with Claude Code

Self-host MMK spine prereq (parent vms-801, per the vms-52c anchor
docs/design-self-host-mmk-spine.md P5). MMK activates as a foreign
command and calls lib$get_foreign to fetch its invocation tail; OVMX's
lib$get_foreign previously ALWAYS read a line from stdin, so an image
invoked as `FOO /qual target` could never see its own arguments.

Semantics grounded in the VSI OpenVMS RTL Library (LIB$) Manual and the
corpus lib_get_foreign.c: the first call returns the CLI foreign command
line if present; with no line (an ordinary RUN, or an empty tail) and on
subsequent calls it prompts on SYS$INPUT exactly like LIB$GET_INPUT
(RMS$_EOF at end of file); a line longer than the resultant descriptor is
truncated and returns LIB$_INPSTRTRU.

Plumbing: DCL's foreign-command dispatch (dcl_exec_foreign_command)
publishes the raw untokenized command tail (cmd->raw_tail) in the
VMS_FOREIGN_CMD environment variable before activation -- the same env
channel DCL already uses for VMS process context (VMS_DEFAULT_DIR, ...) --
which reaches both the in-process activation path and the fork()+execve()
fallback. RUN and DCL-driven utilities do not set it, so they fall
through to SYS$INPUT. lib$get_foreign consumes the line on first read by
clearing the variable, modelling VMS's one-shot CLI foreign line in
per-activation state (robust to the resident-producer statics shared
across in-process activations, where a static consumed-flag would leak
between images).

- libdef.h: add LIB$_INPSTRTRU (0x0015821C), grounded to the public
  $LIBDEF symbol table; encoding cross-checks vs verified LIB$_INSVIRMEM.
- mk_decc_shr.sh: append unsetenv to the DECC$SHR symbol vector
  (append-only; getenv/setenv were already exported) so the STRICT
  native-link resolves it -- caught by reproducing OVMX_LINK_NATIVE.
- test_lib_rtl_batch3.c: assert the exact tail is returned (not stdin),
  space-padding, one-shot consumption, and LIB$_INPSTRTRU truncation;
  make the EOF test deterministic by clearing VMS_FOREIGN_CMD first.

Debug ctest green (146 run/pass, 12 docker-e2e skipped). x86_64
OVMX_LINK_NATIVE link_native_graph reproduced clean (9 artifacts, all
EM_X86_64, zero DT_NEEDED).

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

Bump OVMX_PRODUCT_VERSION V0.4 → V0.4-1. 24 PRs / 32 commits since V0.4,
packed across dimensions (point release toward the 0.5 milestone):

  self-host (R7)  #409 lib$tparse · #411 CLI$ compiled-CLD · #413 sys$setddir
                  #414 lib$get_foreign · #415 sys$filescan (RTL foundation)
                  #418 parse_tables.mar→C (spine #2) · #429 LIBRARIAN.EXE+.OLB (spine #3)
                  #435 shareable-vector freeze (GSMATCH stability)
  authenticity    #421 veracity rubric (Q1 oracle-source/Q2 real-inject) · #424 30 oracle-pinned constants
                  #433 rmsdef.h 74 fabricated RMS codes → oracle
  UX/DCL/RMS      #422 SHOW CLUSTER real membership · #441 DCL per-@-level local scope
                  #442 RMS XAB dates → VMS 1858-epoch quadword
  networking      #419 virtio NIC (user-mode default + opt-in tap/bridge)
  docs            #423 clustering release train
  + swept: other threads' merged work on main since V0.4

Clustering config-authoring UX (vms-098) + its public-manual grounding gate
remain 0.5 (minor) deliverables — not triggered by this point cut.

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