Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions distro/Dockerfile.bootable
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# Contains only: STARTUP.EXE (/init),
# INITIALIZE.EXE, kernel modules, config,
# and SYS$MANAGER files. All other binaries
# (DCL, LOGIN, HELP, LNMD) must be on the
# (DCL, LOGIN, HELP) must be on the
# system disk (/vms).
#
# STARTUP.EXE (ovmx_init) is /init — no busybox, no shell scripts.
Expand Down Expand Up @@ -94,7 +94,6 @@
cp build-static/bin/DCL.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ && \
cp build-static/bin/LOGINOUT.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ && \
cp build-static/bin/HELP.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ && \
cp build-static/bin/VMSLNMD.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ && \
cp build-static/bin/AUTHORIZE.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ 2>/dev/null ; \
cp build-static/bin/MAIL.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ 2>/dev/null ; \
cp build-static/bin/MONITOR.EXE /initramfs-fat/vms/SYS0/SYSCOMMON/SYSEXE/ 2>/dev/null ; \
Expand All @@ -112,7 +111,7 @@

# -- SLIM initramfs ------------------------------------------------------------
# Bootstrap-only: STARTUP.EXE + INITIALIZE.EXE + kernel modules + config.
# All other binaries (DCL, LOGIN, HELP, LNMD) must be on the system disk.
# All other binaries (DCL, LOGIN, HELP) must be on the system disk.
# Use this after the system disk has been installed via the fat initramfs.
RUN mkdir -p /initramfs-slim/dev /initramfs-slim/proc /initramfs-slim/sys \
/initramfs-slim/tmp /initramfs-slim/var /initramfs-slim/mnt \
Expand Down Expand Up @@ -161,7 +160,7 @@
# boot.sh mounts a host directory at /data so the container owns the disk
# file and can write freely (avoids rootless Docker permission issues).
# When run standalone (no /data mount), falls back to /tmp/sysdisk.img.
CMD ARCH=$(uname -m) && \

Check warning on line 163 in distro/Dockerfile.bootable

View workflow job for this annotation

GitHub Actions / Persistent Boot Smoke Test

JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals

JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals More info: https://docs.docker.com/go/dockerfile/rule/json-args-recommended/

Check warning on line 163 in distro/Dockerfile.bootable

View workflow job for this annotation

GitHub Actions / VMS User Acceptance Test

JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals

JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals More info: https://docs.docker.com/go/dockerfile/rule/json-args-recommended/
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
QEMU=qemu-system-aarch64; \
MACHINE="-machine virt -cpu cortex-a57"; \
Expand Down
3 changes: 0 additions & 3 deletions distro/rootfs/vms/SYS0/SYSCOMMON/SYSMGR/OVMX.CONF
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,3 @@ DEFAULT_PROTECTION=S:RWED,O:RWED,G:RE,W:

# Enable VMS-style file versioning
FILE_VERSIONING=1

# Logical name daemon socket path
LNM_SOCKET=/tmp/ovmx/lnm.sock
11 changes: 6 additions & 5 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Layer 4 ─ User Interface

Layer 3 ─ File Services
Record management, VMS filesystem, logical names
[vmsrms, vmsfs, vmslnm + vmslnmd daemon]
[vmsrms, vmsfs, vmslnm]

