Skip to content

Restore the JES2 DDs the STC procedure allocates for its modules - #257

Merged
mgrossmann merged 4 commits into
mainfrom
issue-256-restore-jes2-dds
Aug 25, 2026
Merged

Restore the JES2 DDs the STC procedure allocates for its modules#257
mgrossmann merged 4 commits into
mainfrom
issue-256-restore-jes2-dds

Conversation

@mgrossmann

Copy link
Copy Markdown
Contributor

Fixes #256.

The mechanism

A CGI module is dispatched by the MVS LINK SVC into HTTPD's own task. It has
no allocations of its own, so every ddname it opens resolves against the STC
procedure's. That makes samplib/httpd part of the modules' contract, not just
the server's — and c35ab59 removed two DDs from it after checking only
httpd/src/.

mvsMF's jobs API opens the JES2 checkpoint and spool by name, through libc370's
jesopen() (src/jes/jesopen.c:36,46), from three call sites in jobsapi.c:

line function endpoint
157 jobListHandler GET /zosmf/restjobs/jobs
741 do_print_sysout spool retrieval
1229 find_job_by_name_and_id single-job lookup

Each answers 500 without the DDs, and writes two console lines per request —
libc370's Unable to open checkpoint dataset DD:HASPCKPT and MVSMF201E. Job
submit is unaffected; jesiropn() dynallocs its own INTRDR.

Verified on the artifacts, not argued

The shipped and the rebuilt samplib XMITs, decoded from CP037:

4.0.0 shipped: //HASP* DD statements = []
4.0.1 new    : //HASP* DD statements = ['//HASPCKPT DD']   (+ HASPACE1, split
                                                            across an XMIT
                                                            record boundary)

make package builds all five modules clean and the archive carries the
corrected member.

Why verbatim, not symbolics

The two lines return exactly as 3.3.x had them. Symbolic volsers would add an
installation parameter that can be got wrong and change the PROC interface in a
patch release; an operator diffing against 3.3.x should find nothing new to get
right. The hardcoded VOL=SER is a real portability problem — the fix for
it is libc370 dynallocating checkpoint and spool the way jesiropn() already
dynallocs the INTRDR. That is a library change and is filed on its own, not
shipped here. The comment tells the installer to check UNIT/VOL=SER against
their JES2 procedure.

Docs

  • migration.md was the more severe half — it instructed a working 3.3.x
    system to delete the DDs. Reversed.
  • installation.md gains the requirement in the section that already
    explains why a module needs the STC's STEPLIB: same mechanism, one paragraph
    on.
  • CLAUDE.md records the failure class — a grep that stops at this repo's
    edge cannot answer "does anything still use this", because four consumer repos
    run inside this address space.

Audit of the neighbouring removals

Same check, re-run against every consumer: stck2tv, httpds_, HTTPJES2,
HTTPDSL across mvsmf/src, httplua/src, httprexx/srcno hits. Those
removals were sound. httplua dynallocs its own DDs, httprexx opens none, and the
procedure's remaining DDs are complete (SYSPRINT/SYSTERM/SYSIN are absent
deliberately — httpstrt.c:47-68 refuses to start if they are allocated).

docs/release-notes/

New. The v4.0.0 Release body, captured before that release is replaced — GitHub
is not a source of record for a body deleted along with its release. The 4.0.1
notes are built from it so the changelog survives the correction.

Not decided here

Two release-mechanics questions for the maintainer, in the issue rather than in
code:

  1. THTP400 is already ACCEPTed on any system that installed 4.0.0. A
    4.0.1 full-function SYSMOD under the same FMID cannot simply be received
    over it.
  2. Because the samplib is not an SMP element, such a system needs only the
    corrected SAMPLIB(HTTPD) member — not a new SYSMOD at all.

c35ab59 removed HASPCKPT and HASPACE1 from samplib/httpd because HTTPJES2 was
gone and "nothing else in the server opens them". That check was run against
httpd/src/ alone, and the question it answered is not the question that matters:
a CGI module is dispatched by the LINK SVC into HTTPD's own task, so it has no
allocations of its own and opens every ddname against the STC's.

mvsMF's jobs API opens both data sets by name through libc370's jesopen()
(src/jes/jesopen.c:36,46 -- checkpoint_open("DD:HASPCKPT"),
spool_open("DD:HASPACE1")), from three call sites in jobsapi.c: jobListHandler,
do_print_sysout and find_job_by_name_and_id. Without the DDs each answers 500
and writes two console lines per request, libc370's "Unable to open checkpoint
dataset DD:HASPCKPT" and MVSMF201E. Job submit survives; jesiropn() dynallocs
its own INTRDR.

Measured on the built artifacts rather than argued: the 4.0.0 samplib XMIT
decodes to zero "//HASP* DD" statements, the rebuilt one to both.

The two lines come back verbatim as 3.3.x had them, not as symbolic parameters.
Symbolics would add an installation parameter that can be got wrong and change
the PROC interface in a patch release, and an operator diffing against 3.3.x
should find nothing new to get right. The hardcoded VOL=SER is a genuine
portability problem, but its fix is libc370 dynallocating the checkpoint and
spool the way jesiropn() already dynallocs the INTRDR -- a library change,
filed on its own. The comment says to check UNIT/VOL=SER against the site's
JES2 procedure.

migration.md is the more severe half and it is reversed here: it told a working
3.3.x system to delete the two DDs. installation.md gains the requirement in
the section that already explains why a module needs the STC's STEPLIB -- same
mechanism, one paragraph further. CLAUDE.md records the failure class: a grep
that stops at this repo's edge cannot answer "does anything still use this",
because four consumer repos run inside this address space.

