From 5a6da37646091b112435b0110fbb4aca40f37c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Gro=C3=9Fmann?= Date: Sun, 23 Aug 2026 22:12:36 +0200 Subject: [PATCH 01/11] Release prep 4.0.0: SMP install package, pinned toolchain, ufsd 1.2.1 Makes `make package` produce an installable product instead of a bare load library, and clears two things that would have broken the release run itself. [distribution] follows ufsd and ftpd: the load modules go through SMP (FMID THTP400, target HTTPD.@VRM@.LINKLIB), the sample library rides beside it as its own XMIT restored by TSO RECEIVE. Both DD names fall out of the dataset names, so HTTPLOAD/AHTTPLOD is a one-shot choice -- it goes into the FMID's JCLIN and changing it later is a new functional level. THTP400 is verified free in the SMPPTS on mvsdev only; the CDS and ACDS store hashed member names, so LIST CDS/ACDS SYSMOD(THTP400) still has to answer RC 04 on both stands before the tag. All five modules ship, ABEND0C1 included: mbtdist packages every [[module]] and offers no exclude, and since 4.0.0 a module is inert unless a Parmlib route names it. samplib/httpd had DSN=HTTPD.LINKLIB hardcoded in its STEPLIB, so the shipped procedure would have pointed at an unversioned library while SMP installed into HTTPD.V4R0M0.LINKLIB. It now carries @LINKLIB@, the placeholder ufsd's and ftpd's procedures use, which mbtdist replaces while staging. docs/installation.md is new and wired in as the archive's README -- the generated install job tells the operator to read it, and without the file the package shipped a dangling instruction. It documents what differs from the other two products: APF failure is fatal here rather than a warning, UFSD is optional but takes static file serving with it, the shipped HTTPPRM0 routes to mvsMF, and removal needs UCLIN because the install accepts the FMID. VERSION said 4.0.0 while project.toml said 4.0.0-dev. mvsrelease.py searches each version file for the *current* string, so `make release VERSION=4.0.0` would have bumped project.toml, failed to find 4.0.0-dev in VERSION, and aborted before any commit -- leaving a modified tree and no tag. Both files now carry the full pre-release string, as ftpd's and ufsd's do. The toolchain pin moves to libc370 1.0.3 and the ufsd range to >=1.2.1, both released 2026-08-23. Verified: `make modules` builds all five clean under -Werror against the new ufsd, and `make package` produces the SYSMOD, both jobs and a samplib XMIT whose extracted procedure reads DSN=HTTPD.V4R0M0D.LINKLIB. --- VERSION | 2 +- docs/installation.md | 783 +++++++++++++++++++++++++++++++++++++++++++ mbt.lock | 4 +- project.toml | 90 ++++- samplib/httpd | 2 +- 5 files changed, 875 insertions(+), 6 deletions(-) create mode 100644 docs/installation.md diff --git a/VERSION b/VERSION index fcdb2e1..d9b058f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.0.0 +4.0.0-dev diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..5e7240f --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,783 @@ +# HTTPD Installation Guide + +This guide installs HTTPD on an MVS 3.8j system (TK4-, TK5, MVS/CE, or a custom +Hercules build) from the release distribution archive. + +The installation is managed by **SMP Release 4** — the SMP that ships with +MVS 3.8j, not SMP/E. That means the system keeps a record of what was +installed, and there is a supported way back out (see +[Removing HTTPD](#11-removing-httpd)). + +## Getting help + +**Report problems as a GitHub issue:** + + +That is the only place bug reports are tracked. Please include the two build +stamps HTTPD writes at startup (`HTTPD000I` and `HTTPD005I`, see +[step 9](#9-start-and-verify)) — they identify the exact build — plus the +console messages and, for an install problem, the job output. + +**Questions and general support** are on Discord: + + +--- + +Two placeholders are used throughout: + +| | | +|---|---| +| `` | the release, e.g. `4.0.0` — it appears in every shipped file name | +| `` | the same release as MVS dataset qualifier, e.g. `V4R0M0` | + +Both are already filled in inside the shipped jobs; you only need them to +recognise which file is which. + +--- + +## 1. What is in the archive + +| File | What it is | +|------|------------| +| `README.md` | this guide | +| `httpd--load.xmit` | the five load modules, as a TSO RECEIVE-ready XMIT | +| `httpd--samplib.xmit` | the sample library: STC procedure and configuration pattern | +| `httpd--alloc.jcl` | allocates the datasets SMP installs into — **run once** | +| `httpd--inst.jcl` | receives everything and installs it — repeatable | + +The load library holds five modules: + +| Module | What it is | +|--------|------------| +| `HTTPD` | the server itself — the only one a started task names | +| `HTTPDSRV` | display module: server control blocks (`/.dsrv`) | +| `HTTPDM` | display module: arbitrary storage (`/.dm`) | +| `HTTPDMTT` | display module: Master Trace Table, i.e. the console log (`/.dmtt`) | +| `ABEND0C1` | a deliberate-abend diagnostic used to exercise storage reclaim | + +**Only `HTTPD` runs unless you ask for the others.** Since 4.0.0 no module is +reachable unless a `MOD=` line in the configuration member names it, so the four +above are inert on a fresh install. That is deliberate: `/.dm` and `/.dmtt` hand +out arbitrary storage and the console log, and `ABEND0C1` abends on purpose. +See [step 7](#7-install-the-procedure-and-the-configuration). + +The sample library holds two members, `HTTPD` (the started task procedure) and +`HTTPPRM0` (the configuration pattern). + +Where everything ends up: + +``` +HTTPD..LINKLIB the load modules -- point STEPLIB here +HTTPD..SAMPLIB the patterns you copy from in step 7 +HTTPD..AHTTPLOD SMP's distribution library, the base a RESTORE returns to +``` + +--- + +## 2. Prerequisites + +- **MVS 3.8j** on Hercules, up and IPLed, with SMP 4 usable (the `SMPREC` and + `SMPAPP` procedures and the `SYS1.SMP*` datasets — present on TK4-/TK5 and + MVS/CE as shipped). +- **RAKF** — see [Authorisation](#authorisation) below. HTTPD does not start + without either RAKF or an APF list entry, and no configuration option turns + that off. +- **UFSD**, only if you want to serve static files — see below. +- **mvsMF**, only if you want the REST API the shipped configuration routes to + — see below. +- A userid authorised to submit jobs, to update a PROCLIB in the started-task + concatenation, and to update a PARMLIB. +- A way to upload a **binary** file to the host — see step 3. +- Roughly 15 cylinders of DASD: 10 for the two libraries the allocation job + creates, the rest for the two TSO RECEIVE targets. One of those, the staging + library, is scratched again by the last step of the install job. + +### UFSD is optional, and what it costs you is static files + +HTTPD serves static content from the **UFSD filesystem and nowhere else** — the +DD-based document root of 3.3.x is gone (4.0.0). `DOCROOT` names a UFS path, so +without the UFSD started task there is nothing to serve statically. + +Nothing about the *install* needs it: the SYSMOD declares no prerequisite, +`libufs` is linked statically into the load modules, and a UFS that does not +initialise is a warning, not a failure: + +``` +HTTPD044W UNABLE TO INITIALIZE FILE SYSTEM +``` + +The server starts, listens, and every `MOD=` route — mvsMF, the display modules +— works normally. Only static file requests fail. A CGI-only HTTPD is an +ordinary deployment. + +Note that `HTTPD001I` still reads `READY - SERVING /www` afterwards: it names +the **configured** document root, not a working filesystem. `HTTPD044W` is the +line that tells you the filesystem is not there, and it is written earlier in +the start. On a deployment that will never have UFSD, `UFS=0` in the +configuration member skips the initialisation altogether and the warning with +it. + +Install HTTPD now and add UFSD later if you want it: +, with its own guide at +[ufsd/docs/installation.md](https://github.com/mvslovers/ufsd/blob/main/docs/installation.md). + +Note that UFSD has to be **running**, not just installed — it is a started task +HTTPD talks to across address spaces. + +### mvsMF is what the shipped configuration expects + +`HTTPPRM0` ships with three active routes, all of them to **mvsMF** — the +z/OSMF-compatible REST API, which is a separate product: + +``` +MOD=MVSMF /zosmf/info AUTH=NONE +MOD=MVSMF /zosmf/services/authenticate AUTH=NONE +MOD=MVSMF /zosmf/* +``` + +If mvsMF is not installed, HTTPD starts and those routes register normally — the +program is not looked for until a request first matches. The failure then shows +up per request as + +``` +HTTPD908E EXTERNAL PROGRAM MVSMF could not be loaded (not found in STEPLIB?) +``` + +Comment the three lines out, or install mvsMF: +. Its load library has to be in the +STC's STEPLIB concatenation — HTTPD dispatches a module through the MVS LINK +SVC, which searches the task's own libraries. + +### RAKF is required for logins + +HTTPD has no user database of its own. Every login — the HTML form, HTTP Basic, +and the token endpoint — is verified by RAKF (RACINIT, SVC 244), and a `RES=` +route option is checked against a RAKF profile under the logged-in user's +identity. **On a system without RAKF nobody can log in.** + +A server whose routes are all `AUTH=NONE` never authenticates anybody and does +not need RAKF for that — but it still needs it for authorisation, below. + +The setup — the `HTTPD` user and its group — is step 8. + +### Authorisation + +HTTPD is link-edited `AC(1)` and needs to be APF-authorised: without it the LINK +SVC that dispatches every module and the RACF services behind every login are +both unavailable. + +It obtains authorisation itself at startup, which goes through **SVC 244 — and +that comes from RAKF**. The clean alternative is to add `HTTPD..LINKLIB` to +the APF list in `SYS1.PARMLIB(IEAAPF00)`. On MVS 3.8j the APF list is only read +at IPL, and the library name carries the version — so this is one IPL per +release, not one IPL ever. + +**With neither, HTTPD does not start.** Unlike FTPD, which warns and keeps +running, HTTPD treats this as fatal: + +``` +HTTPD012E HTTPD UNABLE TO DYNAMICALLY OBTAIN APF AUTHORIZATION +``` + +and `main()` returns the failing setup's return code without starting a +listener. Resolve this before step 5 — an install that completes cleanly will +still not start. + +The two routes are not equivalent in one respect that matters if you ever have +to debug HTTPD. An **APF entry** authorises the job step *before* program fetch, +so MVS loads HTTPD into subpool 252 **key 0** — authorised code must not be +patchable by problem-key code. **SVC 244** sets `JSCBAUTH` *after* the fetch and +cannot relabel storage that is already allocated, so the module stays key 8. +HTTPD runs problem state key 8 either way, which means that under an APF entry +it must never store into its own module storage. It does not, as of 4.0.0: the +server block is `main()`'s automatic storage, and the state that used to be +file-scope — the codepage pair, the saved STC ACEE, the Basic realm — lives +there with it (issue #197). + +You do not have to work out which route you got: HTTPD says so at startup, on +the line after the version banner. + +``` +HTTPD002I AUTHORIZED BY LIBRARY (MODULE KEY 0) APF list entry +HTTPD002I AUTHORIZED BY SVC (MODULE KEY 8) SVC 244, from RAKF +``` + +The key is inferred from the route rather than measured — an authorised job step +has its module fetched key 0, an unauthorised one key 8, and SVC 244 arrives too +late to change either. Neither line is a warning: both routes end in an +authorised started task, and which one you want is a site decision. Quote the +line in a bug report — it decides the storage key HTTPD's own module runs in. + +--- + +## 3. Upload the two XMIT files + +Both `.xmit` files are EBCDIC NETDATA streams. Upload them **in binary** — no +ASCII/EBCDIC translation, no CRLF conversion — into sequential datasets with +`RECFM=FB LRECL=80 BLKSIZE=3120`. + +**The dataset names are yours to choose.** The install job names them on its +own `RECEIVE` commands, so nothing depends on what you call them; you will +enter them once in step 6. This guide uses `IBMUSER.HTTPD.LOAD.XMIT` and +`IBMUSER.HTTPD.SAMP.XMIT`. + +Whether you have to allocate them first depends on the upload path: **FTPD** +and **IND$FILE** create the dataset from the attributes you supply, mvsMF and +most other FTP servers need it to exist. Where a method says *pre-allocate*, +allocate both as `DSORG=PS, RECFM=FB, LRECL=80, BLKSIZE=3120`, primary ~50 +tracks, secondary 20 (TSO or ISPF 3.2). + +Pick **one** method: + +### a) FTP — mvslovers/ftpd (no pre-allocation) + +FTPD creates the datasets from the attributes it is given (default port 2121): + +``` +ftp -P 2121 your-mvs-host +> binary +> put httpd--load.xmit 'IBMUSER.HTTPD.LOAD.XMIT' +> put httpd--samplib.xmit 'IBMUSER.HTTPD.SAMP.XMIT' +> quit +``` + +This is also the upload path to prefer when you are **upgrading**: the HTTPD you +are replacing is the one serving mvsMF, so uploading through mvsMF means +uploading through the thing you are about to stop. + +### b) mvsMF (z/OSMF-compatible REST API), via zowe + +Only when a *different* server is up, or you are not replacing this one. It +requires the datasets to **exist first**, so *pre-allocate*, then: + +``` +zowe zos-files upload file-to-data-set httpd--load.xmit \ + "IBMUSER.HTTPD.LOAD.XMIT" --binary +zowe zos-files upload file-to-data-set httpd--samplib.xmit \ + "IBMUSER.HTTPD.SAMP.XMIT" --binary +``` + +### c) Another FTP server (pre-allocate) + +*Pre-allocate* both datasets, then transfer **binary** into them — a plain +`binary` + `put`. Any `SITE` keywords for dataset attributes vary between +MVS 3.8j TCP/IP stacks (they are **not** the z/OS syntax); pre-allocating makes +them unnecessary. + +### d) IND$FILE (3270 emulator) + +No pre-allocation needed. Use your emulator's file transfer in **binary** mode +(no ASCII/CRLF translation) with `RECFM=FB LRECL=80 BLKSIZE=3120`. The exact +option syntax is client-dependent — consult its file-transfer documentation. + +--- + +## 4. Allocate the product datasets + +Submit `httpd--alloc.jcl` unchanged, unless you want a specific unit or +volume — the `UNIT=SYSDA` and the space on each DD are the only things worth +editing. + +It creates `HTTPD..LINKLIB` and `HTTPD..AHTTPLOD` and nothing else. +The libraries the next step receives into are deliberately **not** allocated +here: TSO RECEIVE creates its own target and refuses to merge into an existing +dataset. + +Expect `COND CODE 0000`. + +> **Run this once.** There is no DELETE step in it, on purpose. After the +> install, `HTTPD..AHTTPLOD` holds SMP's accepted copy of the modules; a +> re-run that scratched it would leave the SMP inventory reporting an install +> that is no longer on the system, and nothing would say so. To start over, +> reject the SYSMOD first — see [Removing HTTPD](#11-removing-httpd). + +--- + +## 5. Stop a running HTTPD + +Only relevant when you are upgrading. The APPLY writes into +`HTTPD..LINKLIB`, and each release has its own — so a running *older* HTTPD +does not block the install. It does, however, keep running the old modules until +you restart it (step 9) against the procedure you copy in step 7. + +``` +/P HTTPD +``` + +Two things worth knowing before you do: + +- **HTTPD refuses to start a second instance on a port already served** + (`HTTPD037E`), so a forgotten `/P` becomes a refused start rather than a + confusing half-working one. That check is keyed by port, so a deliberate + second server on another port still starts — which is a good way to try a new + build without touching the running one. +- If mvsMF is your upload or console channel, stopping HTTPD takes it with it. + Have another way in (FTPD, TSO, the Hercules console) before you stop the + server. + +--- + +## 6. Install + +Open `httpd--inst.jcl` and replace the two placeholder dataset names +with what you uploaded in step 3: + +``` + RECEIVE INDSN('CHANGE.ME.HTTPLOAD') - <- IBMUSER.HTTPD.LOAD.XMIT + RECEIVE INDSN('CHANGE.ME.SAMPLIB') - <- IBMUSER.HTTPD.SAMP.XMIT +``` + +Those are the only lines you have to change. Submit it. + +The job runs eight steps, each conditional on the one before, so it stops at +the first failure rather than building on it: + +| Step | What it does | +|------|--------------| +| `DELOLD` | scratches the RECEIVE targets, so the job can be re-run | +| `RECV1` | load XMIT → `HTTPD..HTTPLOAD` (a staging library) | +| `RECV2` | samplib XMIT → `HTTPD..SAMPLIB` | +| `RECV` | receives the SYSMOD into the SMP inventory | +| `APPLYCHK` | dry run — `APPLY` only proceeds if this ends RC 0 | +| `APPLY` | copies the five load modules into `HTTPD..LINKLIB` | +| `ACCEPT` | makes this level the base a later `RESTORE` returns to | +| `CLEANUP` | scratches the staging library, which is now spent | + +The SYSMOD travels inline in the job — there is no third file to upload. + +**What a good run looks like.** Every step `COND CODE 0000`, and in the SMP +output: + +``` +HMA3930 SYSMOD THTP400 SUCCESSFULLY RECEIVED +HMA2380 COPY SUCCESSFUL - MOD=HTTPD - LMOD=HTTPD - LIBRARY=LINKLIB + - RETURN CODE=00 +HMA2050 APPLY PROCESSING COMPLETED - HIGHEST RETURN CODE IS 00 +``` + +There is one `HMA2380` line **per module** — five of them. A run that copies +fewer has lost one, and the `APPLY` still ends RC 00, so count them. + +Then check `HTTPD..LINKLIB` really holds all five (ISPF 3.4). Do look: SMP +reports the library by **ddname**, and a ddname says nothing about which dataset +was behind it. + +SMP **copies** these modules rather than re-binding them, which is why the +`AC(1)` authorisation code on `HTTPD` and every module's custom entry point are +exactly what the build produced. + +--- + +## 7. Install the procedure and the configuration + +SMP does not touch your PROCLIB or PARMLIB, and that is deliberate: **the +product owns the patterns, your system owns the copies.** If SMP owned the +running procedure, every change you made to it would be silently replaced by +the next update. So this step is yours, and it is the one place where you have +to read what you are copying. + +Copy from `HTTPD..SAMPLIB`: + +| Member | Copy to | Adjust | +|--------|---------|--------| +| `HTTPD` | a PROCLIB in the started-task concatenation | usually not — `STEPLIB` already names this release's LINKLIB. Add mvsMF's library to it if you use mvsMF | +| `HTTPPRM0` | a PARMLIB | **yes — see below** | + +`SYS2.PROCLIB` is the usual home for the procedure. + +### Which PARMLIB + +The shipped procedure defaults to `D='SYS2.PARMLIB'`. **On TK5 that dataset +does not exist** — put the member in `SYS1.PARMLIB` and either edit `D=` in +your copy of the procedure, or override it when starting: + +``` +/S HTTPD,D='SYS1.PARMLIB' +``` + +On MVS/CE, `SYS2.PARMLIB` exists and the default is fine. `M=` selects the +member (default `HTTPPRM0`), so a second configuration can live alongside the +first. + +### The STC identity — `STCUSER` and `STCGRP` + +The shipped procedure logs the server on to `HTTPD/USER` at startup: + +``` +// STCUSER=HTTPD, +// STCGRP=USER +//HTTPD EXEC PGM=HTTPD,REGION=8M,TIME=1440, +// PARM='STCUSER=&STCUSER STCGROUP=&STCGRP' +``` + +RAKF has no started-procedures table: it decides only *that* a caller is an STC, +never *which* one, and hands every started task the same `STC/STCGROUP` account +— which on a stock profile set holds **ALTER on every dataset on the system**. +So HTTPD replaces it with a dedicated identity of its own (issue #177). Define +that userid in step 8. + +Two traps if you write your own procedure: + +- The START symbolic is `STCGRP` while the keyword the program parses is + `STCGROUP=` — a JCL symbolic parameter name is at most seven characters. +- `__start()` splits the PARM into `argv` on **blanks, not commas**. Joining the + two keywords with a comma hands the whole string to `STCUSER=`, and the group + is then silently wrong. + +If the logon fails the server **continues** on the inherited identity and says +so with `HTTPD004W`, so a profile typo is not an outage — but it is also not +what you asked for. Watch for that message where you expect `HTTPD004I`. + +### The DD statements — do not add SYSPRINT, SYSTERM or SYSIN + +HTTPD writes its own STDOUT/STDERR and reads STDIN through private DDs +(`HTTPDOUT`, `HTTPDERR`, `HTTPDIN`) so that a module cannot scribble into the +JES datasets an operator reads. The three conventional names are **refused**, +before `main()` runs: + +``` +HTTPD014E SYSPRINT DD NOT ALLOWED, HTTPD USES HTTPDOUT FOR STDOUT +HTTPD015E SYSTERM DD NOT ALLOWED, HTTPD USES HTTPDERR FOR STDERR +HTTPD016E SYSIN DD NOT ALLOWED, HTTPD USES HTTPDIN FOR STDIN +``` + +The shipped procedure already has the right set. Leave it alone unless you know +why you are changing it. + +### Editing HTTPPRM0 + +Every keyword in the shipped member is commented out, so a member copied +unchanged runs on the built-in defaults — **port 8080, document root `/www`** — +plus the three active `MOD=MVSMF` route lines. Four things are worth a look +before the first start: + +``` +PORT=8080 +DOCROOT=/www +REALM=MVS Development System +MOD=MVSMF /zosmf/* AUTH=TOKEN +``` + +- `PORT` is 8080 by default. Nothing on a stock MVS 3.8j contends for it. +- `DOCROOT` is a **UFS path**, and it must exist in a mounted UFSD filesystem. + Without UFSD, leave it and expect `HTTPD044W` (step 2). +- `REALM` defaults to the system's SMF ID — unambiguous, but meaningless to a + user. It is what a browser shows in its Basic credential dialog. +- The `MOD=MVSMF` lines are the ones to review first. Comment them out if you + have no mvsMF. + +**Read the auth model before you publish anything.** Authentication is declared +per route and nowhere else — there is no server-wide login keyword, and the +`LOGIN` keyword of earlier versions is retired: + +``` +MOD=MVSMF /zosmf/* AUTH=TOKEN program route, gated +LOC=/admin/* AUTH=BASIC static prefix, gated +LOC=/* AUTH=NONE static prefix, public on purpose +``` + +- **A route without `AUTH=` is public**, and so is any path no route claims at + all. There is no global default left to fall back on. +- The modes are `NONE`, `FORM` (HTML login form), `BASIC` (401 + + `WWW-Authenticate`) and `TOKEN` (a bare 401 for API clients that handle it + themselves). A value that is none of these refuses the route and the server + **does not start** — `HTTPD411E` then `HTTPD420E`. That is on purpose: a + policy silently weakened is worse than a server that will not start. +- `AUTH=` does not select which credentials are accepted. Every route accepts + all of them, because they are resolved before the route is matched. It selects + *whether* a login is needed and *how* a missing one is challenged. +- A member still carrying `LOGIN=ALL` / `CGI` / `GET` / `HEAD` / `POST` is a + **fatal** configuration error (`HTTPD048E`), because ignoring it would publish + every route without an `AUTH=` of its own. `LOGIN=NONE` was the default and is + merely warned about (`HTTPD048W`). Convert to `AUTH=` per route, then delete + the line. + +The display modules deserve their own warning. `MOD=HTTPDM /.dm` with no `AUTH=` +hands anyone who can reach the port arbitrary storage reads, and `/.dmtt` hands +them the console log. If you enable them, gate them: + +``` +MOD=HTTPDSRV /.dsrv AUTH=FORM +MOD=HTTPDM /.dm AUTH=BASIC +MOD=HTTPDMTT /.dmtt AUTH=BASIC +``` + +A `#` or `*` in the first column comments a line out. The full keyword reference +is [configuration.md](https://github.com/mvslovers/httpd/blob/main/docs/configuration.md). + +--- + +## 8. Set up RAKF + +Without this, HTTPD cannot authorise itself and does not start (step 2), and no +client can log in. + +1. Add the `HTTPD` user to `SYS1.SECURE.CNTL(USERS)`, default group `USER`: + + ``` + HTTPD USER DEFAULT-GROUP(USER) + ``` + + This is the identity from `STCUSER`/`STCGRP` in step 7. It needs **READ** on + whatever HTTPD itself opens before a client identity exists: the PARMLIB + member, the document root, the log DDs. + + It does **not** need `FACILITY SVC244`. HTTPD acquires APF authorisation at + start and releases it at `/P HTTPD`, and it restores the STC account it + started under immediately before the release — so both SVC 244 calls are made + by the same account, rather than requiring the profile on every system. + +2. Optionally define profiles for any route that carries `RES=class:resource`. + A `RES=` naming a resource **no profile covers** is not an error and does not + deny: SAF calls an unprotected resource allowed, so the authorisation stage + does nothing and only the `AUTH=` stage is left. HTTPD says so at startup: + + ``` + HTTPD425W NO PROFILE FOR FACILITY:HTTPD.ADMIN -- /admin/* NOT GATED + ``` + +3. Reload: `/F RAKF,RELOAD` + +--- + +## 9. Start and verify + +``` +/S HTTPD default member (HTTPPRM0) +/S HTTPD,M=HTTPPRM1 alternate config member +/S HTTPD,D='SYS1.PARMLIB' alternate PARMLIB -- TK5, see step 7 +``` + +A healthy start ends in `HTTPD001I … READY`: + +``` +HTTPD000I HTTPD (A69A370) STARTING +HTTPD005I LIBC370 1.0.3 (58767B3) +HTTPD002I AUTHORIZED BY SVC (MODULE KEY 8) +HTTPD004I STC IDENTITY SET TO HTTPD/USER VIA RACINIT +HTTPD036I MODULE MVSMF REGISTERED FOR /zosmf/info +HTTPD036I MODULE MVSMF REGISTERED FOR /zosmf/* +HTTPD054I LISTENING ON ANY PORT 8080 +HTTPD061I STARTING SOCKET THREAD TCB(9CD9D0) TASK(10CFC8) STACKSIZE(32768) +HTTPD061I STARTING WORKER(11ED48) TCB(9CD420) TASK(120FC8) STACKSIZE(65536) +HTTPD001I HTTPD READY - SERVING /www +``` + +That transcript is a system with UFSD running. Without it, `HTTPD044W` appears +between `HTTPD004I` and `HTTPD054I` — and the last line still reads +`SERVING /www`, because it names the configured document root rather than a +working filesystem (step 2). + +The two build stamps identify exactly what is running: `HTTPD000I` gives the +version and the commit it was built from, `HTTPD005I` the libc370 it was linked +against — quote both in a bug report. A build made from a modified working tree +marks its hash `-DIRTY` and adds `HTTPD006W`; a released build never does. + +**The configuration is not echoed at startup** — not the member, not the +codepage, not the task limits. `/F HTTPD,D CONFIG` reports all of it on demand, +and that one look after the first start is worth taking: it prints what HTTPD +*parsed*, not what the member says, so a typo that fell back to a default is +visible there and nowhere else. + +**A refused start is recognised by the step return code, never by a console +string.** A start refused by initialisation ends `CC 0008`; a clean `/P HTTPD` +ends `CC 0000`. The first console line is the cause (`HTTPD037E`, `HTTPD028E`, +`HTTPD030E`, `HTTPD031E`, `HTTPD420E`, `HTTPD033E` or `HTTPD090E`); everything +under it is the ordinary stop sequence and says nothing about what went wrong. +The full contract is in +[messages.md](https://github.com/mvslovers/httpd/blob/main/docs/messages.md). + +Then reach it from a client: + +``` +curl -v http://your-mvs-host:8080/zosmf/info mvsMF installed +curl -v http://your-mvs-host:8080/ static, needs UFSD +``` + +Operator commands: + +``` +/F HTTPD,DISPLAY Config the configuration actually in effect (D C) +/F HTTPD,DISPLAY Stats request/error/byte counters, SMF level (D S) +/F HTTPD,DISPLAY Threads the worker pool, block by block (D T) +/F HTTPD,DISPLAY Ports the listening port (D P) +/F HTTPD,DISPLAY Login who is logged in (D L) +/F HTTPD,DISPLAY Version build stamps again (D V) +/F HTTPD,DISPLAY TIme server time and offset (D TI) +/F HTTPD,DISPLAY Memory xxxxxx[,nnn] (D M) +/F HTTPD,SET MIntask n resize the worker pool +/F HTTPD,SET MAxtask n +/F HTTPD,SET Stats NONE|ERROR|AUTH|ALL [RESET] +/F HTTPD,HELP every MODIFY command +/P HTTPD orderly stop (HTTPD099I SHUTDOWN COMPLETE) +``` + +Commands abbreviate to the capitalised prefix, which is why `DISPLAY Threads` +and `DISPLAY TIme` need one and two letters respectively. + +--- + +## 10. What HTTPD serves + +Two kinds of route, both declared in the configuration member, both carrying the +same per-route auth policy: + +- **`MOD=` — a program.** An MVS load module dispatched on the worker thread's + own TCB through the LINK SVC, once per request. mvsMF is the one that matters + in practice; the three display modules ship with the server. +- **`LOC=` — a static prefix.** No program: the request falls through to the + static file handler on `DOCROOT`, but the prefix still carries `AUTH=`/`RES=`. + This is how a static subtree gets a login without a CGI. + +Routes are tested **in order** and matched exactly unless they carry a `*`, so +list specific prefixes before a catch-all — a `LOC=/*` placed above +`MOD=MVSMF /zosmf/*` shadows it. + +HTTP/1.1 with persistent connections and chunked transfer encoding is the +default for 1.1 clients; 1.0 clients always get `Connection: close`. + +The full reference is +[configuration.md](https://github.com/mvslovers/httpd/blob/main/docs/configuration.md); +writing your own module is +[development.md](https://github.com/mvslovers/httpd/blob/main/docs/development.md). + +--- + +## 11. Removing HTTPD + +Because the installation is SMP-managed, there is a defined way back — but it is +**not** the `RESTORE` followed by `REJECT` that SMP documentation leads you to +expect. The install job accepts the FMID in the same run as the APPLY, and an +accepted function SYSMOD refuses both: `RESTORE` because it was accepted, +`REJECT` because accepting removed from `SYS1.SMPPTS` the control statements it +works from. The route that does work is a `UCLIN` job. + +What this release put on the system: + +| | | +|---|---| +| FMID | `THTP400` | +| Load modules | `HTTPD`, `HTTPDSRV`, `HTTPDM`, `HTTPDMTT`, `ABEND0C1` | +| Target library | `HTTPD..LINKLIB` | +| Distribution library | `HTTPD..AHTTPLOD` | +| Sample library | `HTTPD..SAMPLIB` | + +**1. Stop the server:** `/P HTTPD` + +**2. Cut the FMID out of the SMP inventory.** Submit this — it edits the CDS and +the ACDS and touches no library: + +``` +//HTTPDUCL JOB (SYS),'HTTPD UNINSTALL', +// CLASS=A,MSGCLASS=H,MSGLEVEL=(1,1), +// REGION=4096K +//UCLIN EXEC SMPAPP +//SMPCNTL DD * + UCLIN CDS . + DEL SYSMOD(THTP400) MOD(HTTPD) . + DEL SYSMOD(THTP400) MOD(HTTPDSRV) . + DEL SYSMOD(THTP400) MOD(HTTPDM) . + DEL SYSMOD(THTP400) MOD(HTTPDMTT) . + DEL SYSMOD(THTP400) MOD(ABEND0C1) . + DEL MOD(HTTPD) . + DEL MOD(HTTPDSRV) . + DEL MOD(HTTPDM) . + DEL MOD(HTTPDMTT) . + DEL MOD(ABEND0C1) . + DEL LMOD(HTTPD) . + DEL LMOD(HTTPDSRV) . + DEL LMOD(HTTPDM) . + DEL LMOD(HTTPDMTT) . + DEL LMOD(ABEND0C1) . + DEL SYSMOD(THTP400) . + ENDUCL . + UCLIN ACDS . + DEL SYSMOD(THTP400) MOD(HTTPD) . + DEL SYSMOD(THTP400) MOD(HTTPDSRV) . + DEL SYSMOD(THTP400) MOD(HTTPDM) . + DEL SYSMOD(THTP400) MOD(HTTPDMTT) . + DEL SYSMOD(THTP400) MOD(ABEND0C1) . + DEL MOD(HTTPD) . + DEL MOD(HTTPDSRV) . + DEL MOD(HTTPDM) . + DEL MOD(HTTPDMTT) . + DEL MOD(ABEND0C1) . + DEL SYSMOD(THTP400) . + ENDUCL . +/* +//LIST EXEC SMPAPP +//SMPCNTL DD * + RESETRC . + LIST CDS SYSMOD(THTP400) . + LIST ACDS SYSMOD(THTP400) . +/* +// +``` + +Every `DEL` reports `HMA2550 UPDATE COMPLETE`, and each `UCLIN` block ends +`RC 00`. + +**3. Read the LIST — this is the actual result.** Both zones must answer: + +``` +THE FOLLOWING SELECTED ENTRIES WERE NOT FOUND OR WERE NOT ELIGIBLE +FOR PROCESSING + TYPE NAME + SYSMOD THTP400 +``` + +with `HIGHEST RETURN CODE IS 04`. **RC 04 and an empty list means the FMID is +free.** Both zones matter: the CDS records what is applied, the ACDS what is +accepted, and they are separate inventories — an id gone from one and present in +the other is not free. + +**4. Scratch the libraries.** `UCLIN` edits the inventory only; both datasets are +still there, and a re-install's allocation job would fail on them: + +``` + DELETE HTTPD..LINKLIB NONVSAM SCRATCH PURGE + DELETE HTTPD..AHTTPLOD NONVSAM SCRATCH PURGE +``` + +Leave `HTTPD..SAMPLIB` alone if you like — the install job's `DELOLD` step +scratches it on its own. + +**5. What is not removed, because SMP never owned it:** the procedure and the +configuration member you copied in step 7, and your RAKF definitions. Those are +yours to delete. + +> The `RESTORE`/`REJECT` behaviour above was measured on 2026-08-14 against an +> accepted FMID from a package built by this same generator, on an MVS/CE system +> running SMP 4 level 04.48. It is a property of SMP 4 and of accepting a +> function SYSMOD, not of any one product — but the `UCLIN` job above has not +> itself been run against `THTP400`. Read the `LIST` output rather than trusting +> the `DEL` cards. + +--- + +## Troubleshooting + +| Symptom | Likely cause | +|---------|--------------| +| Allocation job fails, dataset already exists | It was already run. Do not force it — see the warning in step 4 | +| `RECV1`/`RECV2` fails, target exists | Something else allocated it. RECEIVE refuses to merge; scratch it and re-run | +| `APPLYCHK` ends non-zero, `APPLY` skipped | Read the SMP output — the check exists to stop before anything is written. A missing DD is the usual cause | +| `APPLY` RC 00 but fewer than five `HMA2380` lines | A module was lost. Count them, then look in the library itself | +| SMP reports success, but a module is not where you expected | A ddname says nothing about the dataset behind it. Check the JCL, then look at the library itself | +| `S806` (module not found) at `/S HTTPD` | `STEPLIB` in the procedure does not name the LINKLIB the APPLY wrote to | +| `/S HTTPD` rejected — procedure not found | Procedure not copied into a PROCLIB in the started-task concatenation | +| `HTTPD012E … UNABLE TO DYNAMICALLY OBTAIN APF AUTHORIZATION`, no listener | No RAKF (so no SVC 244) and no APF entry — step 2. This one is fatal, not a warning | +| `HTTPD014E`/`015E`/`016E` and the step ends before any banner | A `SYSPRINT`, `SYSTERM` or `SYSIN` DD in the procedure — step 7 | +| `HTTPD037E HTTPD IS ALREADY ACTIVE ON PORT n` | An older instance still holds the port. `/P HTTPD` first — step 5 | +| `HTTPD004W RACINIT ENVIR=CREATE FAILED` | The `STCUSER`/`STCGRP` userid is not defined to RAKF — step 8. Not fatal; the server runs on the inherited STC identity | +| `HTTPD044W UNABLE TO INITIALIZE FILE SYSTEM` | UFSD is not running. Module routes are unaffected; only static files fail — step 2. `HTTPD001I` still names the configured `DOCROOT`, so it is not the line to read here | +| `HTTPD908E EXTERNAL PROGRAM MVSMF …` on every `/zosmf/` request | mvsMF is not in the STC's STEPLIB — step 2. The parenthetical "(not found in STEPLIB?)" is a guess; the real abend code is in the `IEA703I` line beside it, and `106-0F` means storage, not a missing member | +| `HTTPD420E ROUTE AUTHORIZATION POLICY INCOMPLETE`, `CC 0008` | A route's `AUTH=` value is not `NONE`/`FORM`/`BASIC`/`TOKEN`, or a `LOGIN=` line survives in the member — step 7 | +| `HTTPD425W NO PROFILE FOR …` | A `RES=` names a resource no RAKF profile covers, so that route is gated by `AUTH=` alone — step 8 | +| A route answers `200` to anyone | It carries no `AUTH=`, or no route claims the path at all. Both are public by design — step 7. `/.dsrv?target=MOD` prints the policy each route actually got | +| `401` on a route showing `AUTH=NONE` | Not HTTPD's gate. mvsMF runs its own auth track on `/zosmf/*` — establish which layer answered before debugging HTTPD's | +| `S106` at start on a freshly installed library | The XMIT was uploaded in text mode. Re-upload in **binary** and re-run the install job | +| The step ends `CC 0000` but nothing was ever served | A clean `/P HTTPD` and a refused start are `CC 0000` and `CC 0008`. If it is 0000, the server ran — look for what stopped it | + +For the complete message reference, see +[messages.md](https://github.com/mvslovers/httpd/blob/main/docs/messages.md). diff --git a/mbt.lock b/mbt.lock index becc950..9f6ea16 100644 --- a/mbt.lock +++ b/mbt.lock @@ -1,6 +1,6 @@ { "mvslovers/ufsd": { - "sha256": "a64fb1510760565890c714074cd7bcb5bdb2283c3e78c4b771cc7070d3cc0078", - "version": "1.2.0" + "sha256": "3efc6ed09d63cb06afd8b6adf4e411d85efd48511cca266f0ada7b5560ebd5b0", + "version": "1.2.1" } } diff --git a/project.toml b/project.toml index 3f272a9..ad75ee0 100644 --- a/project.toml +++ b/project.toml @@ -13,7 +13,7 @@ type = "application" # first 1.0.0 attempt shipped reporting an unreleased runtime nobody could # reproduce from a tag. HTTPD005I names the runtime it linked against, so an # unpinned release build makes that line unreproducible in exactly the same way. -libc370 = "1.0.2" +libc370 = "1.0.3" [build] # The build stamp behind HTTPD000I/001I/006W is not injected here: mbt @@ -49,7 +49,7 @@ cflags = [ cflags = ["-Wno-error"] [dependencies] -"mvslovers/ufsd" = ">=1.2.0" +"mvslovers/ufsd" = ">=1.2.1" # -- Internal autocall archive ------------------------------------ # All of httpd's objects, archived into build/httpdint.a. Every module @@ -282,5 +282,91 @@ headers = [ "include/types.h", ] +# -- Distribution (SMP4 install package) -------------------------- +# Turns `make package` into an installable product, the same two transports +# ufsd and ftpd ship with: +# +# load modules -> XMIT -> staging HTTPLOAD -> SMP ++MOD -> HTTPD..LINKLIB +# samplib/ -> XMIT -> TSO RECEIVE -> HTTPD..SAMPLIB +# +# SMP *copies* the host-bound modules rather than re-binding them (a COPY-style +# ++JCLIN is what says so), which is what keeps HTTPD's ac = 1 and every custom +# entry point exactly as ld370 set them. The sample library stays outside SMP: +# an MCS card ends at column 72 and HTTPPRM0 has comment lines reaching column +# 80, so routing the configuration pattern through the SYSMOD would make it +# answer to a delivery mechanism. The datasets are versioned, so every release +# brings a fresh SAMPLIB anyway -- there is no in-place update for SMP to +# manage. +# +# samplib/httpd carries @LINKLIB@ in its STEPLIB, which mbtdist replaces with +# the versioned target while staging -- the same placeholder ufsd's and ftpd's +# procs use, and the reason the shipped proc points at the library SMP actually +# installed into rather than at a name fixed when the file was written. Do not +# mention a placeholder in a nearby comment: the substitution runs over the +# whole member, and a 21-character dataset name landing in a comment line is how +# a proc that fit an FB-80 card stops fitting one. +# +# Every value is a dataset name; the ddname SMP addresses it by is always the +# last qualifier, so LINKLIB, SAMPLIB, HTTPLOAD and AHTTPLOD fall out of the +# names. @VRM@ becomes V4R0M0 at package time (V4R0M0D while the version still +# carries -dev). ufsd/ftpd spell these LOAD / ALOD, which for +# a five-letter product would be nine characters; HTTPLOAD/AHTTPLOD keeps the +# suffix and drops the letter, rather than keeping HTTPD and truncating the +# suffix (HTTPDLOD/AHTTPDLD). Both names go into the FMID's JCLIN, so this is a +# one-shot choice -- changing it later is a new functional level. +# +# All five [[module]] entries ship, ABEND0C1 included: mbtdist packages every +# module and offers no exclude. Deliberate rather than overlooked -- since +# 4.0.0 a module is inert unless a Parmlib route names it, and the shipped +# HTTPPRM0 leaves its /.abend line commented out. It is the acceptance vehicle +# for the storage reclaim (#154/#174), and a diagnostic that is present but +# unreachable is worth more than one an operator would have to rebuild to use. +[distribution] +# Shipped into the archive as README.md, which is the name the generated install +# job points at ("See the README for which member goes where"). Without it the +# package tells the operator to read a file it does not contain. +readme = "docs/installation.md" + +[distribution.smp] +# One FMID per minor release, spent exactly once: it names a functional level, +# and a changed one is a new level. Patches on top of it ship as PTFs. 4.0.x +# is THTP400; a later 4.1.0 becomes THTP410 and is installed as a clean cut +# (RESTORE + REJECT the old, then receive the new). The T stays clear of the +# E??nnnn namespace MVS 3.8j's own function SYSMODs occupy (EBB1102 is 3.8j +# itself, alongside EAS1102, EBT1102, EDE1102, ...). +# +# NOT yet verified the way TFTP100 and TUFS120 were, and the difference matters. +# What is measured is the SMPPTS on mvsdev -- 1544 SYSMODs scanned, no THTP400 +# (smp-todo.md §2) -- and the PTS shows only what was *received*. The CDS and +# ACDS store hashed member names, so LIST CDS SYSMOD(THTP400) and LIST ACDS +# SYSMOD(THTP400) are the only way to see what is actually applied or accepted. +# Both stands (mvsdev, drnmig3a) still have to answer RC 04 with an empty list +# before the 4.0.0 tag. A test install must use a throwaway id -- a +# half-applied FMID leaves this one occupied, and smp-todo.md reserves TTST400 +# for exactly that. +fmid = "THTP400" +system = "Z038" + +# Empty despite the [dependencies] entry on ufsd, which is a *build* time one: +# libufs is linked statically, so nothing of ufsd has to be installed for the +# load modules to run. At run time it is soft even though 4.0.0 serves static +# files from UFS and nowhere else: ufs_sys_init() failing is HTTPD044W and the +# server keeps running, so every MOD= route -- mvsMF, the display modules -- +# works on a system with no UFSD at all. REQ(TUFS120) would therefore refuse +# the install wherever UFSD is absent, for a facility that already degrades on +# its own. The installation guide documents UFSD as an optional runtime +# prerequisite instead, which is also how ufsd itself treats RAKF. +prereq = [] + +accept_fmid = true # accept the FMID once so a PTF can be RESTOREd +lklib = "HTTPD.@VRM@.HTTPLOAD" # staging: what the load XMIT is received into +target = "HTTPD.@VRM@.LINKLIB" # where the load modules end up +distlib = "HTTPD.@VRM@.AHTTPLOD" + +[[distribution.library]] +dir = "samplib" +target = "HTTPD.@VRM@.SAMPLIB" + +# -- Release ------------------------------------------------------ [release] version_files = ["VERSION"] diff --git a/samplib/httpd b/samplib/httpd index 9af317c..a61d55e 100644 --- a/samplib/httpd +++ b/samplib/httpd @@ -36,7 +36,7 @@ //* PARM is space-separated: __start() splits argv on blanks, not commas. //HTTPD EXEC PGM=HTTPD,REGION=8M,TIME=1440, // PARM='STCUSER=&STCUSER STCGROUP=&STCGRP' -//STEPLIB DD DISP=SHR,DSN=HTTPD.LINKLIB +//STEPLIB DD DISP=SHR,DSN=@LINKLIB@ //SYSUDUMP DD SYSOUT=* //HTTPDERR DD SYSOUT=* //HTTPDOUT DD SYSOUT=* From ff819cdf86767efc85047f5fbafe5e693ceb2646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Gro=C3=9Fmann?= Date: Sun, 23 Aug 2026 22:12:56 +0200 Subject: [PATCH 02/11] Reconcile smp-todo.md with the generated distribution The document planned by hand what mbt now generates, and it read as current while being wrong in several places. Its first two links -- ../SMP-COOKBOOK.md and ../SMP-INSTALLATION.md -- point at files that no longer exist. It listed six load modules including HTTPJES2 and HTTPDSL, which 4.0.0 stopped building. And its question round proposed two answers the [distribution] block settles the other way. Dropped: the spike (done 2026-08-08 in ../smptest, which proved SMP copies the LKLIB module rather than re-binding it), the MCS/JCLIN/allocation generators, and the plan to ship the sample library as ++MAC elements inside the SYSMOD -- an MCS card ends at column 72 and HTTPPRM0 has comment lines reaching 80. Recorded as reversed rather than quietly changed: - The target is HTTPD.@VRM@.LINKLIB, not SYS2.LINKLIB. Versioned product datasets mean no IPL for an APF entry and no collision with a system library, and the procedure keeps its STEPLIB. That answers the old trap T6: the SVC 244 self-authorization path stays the normal case. - ACCEPT rides along, where the old F4 said "never". Accepting the FMID fills the distribution library, which is the base a later RESTORE of a PTF returns to; without it a RESTORE would delete the module instead of reverting it. The cost is that the FMID becomes permanent and removal needs UCLIN. Service is still never accepted. What is left is what is actually open: the LIST CDS/ACDS check for THTP400 on both stands, a test install on the throwaway TTST400, the UFS webroot SMP cannot deliver, and whether to ship a setup job at all. The traps that still bite are kept; T8 and T5 are struck with the reason they no longer apply. --- smp-todo.md | 581 +++++++++++++++++++--------------------------------- 1 file changed, 213 insertions(+), 368 deletions(-) diff --git a/smp-todo.md b/smp-todo.md index ce78e5a..638d485 100644 --- a/smp-todo.md +++ b/smp-todo.md @@ -1,277 +1,110 @@ -# SMP-Installation httpd — offene Punkte und TODOs - -> **Erprobtes Rezept — hier zuerst nachsehen:** [`../SMP-COOKBOOK.md`](../SMP-COOKBOOK.md) -> **Konzept, Belege und Handbuchzitate:** [`../SMP-INSTALLATION.md`](../SMP-INSTALLATION.md) -> -> Dieses Dokument beantwortet nicht *wie* SMP funktioniert — das steht dort. -> Hier steht, **was für httpd noch fehlt** und in welcher Reihenfolge es -> abgearbeitet wird. - -Ziel: eine **Testinstallation von httpd über SMP4** auf `mvsdev` — gebaut aus dem -aktuellen `4.0.0-dev`-Stand, inklusive SAMPLIB und UFS-Disk für das WWW-Root. -Sie ist die Generalprobe für das spätere Release der finalen `4.0.0`. - -Ablauf: **§1 Fragerunde → §3 Spike → §4–§6 Ausbau → §8 Abnahme.** -Die Fragen in §1 sind vor dem ersten Schreibzugriff zu klären; §2 listet, was -bereits verifiziert ist und **nicht neu hergeleitet werden muss**. - -> **Test ≠ Release.** `project.toml` steht auf `4.0.0-dev` — das ist der laufende -> Entwicklungsstand. Über SMP ausgeliefert wird später die finale, getaggte -> `4.0.0`. Die Testinstallation baut also aus einem Baum, der nicht das Release -> ist, und **muss deshalb ein Wegwerf-FMID benutzen** (`TTST400`). -> -> Warum das kein Detail ist: SMP führt sein Inventar im CDS. Ein Testlauf unter -> `THTP400`, der abbricht, halb angewendet wird oder aus einem `-dev`-Stand -> stammt, hinterlässt genau diese ID als belegt — und das echte 4.0.0 müsste -> dann gegen die eigenen Reste installiert werden. `THTP400` wird erst vom -> getaggten Release vergeben, und zwar genau einmal. +# SMP-Installation httpd — was noch offen ist ---- - -## 1. Fragerunde — vor dem ersten Schritt zu klären - -| # | Frage | Vorschlag | blockiert | -|:--:|---|---|---| -| **F1** | **Wohin installiert SMP die Loadmodule?** Im Repo stehen drei Ziele nebeneinander: `make deploy` landet mangels `[deploy]`-Abschnitt auf `IBMUSER.HTTPD.V4R0M0.LINKLIB`, `samplib/httpd` hat `STEPLIB DD DSN=HTTPD.LINKLIB`, das Konzept schlägt `SYS2.LINKLIB` vor. | **`SYS2.LINKLIB`** — gemessen: APF-autorisiert *und* im LNKLST (§2). Die Proc bräuchte dann keinen STEPLIB mehr, und httpds Selbstautorisierung würde entfallen — **im Experiment beobachten**, s. T6 | JCLIN, DD-Override, Proc-Muster | -| **F2** | **FMID?** Muss 7 Zeichen haben und darf nicht kollidieren. `THTP400` ist im **SMPPTS frei** (1544 SYSMODs geprüft, §2) und passt zur lokalen Konvention. Restrisiko: das **CDS** ist nicht abfragbar, ein längst akzeptiertes SYSMOD könnte dort stehen, ohne im PTS zu sein. | `THTP400` übernehmen; Gewissheit nur über einen SMP-`LIST SYSMODS`-Job | alles | -| **F3** | **HLQ und Volume** für die Produkt-Datasets (DLIB, SAMPLIB, LKLIB)? | `SYS2.HTTPD.*`, Volume wie `MBT_MVS_DEPS_VOLUME` | Allokationsjob | -| ~~F4~~ | ~~ACCEPT mitfahren?~~ **Entschieden: nein, nie.** ACCEPT nimmt `RESTORE` weg und blockiert das erneute Empfangen desselben FMID mit geändertem Inhalt. Begründung und Konsequenzen: `../SMP-COOKBOOK.md` §5.1 | — | — | -| **F5** | **Schreibfreigabe für `mvsdev`** — und ist ein Backup von `SYS1.SMPCDS`/`SMPPTS` vorhanden? | Backup vor dem ersten RECEIVE; Wegwerf-FMID hinterher `REJECT`en | Spike | -| **F6** | **UFS: eigene Disk für `/www`** oder in ein bestehendes Dateisystem mounten? Welcher `UFSDPRMx`-Member? | eigene Disk `HTTPD.WEBROOT`, `MOUNT … PATH(/www) MODE(RO)` | Setup-Job | -| **F7** | **Port für den Test?** Default ist 8080. | 8080, sofern frei | Konfigmuster | -| **F8** | **SAMPLIB: eigenes Produkt-Dataset** (`SYS2.HTTPD.SAMPLIB`) oder in `SYS1.SAMPLIB`? | eigenes — sonst DD-Override-Konflikt mit dem Systemdataset | MCS, Setup-Job | -| **F9** | **Wegwerf-FMID für den Test?** `4.0.0-dev` ist der laufende Entwicklungsstand; über SMP ausgeliefert wird die finale `4.0.0`. Der Test läuft also gegen einen Baum, der **nicht** das Release ist. | **Ja** — Test auf `TTST400`, `THTP400` bleibt für das getaggte 4.0.0 reserviert. Begründung unten. | Spike, Aufräumen | - ---- - -## 2. Was bereits feststeht +**Das Paket wird generiert, nicht mehr von Hand gebaut.** `make package` erzeugt +aus dem `[distribution]`-Block in `project.toml` den SYSMOD, den Allokations- +und den Install-Job. Wie SMP4 dabei arbeitet und warum, steht in +`mbt/scripts/mbt/distribution.py` — dort sind die Handbuchstellen zitiert und +die Messungen vermerkt. Was ein Betreiber tun muss, steht in +[`docs/installation.md`](docs/installation.md). -Nicht neu herleiten, nicht neu messen. Marker wie im Konzeptdokument -(✅ Repo · 🔬 gemessen · 📘 SMP4-Handbuch). +Dieses Dokument hält nur noch das, was **für httpd offen** ist. -**Verfahren** +> *Stand: 2026-08-23, gegen `[distribution]` in `project.toml` abgeglichen.* -- `++MOD(x) LKLIB(ddname)` liefert ein **fertig gebundenes** Loadmodul; ist das - LMOD im JCLIN über einen **IEBCOPY-Step** definiert, kopiert SMP es statt zu - binden. 📘 -- DDNAMEs = letzter Qualifier des Datasetnamens. 📘 -- Copy-Input im JCLIN muss **inline** hinter `//SYSIN DD *` stehen. 📘 -- `SELECT MEMBER=(…)` verwenden — sonst gilt die DLIB als *total* kopiert - (Grenze: zwei Ziel-Bibliotheken). 📘 -- SMP4 kennt **keinen** Datentyp: nur `++MOD/MAC/SRC/MACUPD/SRCUPD/ZAP`. 📘 - -**Zielsystem `mvsdev`** - -- `SMPAPP` und `SMPREC` liegen in **`SYS2.PROCLIB`**, nicht `SYS1.PROCLIB`. 🔬 -- Beide Procs haben genau einen Step (`HMASMP`) 🔬 — **DD-Overrides müssen - trotzdem qualifiziert werden**: `//HMASMP.LINKLIB DD …`, nicht `//LINKLIB DD …`. - Und die Override-Karten müssen **vor** allen hinzugefügten DDs stehen. Siehe - Falle T9; im smptest-Spike gemessen. 🔬 -- Der Proc bringt u. a. `LINKLIB`, `LPALIB`, `PROCLIB`, `PARMLIB`, `SAMPLIB`, - `ASAMPLIB`, `MACLIB`, `CMDLIB` mit — alle auf `SYS1.*`. Wir überschreiben, - was nach `SYS2.*` soll. 🔬 -- `SYS2.LINKLIB` (20 Member) und `SYS2.PARMLIB` (9 Member) existieren. 🔬 - -**Artefaktseite** - -- 6 Loadmodule gebaut: `HTTPD` (AC=1), `HTTPJES2`, `HTTPDM`, `HTTPDMTT`, - `HTTPDSL`, `HTTPDSRV`. ✅ -- `ld370 --pack … -xmit` → `upload_binary` → `RECEIVE` läuft produktiv in - `mbt/scripts/mbtdeploy.py`. ✅ -- `ufsd-utils` ist installiert (`~/go/bin/ufsd-utils`). 🔬 - -**Zielbibliothek `SYS2.LINKLIB`** 🔬 - -Aus `SYS1.PARMLIB` gelesen — beides spricht für `SYS2.LINKLIB` als Ziel: +> **Die frühere Fassung verwies auf `../SMP-COOKBOOK.md` und +> `../SMP-INSTALLATION.md`. Beide Dateien gibt es nicht mehr.** Der Spike liegt +> noch in [`../smptest`](../smptest) — er hat 2026-08-08 gezeigt, dass SMP das +> LKLIB-Modul *kopiert* statt es neu zu binden, und genau darauf baut das +> generierte Paket auf. -``` -IEAAPF00: SYS2.LINKLIB MVS000, USER BATCH LINKLIB <- APF-autorisiert -LNKLST00: SYS2.LINKLIB, USER LOAD MODULE LIBRARY <- im Linklist -IEABLD00: nur SYS1.LINKLIB-Module (HEWL, IFOXxx, LOGON …) <- kein BLDL-Eintrag -``` +--- -- **APF:** `SYS2.LINKLIB` ist autorisiert. httpd bringt sich heute selbst in den - autorisierten Zustand (T6); von dort aus wäre es das von Anfang an. ✔ -- **LNKLST:** die Module werden ohne STEPLIB gefunden. ✔ -- **Kein IPL nötig**, damit ein *neues Member* sichtbar wird — in der residenten - BLDL-Liste (`IEABLD00`) steht nichts aus `SYS2.LINKLIB`. Vorsicht dagegen beim - **Erweitern oder Komprimieren** eines LNKLST-Datasets im laufenden Betrieb; - ausreichend Platz vorher einplanen. - -**SYSMOD-Inventar des Zielsystems** 🔬 - -`SYS1.SMPPTS` ist über die REST-API auslesbar — die Membernamen der MCS-Entries -sind **nicht** encodiert (dokumentierte Ausnahme 📘: *„With the exception of the -MCS entry in the SMPPTS dataset, these member names are encoded and cannot be -easily accessed by utilities other than SMP."*). - -- **1544 SYSMODs** liegen im PTS. Darunter die Funktions-SYSMODs des Sysgens: - `TIST801`, `TJES801`, `TMVS804`, `TMVS816`, `TMVS817`, `TNIP800`, `TTSO801` — - also dieselbe Form `T` + 3 Buchstaben + 3 Ziffern, die wir vorschlagen. -- Ebenfalls da: `RAK0001` (RAKFs Usermod). **`TRKF200` dagegen nicht** — RAKF 2.0 - als Funktion ist auf diesem System nicht empfangen. -- **Frei im PTS:** `THTP400`, `TTST400`, `TUFS100`, `TFTP100`, `TLBC100`. -- ⚠ **`TMVS100` für mvsmf nicht verwenden** — `TMVS8xx` sind die - MVS-Funktions-SYSMODs des Sysgens. Vorschlag stattdessen: `TZMF100`. - -**Das CDS ist so *nicht* prüfbar.** Seine Membernamen sind echte Hashes -(Stichprobe: `Ak\x7F\x1C]\x0D\xB6\x00`, `Jj7\x96\xFF\xDB\x3A\x00`) — ein Namensvergleich dort -liefert nur Scheinergebnisse. Für Gewissheit braucht es einen SMP-`LIST`-Job. -Ebenso: `list_members()` scheitert an beiden Datasets, weil mvsMF die -Steuerzeichen als ungültiges JSON ausliefert; der Roh-Request unten umgeht das. - -```python -# PTS-Inventar auslesen (read-only) -import re, base64, urllib.request -url = "http://:/zosmf/restfiles/ds/SYS1.SMPPTS/member" -req = urllib.request.Request(url) -req.add_header("Authorization", "Basic " + base64.b64encode(b"user:pass").decode()) -req.add_header("Accept", "application/json") -txt = urllib.request.urlopen(req, timeout=90).read().decode("utf-8", "replace") -ids = sorted({n.strip() for n in re.findall(r'"member"\s*:\s*"(.*?)"', txt) - if "\\u" not in n}) # MCS-Entries = lesbare SYSMOD-IDs -``` +## 1. Offen ---- +### O1 — `THTP400` im CDS und ACDS prüfen · **vor dem 4.0.0-Tag** -## 3. TODO — Spike (P0, zuerst) - -> **Erledigt.** Der Spike wurde am 2026-08-08 im Projekt -> [`../smptest`](../smptest) gefahren, nicht mit `HTTPDM` — ein Modul, keine -> Abhängigkeiten, eigener FMID `TSMP100`. Ergebnis: SMP **kopiert** das -> LKLIB-Modul, `SYS2.CMDLIB(SMPTEST)` ist byteidentisch mit `build/SMPTEST`, -> ACCEPT trägt es in die DLIB, RESTORE nimmt es zurück. Belege und -> wiederverwendbare JCL in `../smptest/jcl/` und `../smptest/scripts/`. -> -> Für httpd bleibt davon: der Weg ist bestätigt, die Schritte unten sind die -> Vorlage für den ersten httpd-Lauf. - -Die ursprüngliche Fragestellung: **kopiert SMP das LKLIB-Modul wirklich -unverändert?** Braucht **kein** neues mbt-Feature — alles von Hand, mit den -vorhandenen Upload-Wegen. - -- [ ] **S1** `make modules` — Stand sicherstellen -- [ ] **S2** LKLIB auf MVS bringen — **Weg A (XMIT)**, der heute implementierte - Pfad (§10.4 im Konzeptdokument): - - ```sh - ld370 --pack build/HTTPDM.iebcopy -o build/httpd.deploy \ - -xmit --dsn HTTPD.V4R0M0.LKLIB - # -> upload_binary (FB80) -> TSO RECEIVE -> HTTPD.V4R0M0.LKLIB - ``` - - `ld370 --pack` erhält dabei die Attribute **jedes** Members (AC, RENT, - REUS) aus dem Bindelauf 📖 — deshalb überlebt `HTTPD`s `AC=1` den Transport. - `--blocksize` muss beim Binden und Packen identisch sein (Default 15040). - RECEIVE mergt nicht: Zielbibliothek vorher löschen, wie `mbtdeploy` es tut. - *Alternative für später:* `-iebcopy` + Batch-`IEBCOPY` statt TSO — Vorteile - und offene Fragen in §10.4. -- [ ] **S3** DLIB + SAMPLIB allokieren (IEFBR14): `SYS2.HTTPD.AHTTPLOD` als - Loadlibrary (DCB wie `SYS2.LINKLIB`) -- [ ] **S4** MCS-Datei von Hand schreiben (~12 Zeilen) und als FB80 hochladen: +Belegt ist bisher nur der **SMPPTS** auf `mvsdev`: 1544 SYSMODs gelesen, kein +`THTP400` (§3). Der PTS zeigt aber nur, was *empfangen* wurde. CDS und ACDS +speichern gehashte Membernamen — ein Namensvergleich dort liefert +Scheinergebnisse, wie in §3 gemessen. Gewissheit gibt nur ein `LIST`-Job, auf +**beiden** Ständen (`mvsdev` = MVS/CE, `drnmig3a` = TK5): ``` -++FUNCTION(TTST400) . -++VER(Z038) /* httpd 4.0.0-dev - SPIKE, Wegwerf-FMID */ . -++JCLIN . -//TTST400 JOB 1,'HTTPD SPIKE',MSGLEVEL=1,CLASS=A -//COPYLOAD EXEC PGM=IEBCOPY -//AHTTPLOD DD DISP=SHR,DSN=SYS2.HTTPD.AHTTPLOD -//LINKLIB DD DISP=SHR,DSN=SYS2.LINKLIB -//SYSIN DD * - COPY INDD=AHTTPLOD,OUTDD=LINKLIB - SELECT MEMBER=(HTTPDM) +//LIST EXEC SMPAPP +//SMPCNTL DD * + LIST CDS SYSMOD(THTP400) . + LIST ACDS SYSMOD(THTP400) . /* -++MOD(HTTPDM) LKLIB(HTTPLOAD) DISTLIB(AHTTPLOD) . ``` -- [ ] **S5** Install-Job von Hand: `RECEIVE SELECT(TTST400)` → - `APPLY S(TTST400) CHECK` → `APPLY S(TTST400) DIS(WRITE)`, mit - `//SMPPTFIN DD DSN=…`, `//HTTPLOAD DD …LKLIB`, `//AHTTPLOD DD …`, - `//LINKLIB DD DISP=SHR,DSN=SYS2.LINKLIB` -- [ ] **S6** **Bitvergleich** `SYS2.LINKLIB(HTTPDM)` gegen `build/HTTPDM` — - *das ist der eigentliche Test.* Gleich ⇒ SMP hat kopiert, nicht gebunden, - und `norent`/`ac`/Entry stammen unverändert aus ld370. -- [ ] **S7** `ACCEPT S(TTST400) DIS(WRITE)` → landet das Modul in `AHTTPLOD`? -- [ ] **S8** `++PTF` mit demselben Modul, danach `RESTORE` — kommt der Vorstand - sauber zurück? -- [ ] **S9** Aufräumen: `RESTORE` → `REJECT SELECT(TTST400)`, Test-Datasets - löschen. **Kontrollieren, dass `THTP400` im CDS unberührt ist** — es wird - erst vom getaggten 4.0.0 vergeben. - -**Abbruchkriterium:** Wenn S6 zeigt, dass SMP doch bindet, stoppen und auf das -RAKF-Muster wechseln (Anhang C.7 im Konzeptdokument) — nicht auf Objektdecks. - ---- - -## 4. TODO — SMP-Paket für httpd +**RC 04 mit leerer Liste heißt frei.** Der Zonenoperand ist Pflicht; bares +`LIST SYSMODS .` ist SMP/E-Syntax und endet in `HMA2033 SYNTAX ERROR`. Und +qualifizieren: `LIST CDS .` gibt auf MVS/CE 116 000 Zeilen aus. -Erst wenn §3 grün ist. +Die FMID wird genau einmal vergeben. ufsd (`TUFS120`) und ftpd (`TFTP100`) +haben diesen Job vor ihrem Tag gefahren, httpd noch nicht — der Kommentar in +`project.toml` sagt das auch so. -- [ ] **P1** FMID final vergeben (F2) und in `knowledge/` dokumentieren — - `THTP400` **erst mit dem getaggten 4.0.0**, nicht aus dem `-dev`-Baum -- [ ] **P2** `[smp]`-Abschnitt in `project.toml`: +### O2 — Testinstallation mit Wegwerf-FMID `TTST400` -```toml -[smp] -fmid = "THTP400" -system = "Z038" -mode = "lklib" -lklib = "HTTPLOAD" # DDNAME der hochgeladenen Loadlibrary -distlib = "AHTTPLOD" # DDNAME der Loadmodul-DLIB -samplib = "AHTTPSAM" # DDNAME der SAMPLIB-DLIB -target = "SYS2.LINKLIB" # aus F1 -prereq = ["TUFS100"] # sonst aus [dependencies] abgeleitet -``` +Die Generalprobe aus einem `-dev`-Baum. Ein Testlauf unter `THTP400`, der +abbricht oder halb angewendet wird, belegt genau die ID, die das getaggte 4.0.0 +braucht — und das CDS lässt sich hinterher nur mit `UCLIN` bereinigen +(`docs/installation.md` §11). -- [ ] **P3** MCS-Generator: `++FUNCTION`/`++VER`/`++JCLIN` + je `[[module]]` ein - `++MOD … LKLIB` + je SAMPLIB-Member ein `++MAC` -- [ ] **P4** COPY-JCLIN-Generator: `SELECT MEMBER=(…)` aus den - `[[module]]`-Namen -- [ ] **P5** Allokationsjob generieren (DLIB, SAMPLIB, ASAMPLIB, LKLIB) -- [ ] **P6** `make smppkg` → `dist/httpd-4.0.0.smpmcs` + `…lklib.xmit` + - `…-inst.jcl` + `…-setup.jcl` -- [ ] **P7** `make smpinst` — Upload + Job absetzen + RC prüfen (**schreibt auf MVS**) -- [ ] **P8** Alle 6 Module statt nur `HTTPDM`; `HTTPD` trägt **AC=1** — prüfen, - dass die Autorisierung den Kopiervorgang übersteht -- [ ] **P9** `++PTF`-Pfad (`make smpptf`) — **ganzes** LMOD via LKLIB -- [ ] **P10** **Modul entfällt / kommt hinzu:** Wenn sich die Modulliste ändert, - braucht der SYSMOD ein neues `++JCLIN` mit angepasster - `SELECT MEMBER=(…)`-Liste; ein entfallenes Modul zusätzlich per - `++MOD(x) DELETE`. Generator muss das aus dem Diff der `[[module]]`-Namen - gegen den letzten Release ableiten. -- [ ] **P11** **Aliase:** httpd hat heute keine. Falls je welche entstehen, - müssen sie mit `TALIAS(…)` deklariert werden **und** in der LKLIB - vorhanden sein — sonst kopiert SMP sie nicht 📘. +Mit mbt ist das eine Zeile: `fmid` in `project.toml` auf `TTST400` setzen, +`make package`, installieren — **und die Änderung nie committen**. ---- +Die Datasetnamen kollidieren dabei nicht mit dem späteren Release, ohne dass +man etwas dafür tun muss: `@VRM@` kommt aus der Projektversion, und +`4.0.0-dev` ergibt `V4R0M0D`, das getaggte `4.0.0` dagegen `V4R0M0`. Der Test +lebt also in `HTTPD.V4R0M0D.*`, das Release in `HTTPD.V4R0M0.*`. -## 5. TODO — SAMPLIB +Aufräumen danach: UCLIN-Job aus `docs/installation.md` §11 mit `TTST400`, dann +die Datasets löschen, dann `LIST CDS/ACDS SYSMOD(THTP400)` — das ist zugleich +O1. -Siehe §14.5 im Konzeptdokument. Kernregel: +### O3 — UFS-Webroot: SMP kann das nicht ausliefern -> **Produkt besitzt die Muster, Site besitzt die Kopien.** -> `SYS2.HTTPD.SAMPLIB(HTTPD)` gehört SMP — `SYS2.PROCLIB(HTTPD)` nicht. +Eine UFS-Disk ist ein `DSORG=PS`, `RECFM=U`, `BLKSIZE=4096`-Binärimage; SMP4 +kennt dafür keinen Elementtyp (es kennt nur +`++MOD/MAC/SRC/MACUPD/SRCUPD/ZAP`). Sie ist außerdem **Site-Inhalt** — ein +erneutes APPLY dürfte sie nie anfassen. -Grund: `samplib/httpd` enthält `STEPLIB`, `VOL=SER=MVS000`, REGION, Port — alles -Werte, die der Betreiber ändert. Besäße SMP die aktive Proc, wäre jede Anpassung -beim nächsten APPLY weg. +Heute steht in `docs/installation.md`, dass ohne UFSD nur die `MOD=`-Routen +laufen und `HTTPD044W` kommt. Das ist ehrlich, aber es ist keine Auslieferung. +Offen: -- [ ] **L1** `SYS2.HTTPD.SAMPLIB` + `.ASAMPLIB` allokieren (FB80) -- [ ] **L2** Bestehende Muster als `++MAC` aufnehmen: - `samplib/httpd` → Member `HTTPD`, `samplib/httpprm0` → Member `HTTPPRM0` -- [ ] **L3** **Generierte** Member ergänzen — sie tragen FMID, Version und - Datasetnamen und müssen zum Release passen: - - `HTTPINST` — der SMP-Install-Job - - `HTTPSETU` — der Setup-Job (Disk, Mount, Kopien) - - `HTTPWEB` — JCL-Muster für den Disk-Upload -- [ ] **L4** DD-Override im APPLY/ACCEPT-Step: - `//SAMPLIB DD DISP=SHR,DSN=SYS2.HTTPD.SAMPLIB` (letzter Qualifier passt) -- [ ] **L5** Kopierschritt **im Setup-Job**, nicht im Install-Job: +- [ ] **U1** Image bauen — `ufsd-utils create webroot.img --size 10M`, + `ufsd-utils cp -r static/ webroot.img:/`, danach `ufsd-utils ls -l` + gegenprüfen (Falle T3) +- [ ] **U2** Hochladen: `ufsd-utils upload webroot.img --dsn HTTPD.WEBROOT` +- [ ] **U3** Mount dokumentieren — `UFSDPRMx` gehört **ufsd**, nicht httpd: + `MOUNT DSN(HTTPD.WEBROOT) PATH(/www) MODE(RO)`, oder dynamisch + `/F UFSD,MOUNT DSN=HTTPD.WEBROOT,PATH=/www,MODE=RO`. Kein `++MACUPD` in + ufsds Parmlib +- [ ] **U4** Reihenfolge: **ufsd zuerst**, Dateisystem gemountet, `/www` + existiert — *dann* httpd. Eine Laufzeitabhängigkeit, die SMP nicht + abbilden kann +- [ ] **U5** `make webroot` + CI-Asset `httpd--webroot.img`, mit + SHA256 statt eines Reproduzierbarkeitsversprechens +- [ ] **U6** **Update-Verhalten festlegen** — `.SAMPLE`-Name oder Existenzprüfung. + Ein `ufsd-utils upload --replace` im Update-Job wäre Datenverlust beim + Betreiber + +`[distribution] extra = [...]` kann eine Datei ins Archiv legen, ohne SMP zu +behelligen — das ist der wahrscheinliche Weg für U5, sobald U6 entschieden ist. + +### O4 — Setup-Job: ausliefern oder Handarbeit lassen? + +`docs/installation.md` §7 lässt den Betreiber Proc und Konfigmember von Hand aus +der SAMPLIB kopieren. Das ist Absicht — *Produkt besitzt die Muster, Site +besitzt die Kopien* — aber ein **Muster** für den Kopierschritt wäre trotzdem +freundlicher als eine Prosaanweisung: ```jcl //COPYPROC EXEC PGM=IEBCOPY -//IN DD DISP=SHR,DSN=SYS2.HTTPD.SAMPLIB +//IN DD DISP=SHR,DSN=HTTPD.@VRM@.SAMPLIB //OUTP DD DISP=SHR,DSN=SYS2.PROCLIB //OUTM DD DISP=SHR,DSN=SYS2.PARMLIB //SYSIN DD * @@ -282,145 +115,157 @@ beim nächsten APPLY weg. /* ``` -- [ ] **L6** Für die Testinstallation eine **eigene Minimalkonfiguration** - erzeugen — siehe Falle T4 +Als weiteres SAMPLIB-Member (`HTTPSETU`) wäre das ein Zweizeiler in +`samplib/` — mit dem Haken, dass `@VRM@` dort ersetzt wird, `SYS2.PROCLIB` und +`SYS2.PARMLIB` aber geraten sind und auf TK5 falsch. Entscheidung offen. +Weder ufsd noch ftpd liefern so etwas aus. --- -## 6. TODO — UFS-Disk / WWW-Root +## 2. Erledigt — was mbt heute übernimmt + +Nicht neu planen. Die frühere §3 (Spike), §4 (SMP-Paket), §5 (SAMPLIB) sind +abgearbeitet oder ersetzt: + +| Früher offen | Heute | +|---|---| +| Spike: kopiert SMP wirklich? | ✅ 2026-08-08 in `../smptest` bewiesen (`TSMP100`, Bitvergleich) | +| MCS-/JCLIN-/Allokationsjob-Generator | ✅ `mbt/scripts/mbt/distribution.py` + `mbtdist.py` | +| `[smp]`-Block in `project.toml` | ✅ als `[distribution]` / `[distribution.smp]`, mit **Datasetnamen** statt DDNAMEs — der DDNAME ist immer der letzte Qualifier | +| SAMPLIB als `++MAC` in den SYSMOD | ❌ verworfen: eine MCS-Karte endet in Spalte 72, `HTTPPRM0` hat Kommentarzeilen bis 80. Die SAMPLIB fährt als eigenes XMIT per TSO RECEIVE, außerhalb von SMP | +| Install-Job als SAMPLIB-Member | ❌ liegt im Archiv (`httpd--inst.jcl`), nicht in der SAMPLIB | + +**Umgekehrt entschieden gegenüber der alten Fassung — zwei Punkte:** + +- **Ziel ist `HTTPD.@VRM@.LINKLIB`, nicht `SYS2.LINKLIB`** (alte F1). Versionierte + Produktdatasets heißen: kein IPL für einen APF-Eintrag, keine Kollision mit + Systembibliotheken, jede Release-Stufe nebeneinander installierbar. Die Proc + behält ihren STEPLIB und zieht ihn über `@LINKLIB@` aus dem Paket. + Konsequenz für die alte Falle T6: der Selbstautorisierungsweg über SVC 244 + bleibt der Normalfall, `HTTPD002I AUTHORIZED BY SVC (MODULE KEY 8)` ist die + erwartete Zeile. Der APF-Zweig ist trotzdem beschrieben — ein Betreiber, der + die LINKLIB in `IEAAPF00` einträgt, bekommt `AUTHORIZED BY LIBRARY (MODULE + KEY 0)`, und `docs/installation.md` §2 sagt, was das für die Modulspeicherung + bedeutet. +- **ACCEPT fährt mit** (alte F4 sagte „nein, nie"). Der ACCEPT füllt die DLIB + und ist damit die Basis, auf die ein späteres `RESTORE` eines **PTF** + zurückgeht — ohne ihn würde RESTORE das Modul löschen statt es + zurückzunehmen. Der Preis ist, dass die FMID selbst permanent wird: `RESTORE` + scheitert, weil akzeptiert, und `REJECT`, weil der ACCEPT die MCS aus dem + SMPPTS entfernt. Der Weg zurück ist `UCLIN`, beschrieben in + `docs/installation.md` §11. **Service (PTFs) wird weiterhin nie akzeptiert.** -Siehe §14.1–§14.4 im Konzeptdokument. SMP4 kann das **nicht** ausliefern: eine -UFS-Disk ist ein `DSORG=PS`, `RECFM=U`, `BLKSIZE=4096`-Binärimage, und es gibt -keinen passenden Elementtyp. Sie ist außerdem **Site-Inhalt** — ein erneutes -APPLY dürfte sie nie anfassen. +--- -- [ ] **U1** Image bauen: +## 3. Verifiziertes Inventar -```sh -ufsd-utils create webroot.img --size 10M -ufsd-utils cp -r static/ webroot.img:/ -ufsd-utils ls -l webroot.img:/ # Kontrolle, s. Falle T3 -``` +Nicht neu messen (🔬 gemessen · 📘 SMP4-Handbuch · ✅ Repo). -- [ ] **U2** Hochladen: `ufsd-utils upload webroot.img --dsn HTTPD.WEBROOT` - (legt das Dataset mit an) -- [ ] **U3** Mount eintragen — **`UFSDPRMx` gehört ufsd, nicht httpd** (F6): - `MOUNT DSN(HTTPD.WEBROOT) PATH(/www) MODE(RO)` - oder dynamisch `/F UFSD,MOUNT DSN=HTTPD.WEBROOT,PATH=/www,MODE=RO`. - **Kein `++MACUPD` in ufsds Parmlib** — Muster ausliefern, Schritt - dokumentieren. -- [ ] **U4** Laufzeitreihenfolge sicherstellen: **ufsd zuerst starten**, - Dateisystem gemountet, `/www` existiert — *dann* httpd. `DOCROOT` ist eine - Laufzeitabhängigkeit, die SMP nicht abbilden kann. -- [ ] **U5** `make webroot` + CI-Asset `httpd-4.0.0-webroot.img` (§20 im Konzeptdokument), mit SHA256-Summe statt Reproduzierbarkeitsversprechen -- [ ] **U6** **Update-Verhalten festlegen** (offen): `.SAMPLE`-Name oder - Existenzprüfung im Setup-Job. `ufsd-utils upload --replace` in einem - Update-Job wäre ein Datenverlust beim Betreiber. +**Verfahren** 📘 + +- `++MOD(x) LKLIB(ddname)` liefert ein **fertig gebundenes** Loadmodul; ist das + LMOD im JCLIN über einen IEBCOPY-Step definiert, kopiert SMP es statt zu binden. +- DDNAME = letzter Qualifier des Datasetnamens. +- Copy-Input im JCLIN muss **inline** hinter `//SYSIN DD *` stehen. +- `SELECT MEMBER=(…)` verwenden — sonst gilt die DLIB als *total* kopiert. +- SMP4 kennt keinen Datentyp: nur `++MOD/MAC/SRC/MACUPD/SRCUPD/ZAP`. + +**Zielsystem `mvsdev`** 🔬 + +- `SMPAPP` und `SMPREC` liegen in `SYS2.PROCLIB`, nicht `SYS1.PROCLIB`. +- Beide Procs haben genau einen Step (`HMASMP`); DD-Overrides müssen ihn + trotzdem als Qualifier tragen. Siehe Falle T9. +- Der Proc bringt `LINKLIB`, `LPALIB`, `PROCLIB`, `PARMLIB`, `SAMPLIB`, + `ASAMPLIB`, `MACLIB`, `CMDLIB` mit — alle auf `SYS1.*`. + +**SYSMOD-Inventar** 🔬 — `SYS1.SMPPTS` ist auslesbar, weil die MCS-Entries als +einzige *nicht* encodiert sind (dokumentierte Ausnahme 📘). 1544 SYSMODs im PTS, +darunter die Funktions-SYSMODs des Sysgens. **Frei im PTS:** `THTP400`, +`TTST400`. Das **CDS ist so nicht prüfbar** — Stichprobe der Membernamen: +`Ak\x7F\x1C]\x0D\xB6\x00`, `Jj7\x96\xFF\xDB\x3A\x00`. Deshalb O1. + +> ⚠ Die alte Fassung nannte hier `TMVS100` als Vorschlag für mvsmf und riet +> davon ab. Der ökosystemweite Beschluss steht inzwischen im Root-`CLAUDE.md`: +> **nie `TMVS…`** (MVS/CE führt USERMODs `TMVS804/816/817`), mvsmf bekommt +> `TZMF010`. + +**Artefaktseite** ✅ — **5** Loadmodule: `HTTPD` (AC=1), `HTTPDSRV`, `HTTPDM`, +`HTTPDMTT`, `ABEND0C1`. Die alte Fassung nannte sechs mit `HTTPJES2` und +`HTTPDSL`; beide sind seit 4.0.0 nicht mehr gebaut (mvsMFs jobs- und +dataset-API ersetzen sie, Quellen liegen in `tbd/`). --- -## 7. Fallen +## 4. Fallen -Jede einzelne kostet sonst einen Arbeitstag. +Die, die noch gelten. -- **T1 — Die eiserne Regel für COPY-LMODs.** Ein Update liefert **immer das - ganze Loadmodul** über LKLIB nach. Ein einzelnes Objekt-`++MOD` gegen ein - COPY-LMOD bindet SMP *allein* und zerstört das Modul (📘 „no INCLUDE for the - current version"). Nie ein Objektdeck in ein `++PTF` für httpd. +- **T1 — Die eiserne Regel für COPY-LMODs.** Ein Update liefert **immer das ganze + Loadmodul** über LKLIB nach. Ein einzelnes Objekt-`++MOD` gegen ein COPY-LMOD + bindet SMP allein und zerstört das Modul (📘 „no INCLUDE for the current + version"). Nie ein Objektdeck in ein `++PTF` für httpd. -- **T2 — `norent` / `ac` bleiben bei ld370.** Der Grund, warum wir auf dem Host - binden: ld370s Template markiert alles RENT+REUS, C-Module mit mutable statics - nehmen dann bei TSO-Load einen S0C4 (dokumentiert in RAKFs - `APPLICATIONS/project.toml`). Wenn ein JCLIN-Bindeschritt entsteht, wo keiner - sein sollte, ist der Fehler *hier*. +- **T2 — `norent` / `ac` bleiben bei ld370.** Der Grund, warum auf dem Host + gebunden wird. Entsteht irgendwo ein JCLIN-Bindeschritt, wo keiner sein + sollte, ist der Fehler hier. - **T3 — ASCII→EBCDIC hängt an der Dateiendung.** `ufsd-utils cp` konvertiert - nur bei bekannter Endung (`.html`, `.css`, `.js`, …). Eine Datei ohne Endung - oder mit `.tmpl` landet **verbatim als ASCII** in der Disk und ist auf MVS - unlesbar — ohne Fehlermeldung. `-t` erzwingt Konvertierung, `-b` erzwingt - binär. Ausgabe von `ufsd-utils ls -l` gegenprüfen. - -- **T4 — Das ausgelieferte `httpprm0` aktiviert nur MVSMF-Routen.** Die einzigen - unkommentierten Zeilen im Muster sind `MOD=MVSMF /zosmf/…`. Für eine - httpd-Testinstallation **ohne** mvsmf ist das die falsche Konfiguration — - eigene Minimalkonfiguration mit `DOCROOT=/www` und ggf. `MOD=HTTPDSRV /.dsrv` - verwenden. - -- **T5 — mvsMF wirft `S80A ABEND` nach wenigen Requests.** Ein HTTP 503 heißt - dann **nicht** „Dataset fehlt". Außerdem liefern `dataset_exists()` und - `list_datasets()` gegen diesen Server durchgehend `False`/`[]` — auch für - nachweislich existierende Datasets. Verlässlich ist nur `list_members()`. - Existenzprüfungen im Setup-Job besser per JCL (`IEFBR14`/`IDCAMS LISTCAT`). - -- **T9 — DD-Overrides brauchen den Proc-Step UND die richtige Reihenfolge.** - Im smptest-Spike zweimal reingelaufen 🔬. `//CMDLIB DD DSN=SYS2.CMDLIB` nach - `EXEC SMPAPP` ist **kein** Override, sondern eine zweite DD gleichen Namens: - beide Datasets werden allokiert, SMP nimmt die des Procs, das Modul landet in - `SYS1.CMDLIB` — und jede SMP-Meldung sagt weiterhin `LIBRARY=CMDLIB`, der - Fehler ist also aus dem Log **nicht** ablesbar. Qualifizieren allein reicht - auch nicht: stehen hinzugefügte DDs (`SMPTLOAD`, `ASMPTEST`) vor der - Override-Karte, wird sie ebenfalls ignoriert. Richtig ist: - **erst alle Overrides, dann alle Ergänzungen**, alle mit `HMASMP.`-Präfix. - Kontrolle: nachsehen, wo das Member wirklich liegt — nicht dem RC glauben. - -- **T6 — Die Autorisierung ändert ihren Weg, und das will beobachtet werden.** - httpd hängt heute *nicht* davon ab, dass die STEPLIB autorisiert ist — es - **autorisiert sich selbst**. `httpd.c` verzweigt beim Start ✅: - - ```c - if (crt->crtopts & CRTOPTS_AUTH) rc = auth_setup(argv[0]); /* schon autorisiert */ - else rc = unauth_setup(argv[0]); /* holt sich die Autorisierung */ - ``` - - `unauth_setup()` ruft `__autask()` (SVC 244 → JSCBAUTH) und danach - `__austep()`, um die STEPLIB nachträglich APF-autorisiert zu machen — - Meldungen `HTTPD011I … via SVC 244` und `HTTPD013I STEPLIB is now APF - authorized`. Deshalb funktioniert die heutige Proc mit - `STEPLIB DD DSN=HTTPD.LINKLIB` auch ohne APF-Eintrag. - - Nach einer Installation in die autorisierte LNKLST-Verkettung sollte der - `auth_setup()`-Zweig greifen (`HTTPD010I … is APF authorized`) und die ganze - Selbstautorisierung entfallen. **Das ist während der Installationsexperimente - empirisch zu prüfen**, nicht vorher zu behaupten: - - - Welcher Zweig wird tatsächlich genommen? (Meldung im Log: `HTTPD010I` vs. - `HTTPD011I`/`HTTPD013I`) - - Ist `__austep()` dann überflüssig, harmlos oder störend? - - Braucht es eine zusätzliche Prüfung im Code — oder reicht `CRTOPTS_AUTH` - bereits? Der Verdacht ist, dass es schon reicht. - - Nebenbefund: SVC 244 kommt von RAKFs Usermod `RAK0001` — der liegt auf - `mvsdev` im PTS 🔬. Der heutige Selbstautorisierungsweg hängt also an RAKF. - **Kommt nach dem Spike, blockiert ihn nicht.** - -- **T7 — DDNAME = letzter Qualifier.** `SYS2.HTTPD.LINKLIB` hätte ebenfalls den - DDNAME `LINKLIB` — die Kollision mit dem Proc-DD verschwindet nicht durch - Umbenennen. Override ist der Weg. - -- **T8 — `ACCEPT` ohne `COND`.** RAKF macht das und akzeptiert damit auch nach - einem gescheiterten APPLY. Getrennte Jobs (F4). + nur bei bekannter Endung. Eine Datei ohne Endung oder mit `.tmpl` landet + **verbatim als ASCII** in der Disk und ist auf MVS unlesbar — ohne + Fehlermeldung. `-t` erzwingt Konvertierung, `-b` binär. Betrifft O3. + +- **T4 — Das ausgelieferte `httpprm0` aktiviert nur MVSMF-Routen.** Für eine + Testinstallation *ohne* mvsmf ist das die falsche Konfiguration. + `docs/installation.md` §7 sagt das jetzt auch dem Betreiber; für den Test + reicht eine eigene Minimalkonfiguration mit `DOCROOT=/www`. + +- **T7 — DDNAME = letzter Qualifier.** `HTTPD.@VRM@.LINKLIB` hat den DDNAME + `LINKLIB` und kollidiert damit zwangsläufig mit dem Proc-DD. Umbenennen hilft + nicht, Override ist der Weg — mbt kennt die Proc-DDs (`SMPAPP_PROC_DDS`) und + schreibt die Overrides selbst. + +- **T9 — DD-Overrides brauchen den Proc-Step UND die richtige Reihenfolge.** Im + Spike zweimal reingelaufen 🔬: `//LINKLIB DD …` nach `EXEC SMPAPP` ist **kein** + Override, sondern eine zweite DD gleichen Namens — beide Datasets werden + allokiert, SMP nimmt die des Procs, und jede Meldung sagt weiterhin + `LIBRARY=LINKLIB`. Aus dem Log ist der Fehler nicht ablesbar. Richtig: erst + alle Overrides, dann alle Ergänzungen, alle mit `HMASMP.`-Präfix. Der + generierte Job macht das; der Kommentar im Job sagt auch, dass man ihn nicht + umsortieren soll. + +**Erledigt, nur zur Erinnerung warum:** + +- ~~**T8 — `ACCEPT` ohne `COND`.**~~ Der generierte Job hängt jeden SMP-Step an + den vorigen: `ACCEPT EXEC SMPAPP,COND=(0,NE,APPLY.HMASMP)`. +- ~~**T5 — mvsMF `S80A` nach wenigen Requests.**~~ Aus der Zeit vor dem + Storage-Reclaim (#154/#174). Nicht als aktueller Befund weiterreichen; wenn + ein Setup-Job Existenzprüfungen braucht, sind `IEFBR14`/`IDCAMS LISTCAT` + trotzdem der robustere Weg. --- -## 8. Definition of Done — Testinstallation - -- [ ] `RECEIVE` / `APPLY` laufen mit RC ≤ 4, `APPLY CHECK` vorher sauber -- [ ] Alle 6 Module liegen in der Zielbibliothek und sind **bitgleich** mit - `build/` -- [ ] `SYS2.HTTPD.SAMPLIB` enthält `HTTPD`, `HTTPPRM0`, `HTTPINST`, `HTTPSETU`, - `HTTPWEB` -- [ ] Setup-Job hat Proc und Konfig nach `SYS2.PROCLIB`/`SYS2.PARMLIB` kopiert -- [ ] `HTTPD.WEBROOT` ist angelegt, unter `/www` gemountet, `index.html` darin - lesbar (EBCDIC!) -- [ ] `/S HTTPD` startet, `curl http://mvsdev:8080/` liefert `index.html` -- [ ] `RESTORE` bringt einen sauberen Vorstand zurück -- [ ] Wegwerf-FMID `TTST400` ist `REJECT`ed, Testdatasets sind gelöscht -- [ ] `THTP400` ist im CDS **nicht** belegt — reserviert für das getaggte 4.0.0 +## 5. Definition of Done — Testinstallation + +- [ ] `RECEIVE` / `APPLY` mit RC ≤ 4, `APPLY CHECK` vorher sauber +- [ ] **Fünf** `HMA2380 COPY SUCCESSFUL`-Zeilen — eine je Modul. Weniger fällt + nicht auf: der APPLY endet trotzdem RC 00 +- [ ] Alle fünf Module liegen in `HTTPD.V4R0M0D.LINKLIB` und sind **bitgleich** + mit `build/` +- [ ] `HTTPD.V4R0M0D.SAMPLIB` enthält `HTTPD` und `HTTPPRM0`, und der `STEPLIB` + im Member zeigt auf `HTTPD.V4R0M0D.LINKLIB` (die `@LINKLIB@`-Ersetzung) +- [ ] `/S HTTPD` startet bis `HTTPD001I … READY`, `HTTPD002I` sagt, über welchen + Weg autorisiert wurde +- [ ] `HTTPD.WEBROOT` angelegt, unter `/www` gemountet, `index.html` in EBCDIC + lesbar — **nur wenn O3 bis dahin steht**; sonst gegen eine `MOD=`-Route + prüfen und `HTTPD044W` als erwartet abhaken +- [ ] `curl http://mvsdev:8080/…` antwortet +- [ ] Aufräumen: UCLIN auf `TTST400`, Testdatasets gelöscht, `LIST CDS/ACDS + SYSMOD(THTP400)` antwortet RC 04 mit leerer Liste --- -## 9. Nicht Teil der Testinstallation +## 6. Nicht Teil davon -- Ausrollen auf ufsd, ftpd, mvsmf (dieselbe Mechanik, §21 Roadmap im Konzeptdokument) -- CI-Integration der Artefaktmatrix (§20 im Konzeptdokument) -- Objektdeck-Auslieferung — **verworfen**, Begründung in Anhang C +- Ausrollen auf ufsd, ftpd, mvsmf — ufsd und ftpd sind bereits umgestellt und + sind die Referenz, an der httpds `[distribution]` sich orientiert. +- Objektdeck-Auslieferung — verworfen, siehe T1/T2. From adcb9378c91f0e0e38e6fecbd468df38f190e81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Gro=C3=9Fmann?= Date: Mon, 24 Aug 2026 08:05:35 +0200 Subject: [PATCH 03/11] Update index.html --- static/index.html | 183 +++++++++++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 67 deletions(-) diff --git a/static/index.html b/static/index.html index e700072..1e08b6e 100644 --- a/static/index.html +++ b/static/index.html @@ -1,93 +1,142 @@ - - - HTTPD 4.0.0 + + + + Welcome to HTTPD + + -
-

HTTPD

-
Version 4.0.0 — MVS 3.8j
-
✓ Server is running
-

- HTTP/1.1 server for IBM MVS 3.8j on Hercules.
- Part of the mvslovers open-source ecosystem. -

-