Layer 2 ─ VMS Runtime
System services and RTL
Expand All @@ -57,7 +57,9 @@ libvmssys (freestanding, static only)
│ │
│ └── libvms (+ pthread, math)
│ │
│ ├── vmslnm (+ pthread) ──→ vmslnmd daemon
│ ├── vmslnm (+ pthread) — per-process tables only;
│ │ no daemon (deleted, vms-a4b); executive-resident
│ │ placement is an open ruling, see vms-ln0
│ │ │
│ │ └── vmsfs
│ │ │
Expand Down Expand Up @@ -93,8 +95,7 @@ docker build -f Dockerfile.bootable -o dist .
├── Load: vms.ko, vmsfs.ko
├── Generate /etc/passwd, /etc/group from sysuaf.dat
└── exec /sbin/init (ovmx_init)
├── Start vmslnmd
├── Load system logicals
├── (no logical name daemon — deleted, vms-a4b; VMS has no such process)
├── Execute STARTUP.COM
└── Launch login shell (vmsdcl)
```
Expand Down Expand Up @@ -135,7 +136,7 @@ User types command via SSH
| libvmssys | `src/libvmssys/vms_runtime_init.c` | `vmssys.h` | libvmssys.a |
| vmsprocess | `src/vmsprocess/vms_pcb.c` | `include/vms/process.h` | libvmsprocess |
| libvms | `src/libvms/syssvc/sys_qio.c` | `include/starlet.h` | libvms |
| vmslnm | `src/vmslnm/lnm_table.c` | `include/vms/logical.h` | libvmslnm, vmslnmd |
| vmslnm | `src/vmslnm/lnm_table.c` | `include/vms/logical.h` | libvmslnm |
| vmsfs | `src/vmsfs/vmsfs_translate.c` | `include/vmsfs/filespec.h` | libvmsfs |
| vmsrms | `src/vmsrms/rms_core.c` | `include/rms/rms.h` | librms |
| vmsdcl | `src/vmsdcl/dcl_main.c` | `include/dcl/context.h` | vmsdcl |
Expand Down
2 changes: 1 addition & 1 deletion docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ cmake --build build -j$(nproc)

**Outputs** in `build/`:
- Libraries: `libvms.so`, `libvmsprocess.so`, `libvmslnm.so`, `libvmsfs.so`, `librms.so`, `libvmssys.a`
- Executables: `vmsdcl`, `vmslnmd`, `vms_login`, `vms_help`, `vms_ssh_auth`, `ovmx_init`
- Executables: `vmsdcl`, `vms_login`, `vms_help`, `vms_ssh_auth`, `ovmx_init`
- Tests: `test_vmssys_*`, integration tests

## Static Build
Expand Down
9 changes: 6 additions & 3 deletions docs/design-authenticity-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,10 @@ of *every file open*. An ioctl per translation is a syscall round trip. LNM may
mapping (the `MAP_SHARED` known-image DB is the in-tree precedent) or kernel-side storage with a
per-process cache plus invalidation. Decide LNM separately from the rest.

**Scope:** tracked as **`vms-6b8`**. The `lnm.sock` daemon (already loads `SYLOGICALS.CONF`; nothing
connects to it) and the `MAP_SHARED` known-image DB are the two userspace precedents.
**Scope:** tracked as **`vms-6b8`**. The `MAP_SHARED` known-image DB is the surviving userspace
precedent. The other one, the `lnm.sock` daemon, was deleted by `vms-a4b`: it loaded
`SYLOGICALS.CONF` into a private table that nothing connected to, and VMS has no logical name
server process to model it on.

### 2.2 Re-tiering: rank by tell-probability, not by feature completeness

Expand Down Expand Up @@ -325,7 +327,8 @@ the logical rather than regressing to a compiled-in greeting.

**Logical names are themselves an authenticity surface** (`vms-d37`, blocks A4). Wiring the banner to
`SYS$WELCOME` exposed that OVMX logical-name tables are **per-process**: `lnm_get_manager()` builds an
in-process table, and nothing but the daemon itself reads `SYLOGICALS.CONF`. Demonstrated across two
in-process table, and nothing but the (since-deleted) daemon ever read `SYLOGICALS.CONF`.
Demonstrated across two
DCL processes:

```
Expand Down
11 changes: 9 additions & 2 deletions docs/design-image-activation.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ Priority 1: Known Image Database (VMS$KNOWN_IMAGES.DAT)
|
Priority 2: Hardcoded SYS$SHARE fallback
| /vms/SYS0/SYSCOMMON/SYSLIB/<SONAME>
| Always available, even before VMSLNMD starts
| Always available, even before the Known Image DB exists
| This is the chicken-and-egg breaker
|
Priority 3: SYS$SHARE logical name (after VMSLNMD)
Priority 3: SYS$SHARE logical name (once the tables are executive-resident)
| Translate SYS$SHARE via vmslnm API
| Search result directory for SONAME
| Only available after logical name daemon is running
Expand All @@ -346,6 +346,13 @@ Not found: %IMGACT-F-IMGNOTFND error

### Chicken-and-Egg: VMSLNMD Bootstrap