Re-ran that grep for the neighbouring removals in c35ab59 -- stck2tv, httpds_,
HTTPJES2, HTTPDSL across mvsmf, httplua and httprexx: no hits. Those were
sound. httplua dynallocs its own DDs, httprexx opens none, and the procedure's
remaining DDs are complete -- SYSPRINT/SYSTERM/SYSIN are absent deliberately,
httpstrt.c refuses to start when they are allocated.

docs/release-notes/ is new: the v4.0.0 GitHub Release body, captured before the
release is replaced. GitHub is not a source of record for a body that gets
deleted with its release, and the 4.0.1 notes are built from this file so the
changelog survives the correction.

Fixes #256
The file was reconciled against a tracker with three issues open and 4.0.0
untagged. Both moved: 4.0.0 shipped on 2026-08-24, #254 and #256 are open, and
#256 outranks everything because it is the only item that is wrong on a system
someone can install today.

What the tracker cannot hold, and what this file is for: the code half of #256
is written, the release half is a decision. THTP400 is ACCEPTed on any system
that installed 4.0.0, so a 4.0.1 SYSMOD under the same FMID cannot be received
over it -- and does not need to be, because the corrected member is in the
sample library and the sample library is not an SMP element. Such a system
needs one PROCLIB member replaced and nothing from SMP.

Also records why the SMP rehearsal in smp-todo.md did not catch this: it
verified that the install works, never that the procedure it installs still
allocates what the CGI it routes to opens.

The two issues filed out of #256 go under Cross-repo, both explicitly not
blocking 4.0.1: mvsmf#357 (state the requirement where a mvsMF installer looks)
and libc370#142 (dynalloc the checkpoint and spool, removing the class).
All three were written from one measurement and generalised, which is the same
move that produced the bug being fixed.

The jobs API does not fail uniformly. Two of the three jesopen() call sites
answer 500, as documented -- jobListHandler and do_print_sysout both send
REASON_INCORRECT_JES_VSAM_HANDLE. The third does not: find_job_by_name_and_id()
returns NULL on an unreachable JES2, and all four of its callers report that as
404 job not found, the same answer they give for a job that genuinely is not
there. So a client resolving one job by name and id is told it does not exist
while it does. That is worth more than the sentence it replaces: the status code
misreports the cause, and the console pair is the only reliable signal.

docs/release-notes/README.md described a convention the release machinery does
not implement. mbt's shared release.yml deletes every existing release for the
tag and recreates it with `gh release create --generate-notes`, so a body is
built from commit subjects and a hand-written one does not survive a re-push.
The README now says what actually applies a body (`gh release edit
--notes-file`, after the workflow, not before) and warns that reusing v4.0.0's
means substituting its six artifact names and every HTTPD.V4R0M0.* qualifier.

"Four consumer repos" was three: mvsmf, httplua and httprexx ship modules that
run in this address space. ftpd is a separate server, not a module. The wrong
count sat in the two files that now carry the rule.
@mgrossmann

Copy link
Copy Markdown
Contributor Author

Three corrections pushed in d12e81e. All three were written from one
measurement and generalised — the same move that produced the bug.

The jobs API does not fail uniformly. The description above says all three
call sites answer 500. Only two do:

call site on an unreachable JES2
jobListHandler (157) 500, REASON_INCORRECT_JES_VSAM_HANDLE
do_print_sysout (741) 500, same
find_job_by_name_and_id (1229) returns NULL → callers send 404 job not found

The third is the interesting one. find_job_by_name_and_id() returns NULL
whether JES2 is unreachable or the job is genuinely absent, and all four callers
(237, 291, 388, 1783) report the second. A client is told the job does not exist
while it does. The console pair is the only reliable signal, which strengthens
rather than weakens the case for the fix. installation.md and migration.md
now say this.

docs/release-notes/ described a convention the machinery does not
implement.
mbt's shared release.yml deletes every existing release for the
tag and recreates it with gh release create --generate-notes, so the body is
built from commit subjects and a hand-written one does not survive a re-push of
the tag. The README now names what actually applies a body — gh release edit --notes-file, after the workflow — and warns that reusing v4.0.0's means
substituting its six artifact names and every HTTPD.V4R0M0.* qualifier.

"Four consumer repos" was three — mvsmf, httplua, httprexx. ftpd is a
separate server, not a module. Fixed in CLAUDE.md and TODO.md, which are the
files now carrying the rule.

Every version string substituted -- six artifact names, the HTTPD.V4R0M0.*
qualifiers, and the compare link. FMID stays THTP400: no code changed between
the two releases, so there is no functional level to cut.

The new section leads because it is what an existing installation needs, and
what it needs is small: add the two DD statements to the PROCLIB member and
restart. SMP has nothing to do -- the corrected member is in the sample
library, which is not an SMP element, and the load modules are identical.

It also says what not to do, which is the trap this package sets. The shipped
procedure's STEPLIB names HTTPD.V4R0M1.LINKLIB, the library this package
installs into. Copying the new member wholesale onto a system running 4.0.0
points the started task at a dataset that does not exist there. Take the two
lines, not the member.
@mgrossmann
mgrossmann merged commit d45cd43 into main Aug 25, 2026
1 check passed
@mgrossmann
mgrossmann deleted the issue-256-restore-jes2-dds branch August 25, 2026 08:30
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.

STC procedure drops HASPCKPT/HASPACE1, breaking mvsMF's jobs API

1 participant