> **SUPERSEDED (`vms-a4b`, 2026-07-30).** `VMSLNMD.EXE` no longer exists. OpenVMS has no logical
> name server process — the tables are executive-resident — so the daemon was deleted rather than
> kept as a bootstrap step. Everything below describing VMSLNMD's place in the boot sequence is
> **historical**. The resolution it describes still holds and is now the *whole* story: IMGACT.EXE
> breaks the circularity with its hardcoded `SYS$SHARE` fallback path, and no daemon is involved.
> Where the executive-resident tables end up living is ruled by `vms-ln0` / built by `vms-d37`.

The logical name daemon (`VMSLNMD.EXE`) is itself a dynamically linked binary
that requires image activation. But IMGACT.EXE normally uses logical names
(SYS$SHARE) to find shareable images. This creates a circular dependency.
Expand Down
6 changes: 3 additions & 3 deletions src/imgact/imgact.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,9 @@ static void known_db_shutdown(void)
* Priority 1: Known Image Database -- O(1) mmap'd hash lookup, no
* filesystem search at all on a hit (bead vms-30d).
* Priority 2: hardcoded SYS$SHARE fallback (vms-913.2; always available,
* even before the Known Image DB exists or VMSLNMD starts).
* Priorities 3 (SYS$SHARE logical name via VMSLNMD) and 4 (ELF RPATH) are
* not yet implemented. */
* even before the Known Image DB exists).
* Priorities 3 (SYS$SHARE logical name, once the logical name tables are
* executive-resident -- vms-a4b) and 4 (ELF RPATH) are not yet implemented. */
static struct obj *load_needed(const char *soname)
{
struct obj *existing = find_loaded(soname);
Expand Down
2 changes: 1 addition & 1 deletion src/imgact/test/verify_imgact_cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ readelf -dW "$BIN/STARTUP.EXE" 2>/dev/null | grep -q NEEDED && fail "STARTUP.EXE
echo " ok"

echo "== executables: PT_INTERP=IMGACT.EXE, DT_HASH =="
for exe in DCL.EXE LOGINOUT.EXE VMSLNMD.EXE; do
for exe in DCL.EXE LOGINOUT.EXE HELP.EXE; do
[ -f "$BIN/$exe" ] || fail "$exe not built"
readelf -lW "$BIN/$exe" | grep -q "$IMGACT_PATH" \
|| fail "$exe PT_INTERP != $IMGACT_PATH"
Expand Down
2 changes: 1 addition & 1 deletion src/imgact/test/verify_imgact_cmake_x86_64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ $READELF -dW "$BIN/STARTUP.EXE" 2>/dev/null | grep -q NEEDED && fail "STARTUP.EX
echo " ok"

echo "== executables: PT_INTERP=IMGACT.EXE, DT_HASH =="
for exe in DCL.EXE LOGINOUT.EXE VMSLNMD.EXE; do
for exe in DCL.EXE LOGINOUT.EXE HELP.EXE; do
[ -f "$BIN/$exe" ] || fail "$exe not built"
$READELF -lW "$BIN/$exe" | grep -q "$IMGACT_PATH" \
|| fail "$exe PT_INTERP != $IMGACT_PATH"
Expand Down
5 changes: 4 additions & 1 deletion src/libvms/include/ovmx_layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
#define VMS_SYLOGIN_PATH "SYS$MANAGER:SYLOGIN.COM"
#define VMS_STARTUP_PATH "SYS$MANAGER:STARTUP.COM"
#define VMS_HELPLIB_PATH "SYS$HELP:HELPLIB.HLP"
/* Reserved: zero readers as of vms-a4b (its only reader, lnm_daemon.c,
* was deleted). Not wired to anything until the executive-resident
* logical name work lands — see vms-ln0 (gated, operator sign-off
* pending) and vms-d37. Do not add a reader without that ruling. */
#define VMS_LNM_CONF_PATH "SYS$MANAGER:SYLOGICALS.CONF"
#define VMS_SSH_HOST_KEY "SYS$MANAGER:SSH_HOST_RSA_KEY"

Expand All @@ -67,7 +71,6 @@

#define VMS_DCL_PATH "SYS$SYSTEM:DCL.EXE"
#define VMS_LOGINOUT_PATH "SYS$SYSTEM:LOGINOUT.EXE"
#define VMS_LNMD_PATH "SYS$SYSTEM:VMSLNMD.EXE"
#define VMS_SSHD_PATH "SYS$SYSTEM:VMSSSHD.EXE"
#define VMS_AUTHORIZE_PATH "SYS$SYSTEM:AUTHORIZE.EXE"
#define VMS_INITIALIZE_PATH "SYS$SYSTEM:INITIALIZE.EXE"
Expand Down
73 changes: 9 additions & 64 deletions src/ovmx_init/ovmx_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "ovmx_layout.h"
#include "ovmx_identity.h"

#define LNM_SOCKET_PATH "/tmp/ovmx/lnm.sock"
#define SYSDISK_DEV "/dev/vda"
#define INITRAMFS_BACKUP "/tmp/initramfs_vms"

Expand Down Expand Up @@ -465,7 +464,7 @@ static void provision_symlinks(void)
/* [SYS0.SYSCOMMON.SYSEXE] executables */
const char *exes[] = {
"LOGINOUT.EXE", "DCL.EXE", "HELP.EXE", "AUTHORIZE.EXE",
"MAIL.EXE", "MONITOR.EXE", "VMSSSHD.EXE", "VMSLNMD.EXE",
"MAIL.EXE", "MONITOR.EXE", "VMSSSHD.EXE",
"STARTUP.EXE", NULL
};
for (int i = 0; exes[i]; i++) {
Expand Down Expand Up @@ -564,47 +563,6 @@ static void install_system_blkdev(void)
printf("%%STARTUP-I-INSTALLED, system installation complete\n");
}

/*
* Try to start the logical name daemon.
* Returns the child PID on success, -1 if vmslnmd not found.
*/
static pid_t start_lnm_daemon(void)
{
char lnmd_path[512];
vms_to_linux(VMS_LNMD_PATH, lnmd_path, sizeof(lnmd_path));
struct stat st;
if (stat(lnmd_path, &st) != 0) {
return -1; /* vmslnmd not available */
}

pid_t pid = fork();
if (pid == 0) {
/* Child: exec vmslnmd */
execl(lnmd_path, "vmslnmd", (char *)NULL);
_exit(1);
}
return pid;
}

/*
* Wait for the LNM daemon socket to appear (up to timeout_ms).
*/
static int wait_for_lnm_socket(int timeout_ms)
{
struct stat st;
int elapsed = 0;
int interval = 50000; /* 50ms */

while (elapsed < timeout_ms * 1000) {
if (stat(LNM_SOCKET_PATH, &st) == 0) {
return 1; /* Socket appeared */
}
usleep((useconds_t)interval);
elapsed += interval;
}
return 0; /* Timed out */
}

/*
* Try to start the SSH daemon for remote access.
* Returns the child PID on success, -1 if sshd not found.
Expand Down Expand Up @@ -664,7 +622,7 @@ static void run_startup(void)
/*
* Display VMS-style boot banner.
*/
static void display_boot_banner(int lnm_started, int sshd_started)
static void display_boot_banner(int sshd_started)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
Expand All @@ -683,10 +641,6 @@ static void display_boot_banner(int lnm_started, int sshd_started)
tm.tm_hour, tm.tm_min, tm.tm_sec,
(int)(ts.tv_nsec / 10000000));

if (lnm_started) {
printf("%%STDRV-I-LNMSTART, logical name daemon started\n");
}

if (sshd_started) {
printf("%%STDRV-I-SSHSTART, SSH remote access started on port 22\n");
}
Expand Down Expand Up @@ -765,29 +719,24 @@ int main(void)
* without overwriting existing files. */
provision_seed_files();

/* Step 3: Start logical name daemon */
int lnm_started = 0;
pid_t lnm_pid = start_lnm_daemon();
if (lnm_pid > 0) {
lnm_started = wait_for_lnm_socket(2000);
}

/* Step 4: Run STARTUP.COM */
/* Step 3: Run STARTUP.COM.
* There is no logical name daemon to start first: on VMS the logical name
* tables are executive-resident, not a service (vms-a4b). */
run_startup();

/* Step 5: Start SSH daemon */
/* Step 4: Start SSH daemon */
int sshd_started = 0;
pid_t sshd_pid = start_sshd();
if (sshd_pid > 0) {
sshd_started = 1;
}

/* Step 6: Boot banner */
display_boot_banner(lnm_started, sshd_started);
/* Step 5: Boot banner */
display_boot_banner(sshd_started);
fflush(stdout);
fflush(stderr);

/* Step 7: Login loop (only if stdin is a terminal) */
/* Step 6: Login loop (only if stdin is a terminal) */
char loginout_path[512], dcl_path[512];
vms_to_linux(VMS_LOGINOUT_PATH, loginout_path, sizeof(loginout_path));
vms_to_linux(VMS_DCL_PATH, dcl_path, sizeof(dcl_path));
Expand Down Expand Up @@ -893,10 +842,6 @@ int main(void)
kill(sshd_pid, SIGTERM);
waitpid(sshd_pid, NULL, 0);
}
if (lnm_pid > 0) {
kill(lnm_pid, SIGTERM);
waitpid(lnm_pid, NULL, 0);
}

return 0;
}
3 changes: 1 addition & 2 deletions src/vmslink/mk_vmslnm_shr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
# the simplest migration so far: no PT_TLS, no --use LIBVMSSYS$SHR (no vms$/vms_kif_
# freestanding syscall imports), just a plain shareable over DECC$SHR.
#
# Composition: the 4 vmslnm library translation units (NOT lnm_daemon.c, which is a
# separate VMSLNMD.EXE executable), compiled -fPIC musl:
# Composition: the 4 vmslnm library translation units, compiled -fPIC musl:
# lnm_table.c lnm_translate.c lnm_client.c lnm_defaults.c
# Compile flags mirror the proven lib-shareable pattern (mk_vmsprocess_shr.sh):
# -fPIC -O2 -ffreestanding -fno-builtin -fno-stack-protector -mno-outline-atomics
Expand Down
20 changes: 5 additions & 15 deletions src/vmslnm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,8 @@ if(OVMX_IMGACT)
target_link_libraries(vmslnm_static PUBLIC pthread)
endif()

# Daemon executable
add_executable(lnm_daemon_exe lnm_daemon.c)
target_include_directories(lnm_daemon_exe PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${VMS_INCLUDE_DIR}
${VMS_FS_INCLUDE_DIR}
)
target_link_libraries(lnm_daemon_exe PRIVATE vmslnm vmsfs pthread)
target_compile_definitions(lnm_daemon_exe PRIVATE LNM_DAEMON_MAIN)
set_target_properties(lnm_daemon_exe PROPERTIES
OUTPUT_NAME "VMSLNMD"
SUFFIX ".EXE"
)

install(TARGETS lnm_daemon_exe RUNTIME DESTINATION ${VMS_SYSTEM_DIR})
# There is no logical name daemon. On OpenVMS the logical name tables live in
# the executive; there is no server process to start and no socket to connect
# to. VMSLNMD.EXE was an OVMX invention with zero clients product-wide, so it
# is gone rather than reduced (vms-a4b). The executive-resident tables that
# replace it are tracked by vms-ln0 / vms-d37.
11 changes: 8 additions & 3 deletions src/vmslnm/lnm_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
* lnm_client.c - Logical Name Client Library
*
* Provides the public API for logical name operations.
* Currently uses in-process tables with a global static manager.
* Will be extended to talk to the daemon via Unix domain socket
* for system-wide logicals in a future iteration.
* Currently uses in-process tables with a global static manager, so
* SYSTEM/GROUP/JOB tables are per-process, not per-system — a process
* cannot see a logical name DEFINE/SYSTEM'd by another process. On real
* OpenVMS these tables are executive-resident (LNM$SYSTEM_TABLE); there
* is no daemon to talk to. Placement (ioctl-per-translation vs. a
* mmap'd shared arena behind /dev/vms) is an open operator ruling —
* see vms-ln0 (gated) and vms-d37 (blocked twin). Do not add a
* socket/daemon client here; that architecture was deleted (vms-a4b).
*/

#include <stdio.h>
Expand Down
Loading
Loading