Compare commits

...

87 Commits

Author SHA1 Message Date
Jan Höppner
997343f841 New release s390-tools-2.42.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 17:06:55 +02:00
Finn Callies
6a767408b3 ebc: Add new tool pvics
pvics (PV Image Customization Support) is a comprehensive tool for
converting existing qcow2 KVM guest images to IBM Secure Execution for
Linux (SEL) images with Early Boot Customization (EBC) support and
encrypted root filesystems.

The tool provides four main actions:
- list: Retrieve information about boot loader entries in a base image
- convert: Convert a base image to an EBC-ready SEL image
- encrypt: Encrypt the root filesystem and prepare EBC resources
- full: Perform both conversion and encryption in one operation

Assisted-by: IBM Bob:1.0.1
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:47:26 +02:00
Finn Callies
3aa5c38714 ebc: Add ibm-sel-ebc dracut module
Add 95ibm-sel-ebc dracut module for secure boot-time customization of
SEL guests.

Introduce the IBM SEL EBC dracut module (95ibm-sel-ebc) that enables
Early Boot Customization for SEL guests during the initramfs phase.

The module implements a critical security architecture to prevent
injection attacks: all EBC resources (.asr and .pol files) are copied from
/boot/sics (which resides in the qcow2 image on the host filesystem) to
/run/ibm-sel-ebc (a tmpfs/RAM-backed directory). Since guest RAM is
protected by the Ultravisor, this prevents malicious hosts from modifying
EBC resources during boot.

Systemd units and their purposes:
 - ibm-sel-ebc.target: Groups all EBC-related units
 - boot.mount: Mounts /dev/disk/by-label/boot to /boot
 - ibm-sel-ebc-ensure-sics.service: Fallback to create /boot/sics/ if boot
   partition mount fails (supports Kata VM scenarios)
 - ibm-sel-ebc-pvebc.service: Main unit that copies EBC resources to RAM,
   invokes pvebc tool to verify integrity and add ASRs to UV, retrieves
   LUKS passphrase from UV secret store
 - ibm-sel-ebc-override-crypttab.service: Replaces /etc/crypttab with
   prepared IBM SEL EBC crypttab, reloads systemd daemon, starts cryptsetup
   service
 - ibm-sel-ebc-paes-enforce.service: Verifies root filesystem uses PAES
   encryption to prevent root filesystem substitution attacks

All units write logs to /boot/sics/log for debugging, accessible even if
root filesystem fails to mount. Units are triggered by rd.ibm-sel-ebc
kernel parameter and only execute in initramfs
(ConditionPathExists=/etc/initrd-release).

Assisted-by: IBM Bob:1.0.1
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:46:31 +02:00
Finn Callies
c04a0919f6 rust: Add new tool pvebc
Add pvebc tool for parsing and verifying EBC Add-Secret-Request structures

Introduce pvebc, a CLI tool that parses and verifies the integrity of
Add-Secret-Request (ASR) structures used in Early Boot Customization for
SEL guests.

The tool processes an integrity-protected ASR structure consisting of:
 - toc.asr: Meta secret that links to toc.pol via relative filepath and
   SHA512 hash, integrity-protected by its AES GCM authentication tag
 - toc.pol: Policy file containing AES GCM authentication tags (last 16
   bytes) of all user-provided ASRs
 - User ASRs: Individual Add-Secret-Requests containing encrypted secrets

This structure guarantees:
 - Prevents ASR removal: toc.pol lists all expected ASR authentication tags
 - Prevents ASR insertion: Unlisted ASRs are rejected
 - Prevents ASR modification: AES GCM authentication tags provide
   cryptographic integrity
 - Prevents toc.pol tampering: toc.asr's integrity protection secures the
   link

The tool verifies completeness by checking that all ASRs listed in toc.pol
are present and their AES GCM authentication tags match. This prevents
attackers from removing, inserting, or modifying ASRs during transport over
unsecured channels.

After verification, pvebc adds all ASRs to the Ultravisor (UV), which
decrypts them using the guest's secret key and makes them available to
the guest during early boot.

Assisted-by: IBM Bob:1.0.1
Acked-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:46:31 +02:00
Finn Callies
c803cb925e rust: Add toc support for ebc to pvsecret
Add two new command-line options to pvsecret create for Early Boot
Customization (EBC) Table of Contents (TOC) support:

 1. --policy FILE
    Links an Add-Secret-Request (ASR) to a policy file by embedding a
    PolicyReference in the ASR's user data field. The PolicyReference
    contains the relative file path and SHA512 hash of the policy file,
    enabling integrity verification of the policy. This option conflicts
    with --user-data as both use the same user data field in the ASR
    structure.

 2. --toc-policy FILE
    Appends the AES-GCM authentication tag (MAC tag - last 16 bytes of
    the encrypted ASR) to the specified TOC policy file. This enables
    the TOC policy to maintain a list of all ASR MAC tags for
    completeness verification during boot. The TOC can verify that all
    expected ASRs are present and unmodified by checking their MAC tags
    against this list. This option also conflicts with --user-data.

Both options support the EBC multi-party workflow where an ISV/CSP builds
a generic SEL image and customers customize it with their own secrets. The
TOC mechanism ensures the integrity and completeness of all EBC resources
during the boot process.

Assisted-by: IBM Bob:1.0.1
Acked-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:46:31 +02:00
Finn Callies
1741ecff96 rust: Add EBC support to pv_core library
Add EBC (Early Boot Customization) utility functions to pv_core library
for parsing and verifying Add-Secret-Request structures.

Introduce the core library functionality needed for EBC:
- Add ebc_utils module to pv_core with ASR parsing and verification
- Export ebc_utils in pv_core lib.rs
- Re-export ebc_utils in pv lib.rs for downstream consumers
- Update pvsecret Cargo.toml dependencies

The library provides the foundation for tools that work with
integrity-protected ASR structures used in SEL guest customization.

Assisted-by: IBM Bob:1.0.1
Acked-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:46:31 +02:00
Finn Callies
20de1fce2a rust: Fix typo in pv
Change "Extracrted" to "Extracted".

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:46:31 +02:00
Szabina Korbai
a5af5bcf70 zcrypt: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts
to chzcrypt, lszcrypt and zcryptstats.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:51:04 +02:00
Szabina Korbai
7730f2489f zipl-editenv: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:51:04 +02:00
Szabina Korbai
6dbc5646f9 lsscm: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:51:04 +02:00
Szabina Korbai
f70991ab1e lsqeth: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:51:04 +02:00
Szabina Korbai
e9ee658492 lscss: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.
Modify --devtype flag description to make it
compatible with zsh autocompletion.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:51:04 +02:00
Szabina Korbai
35d5f41232 chpstat: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:51:03 +02:00
Szabina Korbai
260a0a2428 chp: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts
to chchp and lschp.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:50:38 +02:00
Szabina Korbai
b444e71ee3 zmemtopo: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Tested-by: Mete Durlu <meted@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:50:10 +02:00
Szabina Korbai
31d576a595 zpwr: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:49:28 +02:00
Szabina Korbai
68309ccb7f zpcictl: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:49:26 +02:00
Szabina Korbai
755ea88d5d vmcp: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:49:03 +02:00
Szabina Korbai
af99efaab2 tunedasd: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:48:33 +02:00
Szabina Korbai
3b55ca085e opticsmon: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.
Modify --module-info flag description to make it
compatible with zsh autocompletion.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:48:33 +02:00
Szabina Korbai
9fdfd1a6dc lsstp: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:48:33 +02:00
Szabina Korbai
c459ec08c6 hsavmcore: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:48:33 +02:00
Szabina Korbai
eb63434f44 fdasd: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:48:30 +02:00
Szabina Korbai
0eae712cc2 dump2tar: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:47:35 +02:00
Szabina Korbai
e7e9f137c1 dasdview: Implement zsh and bash autocompletion
Add generation of shell autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:47:33 +02:00
Szabina Korbai
364cb9d869 dasdinfo: Implement zsh and bash autocompletion
Add generation of shell	autocompletion scripts.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:47:05 +02:00
Szabina Korbai
a64e9cab67 dasdfmt: Remove license boilerplate
Remove outdated license boilerplate from autocompletion
generator and cli header file. Fix SPDX-tag style.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Szabina Korbai
74cb6ee40e cpumf: Remove license boilerplate
Remove outdated license boilerplate from autocompletion
generator and cli header files. Fix SPDX-tag style.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Szabina Korbai
8c99c3878e libutil/util_autocomp_host: Remove license boilerplate
Remove outdated license boilerplate and fix
SPDX-tag style.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
f302f5734b zpwr: Adapt to new JSON Lines text format
util_fmt now provides support for JSON Lines text format. Adapt certain
checks in the code and document the newly supported format in the man
page accordingly.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
3485192791 zmemtopo: Adapt to new JSON Lines text format
util_fmt now provides support for JSON Lines text format.
Document the newly supported format in the man page accordingly.

Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
715da84030 lschp: Adapt to new JSON Lines text format
util_fmt now provides support for JSON Lines text format.
Document the newly supported format in the man page accordingly.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
6e53be736e chpstat: Adapt to new JSON Lines text format
util_fmt now provides support for JSON Lines text format. Adapt certain
checks in the code and document the newly supported format in the man
page accordingly.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
88bf638487 cpumf: Adapt to new JSON Lines text format
util_fmt now provides support for JSON Lines text format. Adapt certain
checks in the code and document the newly supported format in the man
pages for lshwc and lspai accordingly.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
182892da12 hyptop: Adapt to new JSON Lines text format
util_fmt now provides support for JSON Lines text format. Adapt certain
checks in the code and document the newly supported format in the man
page accordingly.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
f9e07c3916 libutil/util_fmt: Introduce JSON Lines text format
JSON Lines text format (JSONL) [1] is a line-delimited JSON format where
objects are separated by the new line character (\n, LF) as opposed to
the JSON Sequence text format (json-seq) where JSON text is encapsulated
in an ASCII Record Separator (0x1E, RS) and ASCII Line Feed character
(0x0A, LF).

Whilst JSONL is also used for data streaming, this simpler format is
better suited for logging and works also well with traditional
line-oriented Unix tooling (e.g. grep or sed).

Add this format to util_fmt so that users have more choice and control
over formats that are required for their usecases.

Add helper functions that let the user determine whether a given format
type is JSON in general or a JSON streaming format (such as json-seq or
jsonl).

For better readability and more clarity use the helper function
util_fmt_is_json_stream() where the same decision is made for both
JSON streaming formats FMT_JSONSEQ and FMT_JSONL.

[1] https://jsonlines.org/

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Thomas Richter
3aaf3c067e cpumf/pai.c: Install SIGINT/SIGTERM handler for graceful termination
Sending signal SIGINT/SIGTERM to a running pai process causes immediate
termination of that running process. This usually interrupts a
select() system call waiting for more input to read from the installed
events and its mapped memory buffers. As there is no signal handler
installed, a SIGINT or SIGTERM signal simply terminates the process,
sometimes leaving incomplete recorded output file paicryto.XXX
(where XXX is the CPU number).
Install a signal handler to intercept signal SIGINT or SIGTERM and run
one more data collection loop to read out pending data and close all
recording output files properly.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Steffen Eiden
801e404160 pvimg: Fix hidden inferred bound
The associated type bound  for Iterator::Item was unsatisfied for Self.
Fix this by requiring Sized for IntoEnumIterator.

Fixes: 1d2a89b387 ("pvimg: Improve the readability of Display output for control flags")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Steffen Eiden
280b8509d1 pvimg: Remove unnecessary references
Referencing here is superfluous and makes clippy sad.

Fixes: 87966251c4 ("pvimg: info: Improve JSON output")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Steffen Eiden
0f56416d82 pvsecret: Improve UX on non-s390 systems
If pvsecret {add, list, retrieve} is executed with options on a non-s390
system the user gets misleading error messages as the options are not
defined.

> pvsecret add -i secret.bin
error: unexpected argument '-i' found

This may lead the user to think wrong arguments where chosen, which is
not entirely true as they are valid on s390. The more helpful error
message would be
error: Command only available on s390x

Which is already the case if no arguments are given.
Solve this by allowing non-s390 systems to parse the options:

> pvsecret add -i secret.bin
  error: Command only available on s390x

Reported-by: Carlo Della Giusta <carlo.dellagiusta@suse.com>
Fixes: dd82c26f87 ("rust: Add tool to manage UV-secrets")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Steffen Eiden
c88e0276c1 pvattest: Improve UX on non-s390 systems
If pvattest perform is executed with options on a non-s390 system the
user gets misleading error messages as the options are not defined.

> pvattest perform -i attestation_request.bin  -o attresp.bin
  error: unexpected argument '-i' found

This may lead the user to think wrong arguments where chosen, which is
not entirely true as they are valid on s390. The more helpful error
message would be
error: Command only available on s390x

Which is already the case if no arguments are given.
Solve this by allowing non-s390 systems to parse the options:

> pvattest perform -i attestation_request.bin  -o attresp.bin
  error: Command only available on s390x

While at it ignore some unused code warnings in the exchange format code
that appear on non-s390 systems as not all code is used.

Reported-by: Carlo Della Giusta <carlo.dellagiusta@suse.com>
Fixes: 16610a211f ("rust: pvattest-Rust")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Szabina Korbai
5b7f08624b libutil/util_autocomp_host: Fix script updating
Force the autocompletion script generator to always write to a new
empty file, thus preventing the potential corruption of script contents.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>

Signed-off-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jörn Siglen
b94d5e8f87 dbginfo.sh: Add command zmemtopo
Display CEC memory topology of allocated memory increments

Suggested-by: Mario Held <mario.held@de.ibm.com>
Suggested-by: Eberhard Pasch <epasch@de.ibm.com>
Reviewed-by: Michael Storzer <MSTORZER@de.ibm.com>
Signed-off-by: Jörn Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jörn Siglen
a4f171d4ba dbginfo.sh: Update comments and copyright year
first change for 2026 and some clarification in comments

Reviewed-by: Michael Storzer <MSTORZER@de.ibm.com>
Signed-off-by: Jörn Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Ingo Franzki
93f8d093ce libkmipclient: Adjustments for OpenSSL v4.0.0 API changes and deprecations
With OpenSSL 4.0.0 function SSL_set1_host() is deprecated and should be
replaced by SSL_set1_ipaddr() and SSL_set1_dnsname().

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Ingo Franzki
7e68d7f61a libseckey: Adjustments for OpenSSL v4.0.0 API changes and deprecations
With OpenSSL 4.0.0 function X509_NAME_get_entry() returns a const pointer.
Make the local variable also const to avoid compile warnings like:

  warning: assignment discards ‘const’ qualifier from pointer target type
  [-Wdiscarded-qualifiers]

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Ingo Franzki
7755d35995 libekmfweb: Adjustments for OpenSSL v4.0.0 API changes and deprecations
With OpenSSL 4.0.0 function X509_NAME_get_entry() returns a const pointer.
Make the local variable also const to avoid compile warnings like:

  warning: assignment discards ‘const’ qualifier from pointer target type
  [-Wdiscarded-qualifiers]

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Ingo Franzki
211431abc2 zkey: Adjustments for OpenSSL v4.0.0 API changes and deprecations
With OpenSSL 4.0.0 function X509_cmp_current_time() is deprecated and
should be replaced by X509_check_certificate_times().

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:02 +02:00
Jan Höppner
0ae29148f0 gitignore: Update gitignore
zdev usage files were converted from .c to .h files. Adapt the file
names in gitignore.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Polensky
43cf7873be zdev: generate usage text headers instead of C files
Generating and then including C source files from another C file can
lead to unexpected compilation errors in certain environments.

Switch the usage text generation from %_usage.c to %_usage.h. The
generated header provides the usage_text definition directly, and
chzdev.c and lszdev.c include the corresponding *_usage.h instead.

Update depfile prerequisites and the clean target to match the new
generated artifacts.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Polensky
d8cea21e1e zdev: Makefile: deduplicate *_usage.c generation
Consolidate the duplicated sed command sequences used to generate
*_usage.c files into a shared CSTR_SED definition and a single pattern
rule:

	%_usage.c: %_usage.txt

This removes the copy/pasted rules for chzdev_usage.c and lszdev_usage.c
and keeps the Makefile easier to maintain.

Also drop the explicit chzdev.o/lszdev.o prerequisites on the generated
sources as dependencies are already tracked via the .*.o.d depfiles.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Polensky
7093a70b51 dasdinfo: Drop obsolete kernel check and use errx() for arg errors
Remove the uname()/sscanf()-based kernel version gate (Linux < 2.6),
which is long obsolete and does not belong in user-space argument
validation.

While touching the code, replace the repeated warnx() + exit(1) pattern
with errx(EXIT_FAILURE, ...) in the option sanity checks to reduce
boilerplate and keep error paths consistent.

Behaviour is unchanged for supported environments; the version gate is
dropped because it is obsolete.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Polensky
06984cd9ee dasdinfo: Modernize NULL pointer checks
Replace explicit NULL comparisons with idiomatic C style:
- 'if (ptr == NULL)' -> 'if (!ptr)'
- 'if (ptr != NULL)' -> 'if (ptr)'

No functional changes.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Polensky
3a05ab769d dasdinfo: Apply code style improvements
- Use __packed instead of __attribute__ ((packed))
- Rename EBCtoASC to ebc_to_asc following naming conventions
- Consolidate multi-line error message into single line

No functional changes.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Polensky
bcbc69c77f zkey/kmip: Normalize encoding; remove non-UTF-8 artifact
Normalize the man page source to UTF-8/US-ASCII and remove a mojibake
artifact that could not be represented cleanly.

Documentation only, no functional changes.

Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Niklas Schnelle
b385b8cc38 opticsmon: Fix wrong reference to --daemon flag in man page
Even before release the flag was renamed to --monitor but the mention in
the man page was missed.

Reported-by: Halil Pasic <pasic@linux.ibm.com>
Fixes: c34adb9cab ("opticsmon: Introduce opticsmon tool")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Höppner
2b282bdacd libutil/util_autocomp: Remove comments describing resulting scripts
Future updates might change the outcome of the resulting scripts and the
comments describing the script output would need to be updated every
time as well. It's not worth the effort.

Remove the comments that list script examples from the functions
generate_bash_autocomp() and generate_zsh_autocomp().

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Höppner
bd2610d275 libutil/util_autocomp: Fix default file completion
For Bash, when compspecs are found the generated script is returned as
the full set of possible completions and default completions are
disabled [1]. This leads to the behaviour that command line arguments
are not completed, only options defined by the script.

Zsh has the same issue.

Fix the issue by always adding the bash defaults to the generated
script. For zsh the corresponding file completion is always added to the
end of the argument list and the -A "*" option is added to allow
completion after positional arguments.

[1] https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html#Programmable-Completion-1

Fixes: 638cbbe332 ("libutil: Implement zsh and bash autocompletion")
Reported-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Jan Höppner
5cf2cefa94 libutil/util_autocomp: Fix ShellCheck findings and apply coding style
Apply coding style changes by reducing line breaks for a more compactly
generated script and add double quotes to fix ShellCheck findings.
Furthermore, remove the unused variable previous_word and use mapfile to
read the output of compgen into the COMPREPLY array to avoid unwanted
splitting and glob expansion.

Reviewed-by: Szabina Korbai <szkorbai@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 08:44:01 +02:00
Eduard Shishkin
984e008127 zipl/src: Indicate in a verbose output if a component is signed
Regardless of secure boot support, indicate in the verbose zipl(8)
output if a component is signed.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-10 11:22:10 +02:00
Eduard Shishkin
fcfee1aa84 zipl/src: Fix a bug in building replicated program tables
When installing IPL on mirrored targets, zipl builds multiple program
tables (one such table per each mirror). If the option "--add-files"
was specified, then zipl uses the in-bootmap files, that was written
at the prevoius iteration (for the mirror ID #0) to build program
tables for mirrors with ID #1 (and larger). The in-bootmap files
already don't contain trailers. Despite this, the building process
cuts off the tail of trailer size, which results in corrupted boot
data.

This bug may result in crashing the kernel when booting from mirrors
with ID #1 (and larger) and manifests only if the boot components are
signed and the option "--add-files" is specified for the installation
session.

Don't count the trailer, when building program tables using in-bootmap
files written at the previous iteration.

Fixes: 431e4542ca ("zipl/src: Reuse data of file components in bootmap")
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-10 11:22:10 +02:00
Chinmaya Kajagar
b401ad0da0 zfcpdbf: Print sysfs unit add store events
New trace tags "sysuas*" added in kernel to trace zfcp sysfs unit add
store events.

Print the trace events under HBA with new record ID 6. The fields under
this tag are WWPN, FCP LUN and return value of the device having issues.

Example zfcpdbf output for unit add store events:

Timestamp      : 2026-02-02-10:50:02:474983
Area           : HBA
Subarea        : 00
Level          : 4
Exception      : -
CPU ID         : 0003
Caller         : 0x000001d89a86bd0e
Record ID      : 6
Tag            : sysuas2
Description    : sysuas2 HBA, Sysfs unit add store failure, unit add failed
Request ID     : 0x00000000ffffffff
Request status : 0xffffffff
FSF cmnd       : 0xffffffff
FSF sequence no: 0xffffffff
WWPN           : 0x500507680b26c449
LUN            : 0x01d0000000000000
Return Value   : 0xfffffff4

Timestamp      : 2026-02-02-10:50:02:475037
Area           : HBA
Subarea        : 00
Level          : 4
Exception      : -
CPU ID         : 0003
Caller         : 0x000001d89a86bd0e
Record ID      : 6
Tag            : sysuas2
Description    : sysuas2 HBA, Sysfs unit add store failure, unit add failed
Request ID     : 0x00000000ffffffff
Request status : 0xffffffff
FSF cmnd       : 0xffffffff
FSF sequence no: 0xffffffff
WWPN           : 0x500507680b26c449
LUN            : 0x01d1000000000000
Return Value   : 0xfffffff4

Signed-off-by: Chinmaya Kajagar <chinmayk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-10 11:21:23 +02:00
Vasily Gorbik
50f909db8f zipl/boot: Fix stage3 secure boot trailer placement
The stage3 linker script places .sb.trailer so that it must end at
COMMAND_LINE_EXTRA. The current script derives the start address from
SIZEOF(.sb.trailer) before the section is emitted:

  . = COMMAND_LINE_EXTRA - SIZEOF(.sb.trailer);

With binutils older than 2.39 before commit 648f6099d4dc ("-z relro
relaxation and ld script SIZEOF") this can result in .sb.trailer being
placed at COMMAND_LINE_EXTRA instead, moving the trailer into the
following area and breaking the expected layout.

The trailer has a fixed size, so use an explicit constant for the
placement calculation and keep the ASSERT to verify the final section
size. This makes the placement deterministic again.

Fixes: a1126352ec ("zipl/boot: Improve linker scripts")
Reviewed-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-10 11:21:23 +02:00
Harald Freudenberger
d0046257b6 lszcrypt/chzcrypt: Warn if default domain is unavailable
Improvements for lszcrypt and chzcrypt:
* lszcrypt -b and lszcrypt -d now check for default domain
  available and gives a warning if the current default domain
  is not in the usage_domain_mask of the AP bus.
* lszcrypt without any further device also checks for the
  default domain and emits a warning string if the default
  domain is not available.
* chzcrypt --default-domain emits a warning if the newly
  set default domain is not enabled in the usage_domain_mask
  of the AP bus.

Suggested-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:25:25 +01:00
Ajaykumar Rajappa
daad3bf0e7 ziomon: Send MQ poll status messages to stdout
Move MQ poll status messages from stderr to stdout since they are
normal progress indications rather than warnings/errors.

Signed-off-by: Ajaykumar Rajappa <ajaykr@linux.ibm.com>
Reviewed-by: M Nikhil <nikh1092@linux.ibm.com>
Reviewed-by: Nihar Panda <niharp@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:25:18 +01:00
Ajaykumar Rajappa
6537f711a6 ziomon: Ignore benign blkiomon early-read warnings
The blkiomon warnings "bad trace magic 0" and "blkiomon: bad trace" are
benign startup artifacts caused by early pipeline reads before blktrace
produces a complete record. These messages do not affect processing and
valid reports are still generated. Filter them out so only real errors
trigger failures.

Signed-off-by: Ajaykumar Rajappa <ajaykr@linux.ibm.com>
Reviewed-by: Nihar Panda <niharp@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:25:13 +01:00
Mete Durlu
7c75df9e96 hyptop/opts: Fix long command line option abbreviations
Hyptop should be able to accept abbreviations of the long command line
options as getopt() is able to match them. Ex;

$ hyptop --batch-mode

$ hyptop --batch

$ hyptop --bat

From getopt(3) man page:
"""
  Long option names may be abbreviated if the abbreviation is unique
  or is an exact match for some defined option.
"""

After the introduction of commit c5695e43c4 ("hyptop/opts: Replace long
option formats for consistency") long command line options for hyptop
received additional definitions to support dash separated option formats.
Unfortunately these definitions were defined as new and unique options
and caused an ambiguity for getopt() when abbreviations matched both
definitions. Ex;

$ hyptop --batch
hyptop: option '--batch' is ambiguous;
possibilities: '--batch-mode' '--batch_mode'

Map both long option formats to the same short option to fix the
issue and restore the functionality.

Fixes: c5695e43c4 ("hyptop/opts: Replace long option formats for consistency")
Reported-by: Gorkem Kilinc <kilinc@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:25:03 +01:00
Mete Durlu
376ddfbd22 hyptop/opts: Replace sort_field option with sort
Hyptop's "--sort_field" command line option has always been documented
as "--sort", while the code _only_ explicitly has "--sort_field".
Specifying the shorter "--sort" happened to work due to an unnoticed
getopt() behavior.

From getopt(3) man page:
"""
  Long option names may be abbreviated if the abbreviation is unique
  or is an exact match for some defined option.
"""

With the addition of "--sort-field" as another unique identifier via
commit c5695e43c4 ("hyptop/opts: Replace long option formats for
consistency") "--sort" is no longer unique. getopt() won't be able to
use that as an abbreviation, since there is ambiguity between
"--sort_field" and new "--sort-field" as they are defined as separate
options.

Replace "--sort-field" and "--sort_field" with plain "--sort" to adhere
to the documented hyptop command line argument specification and resolve
the broken behavior.

Fixes: c5695e43c4 ("hyptop/opts: Replace long option formats for consistency")
Reported-by: Gorkem Kilinc <kilinc@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:46 +01:00
Holger Dengler
1afa6efb26 lszcrypt: Change exit code to 0 for empty device list
An empty device list is not an error case, if `lszcrypt` is called
without a specific device list or device filter. Return with rc == 0 in
such cases.

Remove the message about the empty device list on stderr.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:42 +01:00
Jan Höppner
69c89416b0 lsznet: Remove support for lcs device type
Kernel support for LCS devices was removed with commit 6cccb3bb0561
("s390/net: Remove LCS driver") in kernel v6.15. Remove the associated
lsznet support for the lcs device type.

Reviewed-by: Aswin Karuvally <aswin@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:38 +01:00
Jan Höppner
81e0d02d90 znetcontrolunits: Remove znetcontrolunits library
znetcontrolunits provided two arrays and a search function that were
only used by lsznet. Since lsznet has it's own implementation of this
function now and the CU array was a duplicate of CU_TCPIP anyway, remove
znetcontrolunits as it serves no purpose.

Reviewed-by: Aswin Karuvally <aswin@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:36 +01:00
Jan Höppner
d41d968792 znet: Move functionality from znetcontrolunits to lsznet
lsznet sources znetcontrolunits to use search_cu() and set the variable
cu_idx. lsznet's own function search_cu_tcpip() is doing the same thing
as search_cu() without setting cu_idx.

Declare and move cu_idx to the global variable CU_IDX and consolidate
the functions by letting search_cu_tcpip() set CU_IDX. Call
search_cu_tcpip() instead of search_cu() and replace cu_idx with CU_IDX
accordingly. search_cu() is removed and the CU_DEVDRV array is moved to
lsznet.

Reviewed-by: Aswin Karuvally <aswin@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:35 +01:00
Jan Höppner
c81ca8f01b lsznet: Convert space indentation to tabs
Reviewed-by: Aswin Karuvally <aswin@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:33 +01:00
Mikhail Zaslonko
73ab25f419 zipl/boot: Add secure boot option to the dump programm
With SECURE_BOOT_DISABLED always set in add_dump_program() no signature
entries for a dump kernel are written. This might lead to security
violation error from the IPL Loader on the systems with secure boot support
on the attempt to boot the dump kernel:
  MLOLOA6269321F A security violation error was encountered when loading from device <device>
  MLOLOA62693212 Audit: No signed components found for program 0 loaded from device <device>

Propagate '--secure' zipl option to add_dump_program() in order to sign
relevant components upon dump program installation and thus support
secure boot execution for List-directed dump kernels.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Tested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:23 +01:00
Chinmaya Kajagar
6fc1ed1a67 zfcpdbf: Print plogi and prli within open port response as payload
Print plogi and prli of each incoming open port response. Additional
payload ‘fsf_els’ HBA area to trace and print the new open port response
details.

Relevant kernel dbf structure changes are done in a separate patch. New
fields plogi_len and prli_len (u32 i.e. 4 hex digits at new appended
offsets 112 and 120) and payload record(s) are available.
The kernel structure with added members,
struct zfcp_dbf_hba_res {
	u64                        req_issued;           /*     0     8 */
	u32                        prot_status;          /*     8     4 */
	u8                         prot_status_qual[16]; /*    12    16 */
	u32                        fsf_status;           /*    28     4 */
	u8                         fsf_status_qual[16];  /*    32    16 */
	u32                        port_handle;          /*    48     4 */
	u32                        lun_handle;           /*    52     4 */
	u32                        plogi_len;            /*    56     4 */
	u32                        prli_len;             /*    60     4 */
};

zfcpdbf partial output for HBA area with relevant kernel code changes
displaying PLOGI/ PRLI info log with length for each:

PLOGI length   : 116
PRLI length    : 20
Payload time   : 2026-01-29-06:19:15:626629
PLOGI/PRLIinfo : 02000000 00000000 80000800 000a0002
                 00000000 2002000e 1115c62f 2001000e
                 1115c62f 00000000 00000000 00000000
                 00000000 80000000 00000000 00000000
                 00000000 80000000 00000000 000a0000
                 00010000 00000000 00000000 00000000
                 00000000 00000000 00000000 00000000
                 00000000 02100014 08002100 00000000
                 00000000 00000112

Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
Signed-off-by: Chinmaya Kajagar <chinmayk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:16 +01:00
Chinmaya Kajagar
1c3547d205 zfcpdbf: Trace all fsf status read buffer fields under HBA
This patch is to enhance fsf status read buffer tracing. Add remaining
status read buffer (SRB) fields including S_ID and reserved fields under
HBA trace area.

Relevant kernel dbf structure changes are done in a seperate patch.

zfcpdbf output for HBA area with relevant kernel code changes:

Timestamp      : 2025-08-22-05:52:04:171750
Area           : HBA
Subarea        : 00
Level          : 2
Exception      : -
CPU ID         : 0003
Caller         : 0x0000021e278c07c8
Record ID      : 2
Tag            : fssrh_4
Description    : fssrh_4 HBA, FSF unsolicited status
Request ID     : 0x0000000000004bfc
Request status : 0x00000000
FSF cmnd       : 0x00006305
FSF sequence no: 0x00000000
SRB stat type  : 0x00000002
SRB stat sub   : 0x00000000
SRB D_ID       : 0x00fffffd
SRB LUN        : 0x0000000000000000
SRB q-design.  : 0x0000000000000000
SRB length     : 0x0000004c
SRB res1       : 0x00000000
SRB res2       : 0x00
SRB class      : 0x00000000
SRB res3       : 0x00
SRB S_ID       : 0x0033c048
SRB res4       : 00000000 00000000 00000000 00000000
                 00000000
SRB pay length : 12
Payload time   : 2025-08-22-05:52:04:171743
SRB info       : 6104000c 0033c024 0033c02e

Signed-off-by: Chinmaya Kajagar <chinmayk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:11 +01:00
Vineeth Vijayan
b6bb87f377 zdev: Remove support for lcs device type
Kernel support for LCS devices was removed with commit 6cccb3bb0561
("s390/net: Remove LCS driver") in kernel v6.15. Remove the associated
zdev support for the lcs device type.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:07 +01:00
Jan Höppner
bd0bb9dd5c zipl/man: Remove trailing whitespace
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:05 +01:00
Jan Höppner
075f7f7186 zipl/man: Only mention 3490 tape devices
The Virtual Tape Server (VTS) only supports 3490 tape devices. Remove
all other older device types from the man pages.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:04 +01:00
Jan Höppner
5af1e8cc69 zipl/tape2dump: Remove check for data compaction support
Data compaction is only supported by 3490 tape devices. For Virtual Tape
Server (VTS) this is the only supported device. Reading device
characteristics and checking the type is unnecessary.

Remove the corresponding code and simply enable data compaction.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:02 +01:00
Jan Höppner
145c21a9ca zipl/tape2dump: Remove load display command
Load Display (LDD) X'9F' is still accepted by the Virtual Tape Server
(VTS) but does not perform any action. Remove code that still uses this
command in tape2dump.c.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:01 +01:00
Jan Höppner
1bd8ee4b79 lstape: Remove type filter support
There is only one supported tape device type left. A filter command line
option doesn't make any sense anymore.

Remove the functionality and documentation of the --type option.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:00 +01:00
Jan Höppner
4f0dfae97e lstape: Remove 3480 and 3590 tape support
The device models 3480 and 3590 are no longer supported by the tape
device driver. Remove them from the device list

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:23:58 +01:00
Jan Höppner
3d6bb988c2 lstape: Remove trailing whitespace
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:23:57 +01:00
Jan Höppner
8f83002e37 tape390: Remove tape390_display and tape390_crypt
The tape390_display tool was used to send text to the display of tape
storage server. The corresponding command is still accepted by the
Virtual Tape Server (VTS) but no action is performed. The tool is
useless, remove it.

The tape390_crypt tool was used to manage encryption for tape devices.
However, only 3590/3592 models did support encryption. Support for these
models is removed from the Kernel as there is no support for these tape
models in general anymore. The tool is not required anymore, remove it.

Note: VTS uses encryption transparantly for its virtualized 3490 models.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:23:55 +01:00
Mikhail Zaslonko
d92f419836 zdump/dfi: Fix dump header check for dfi_s390tape
The magic number used in the dump header for all stage2 dumps (including
tape dump) is DF_S390_MAGIC_EXT since commit ff475d9c7d0a ("zipl: Extend
DASD stand-alone dumpers to drop zero pages").
Adjust dfi_s390tape code accordingly.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:23:52 +01:00
Jan Höppner
8ff8b40182 Prepare for next release
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2026-02-16 15:34:05 +01:00
194 changed files with 6359 additions and 4037 deletions

52
.gitignore vendored
View File

@@ -25,7 +25,7 @@ compile_commands.json
#
**/.detect-openssl.dep.c
*.debug
*/autocompletion_generator_host
**/autocompletion_generator_host
ap_tools/ap-check
cmsfs-fuse/cmsfs-fuse
cpacfstats/cpacfstats
@@ -50,12 +50,22 @@ dasdfmt/dasdfmt
dasdfmt/_dasdfmt
dasdfmt/dasdfmt.bash
dasdinfo/dasdinfo
dasdinfo/_dasdinfo
dasdinfo/dasdinfo.bash
dasdview/dasdview
dasdview/_dasdview
dasdview/dasdview.bash
dump2tar/src/dump2tar
dump2tar/src/_dump2tar
dump2tar/src/dump2tar.bash
fdasd/fdasd
fdasd/_fdasd
fdasd/fdasd.bash
hmcdrvfs/hmcdrvfs
hsavmcore/check-dep-fuse
hsavmcore/hsavmcore
hsavmcore/_hsavmcore
hsavmcore/hsavmcore.bash
hyptop/hyptop
ip_watcher/xcec-bridge
ipl_tools/chreipl
@@ -88,34 +98,58 @@ libutil/*_example
libvmcp/vmcp_example
libzds/libzds.a
lsstp/lsstp
lsstp/_lsstp
lsstp/lsstp.bash
mon_tools/mon_fsstatd
mon_tools/mon_procd
opticsmon/opticsmon
opticsmon/_opticsmon
opticsmon/opticsmon.bash
osasnmpd/osasnmpd
qetharp/qetharp
qethqoat/qethqoat
systemd/cpacfstatsd.service
systemd/iucvtty-login@.service
systemd/ttyrun-getty@.service
tape390/tape390_crypt
tape390/tape390_display
tunedasd/src/tunedasd
tunedasd/src/_tunedasd
tunedasd/src/tunedasd.bash
vmcp/vmcp
vmcp/_vmcp
vmcp/vmcp.bash
vmur/vmur
zconf/chp/chchp
zconf/chp/_chchp
zconf/chp/chchp.bash
zconf/chp/lschp
zconf/chp/_lschp
zconf/chp/lschp.bash
zconf/chp/chpstat/chpstat
zconf/chp/chpstat/_chpstat
zconf/chp/chpstat/chpstat.bash
zconf/css/lscss
zconf/css/_lscss
zconf/css/lscss.bash
zconf/qeth/lsqeth
zconf/qeth/_lsqeth
zconf/qeth/lsqeth.bash
zconf/scm/lsscm
zconf/scm/_lsscm
zconf/scm/lsscm.bash
zconf/zcrypt/chzcrypt
zconf/zcrypt/_chzcrypt
zconf/zcrypt/chzcrypt.bash
zconf/zcrypt/lszcrypt
zconf/zcrypt/_lszcrypt
zconf/zcrypt/lszcrypt.bash
zconf/zcrypt/zcryptctl
zconf/zcrypt/zcryptstats
zconf/zcrypt/_zcryptstats
zconf/zcrypt/zcryptstats.bash
zdev/src/chzdev
zdev/src/chzdev_usage.c
zdev/src/chzdev_usage.h
zdev/src/lszdev
zdev/src/lszdev_usage.c
zdev/src/lszdev_usage.h
zdev/src/zdev_id
zdsfs/zdsfs
zdump/.check_dep_fuse
@@ -139,6 +173,8 @@ zipl/src/chreipl_helper.device-mapper
zipl/src/chreipl_helper.md
zipl/src/zipl
zipl/src/zipl-editenv
zipl/src/_zipl-editenv
zipl/src/zipl-editenv.bash
zipl/src/zipl_helper.device-mapper
zipl/src/zipl_helper.md
zkey/check-dep-zkey
@@ -151,5 +187,11 @@ zkey/kmip/zkey-kmip.so
zkey/zkey
zkey/zkey-cryptsetup
zmemtopo/zmemtopo
zmemtopo/_zmemtopo
zmemtopo/zmemtopo.bash
zpcictl/zpcictl
zpcictl/_zpcictl
zpcictl/zpcictl.bash
zpwr/zpwr
zpwr/_zpwr
zpwr/zpwr.bash

View File

@@ -17,6 +17,7 @@ List of all individuals having contributed content to s390-tools
- Bjoern Walk
- Brian C. Lane
- Carsten Otte
- Chinmaya Kajagar
- Christian Borntraeger
- Christian Ehrhardt
- Christof Schmitt

View File

@@ -1,6 +1,37 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.42.0 (2026-04-30)__
For Linux kernel version: 7.0
Add new tools / libraries:
- Enable zsh and bash autocompletion for various tools
- pvebc: Resolve ASR integrity structure for EBC
- pvics: Generate SEL guests from base images
Remove:
- tape390_display and tape390_crypt removed due to long gone hardware support
- znetcontrolunits: Remove znetcontrolunits library
Changes of existing tools:
- cpumf/pai: Install SIGINT/SIGTERM handler for graceful termination
- dbginfo.sh: Add command zmemtopo
- libutil/util_fmt: Add support for JSON Lines text format
- lstape: Remove 3480 and 3590 tape support
- lsznet: Remove support for lcs device type
- pvsecret: Add support for ASR integrity structure for EBC
- zfcpdbf: Print plogi and prli within open port response as payload
- zfcpdbf: Trace all fsf status read buffer fields under HBA
- zipl/boot: Add secure boot option to the dump programm
- zkey, libekmfweb, libseckey, libkmipclient: Adjust for OpenSSL v4.0.0 API
changes and deprecations
Bug Fixes:
- hyptop/opts: Fix long command line option abbreviations
- libutil/util_autocomp: Fix default file completion
- zipl/boot: Fix stage3 secure boot trailer placement
* __v2.41.0 (2026-02-16)__
For Linux kernel version: 6.19

View File

@@ -11,7 +11,7 @@ BASELIB_DIRS = libutil libseckey
LIB_DIRS = libvtoc libzds libdasd libccw libvmcp libekmfweb \
libkmipclient libcpumf libap libpv libzpci
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \

View File

@@ -30,6 +30,8 @@ Package contents
Manage secrets for IBM Secure Execution guests
- pvimg:
Create and inspect IBM Secure Execution images
- pvebc:
Verify a secret structure for IBM Secure Execution for Linux.
* dasdfmt:
Low-level format ECKD DASDs with the classical Linux disk layout or the new
@@ -50,6 +52,10 @@ Package contents
Create an IBM Secure Execution (protected virtualization) image. The
genprotimg command is a symbolic link to the `pvimg create` command.
* pvics:
Convert a qcow2 image to a qcow2 image ready to boot as IBM Secure Execution
for Linux guest.
* udev rules:
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
- 57-osasnmpd.rules: udev rules for osasnmpd.
@@ -79,13 +85,6 @@ Package contents
* qetharp:
Read and flush the ARP cache on OSA Express network cards.
* tape390_display:
Display information on the message display facility of a s390 tape
device.
* tape390_crypt:
Control and query crypto settings for 3592 tape devices.
* osasnmpd:
NET-SNMP subagent implementing MIBs provided by OSA-Express
features Fast Ethernet, Gigabit Ethernet, 10 Gigabit Ethernet.

View File

@@ -32,7 +32,7 @@ endif
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION := 2
RELEASE := 41
RELEASE := 42
PATCHLEVEL := 0
DISTRELEASE := build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)

View File

@@ -1,11 +1,7 @@
// SPDX-License-Identifier: MIT
/*
* Autocompletion generation - for cpumf family of tools
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"

View File

@@ -1,11 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* Command line utilities - for chcpumf
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#ifndef CHCPUMF_CLI_H

View File

@@ -1,11 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* Command line utilities - for lscpumf
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#ifndef LSCPUMF_CLI_H

View File

@@ -700,7 +700,7 @@ static int do_it(char *s)
if (output_format == FMT_CSV)
flags |= FMT_NOMETA;
if (output_format == FMT_JSON || output_format == FMT_JSONSEQ)
if (util_fmt_is_json(output_format))
flags |= FMT_HANDLEINT;
if (quote_all)
flags |= FMT_QUOTEALL;
@@ -708,7 +708,7 @@ static int do_it(char *s)
mk_labels();
util_fmt_init(stdout, output_format, flags, 1);
util_fmt_obj_start(FMT_DEFAULT, "lshwc");
if (output_format == FMT_JSON || output_format == FMT_JSONSEQ) {
if (util_fmt_is_json(output_format)) {
util_fmt_obj_start(FMT_ROW, "cpumcf info");
util_fmt_pair(FMT_PERSIST, "counter first", "%d", cfvn);
util_fmt_pair(FMT_PERSIST, "counter second", "%d", csvn);

View File

@@ -1,11 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* Command line utilities - for lshwc
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#ifndef LSHWC_CLI_H

View File

@@ -1,11 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* Command line utilities - for lspai
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#ifndef LSPAI_CLI_H

View File

@@ -138,7 +138,7 @@ Apply quoting to every output element, regardless of content or format.
.TP
.BR \-f ", " \-\-format \fI\ FORMAT\fP
Retrieve output in one of the following formats:
JSON, CSV, JSON-SEQ or PAIRS.
JSON, CSV, JSON-SEQ, JSONL or PAIRS.
If no format is specified, the output defaults to CSV.
.
.SS JSON Output Structure

View File

@@ -136,7 +136,7 @@ Default sort order is PAI counter name.
.TP
.BI \-\-format "\ FORMAT"
Retrieve output in one of the following formats:
JSON, csv, json-seq or pairs.
JSON, csv, json-seq, jsonl or pairs.
If no format is specified,
the output defaults to a human-readable format.
.

View File

@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
@@ -47,6 +48,8 @@
#define S390_EVT_PAI_CRYPTO 0x1000
#define S390_EVT_PAI_NNPA 0x1800
/* SIGINT or SIGTERM signal received */
static volatile unsigned int sigterm;
/* Default values for select() timeout: 1 second */
static unsigned long read_interval = 1000;
/* Size of mapped perf event ring buffer in 4KB pages.
@@ -350,6 +353,10 @@ static int collect(unsigned long cnt)
if (FD_ISSET(i, &r_fds))
readmap(i);
}
} else if (errno == EINTR && sigterm) {
/* Interrupt by signal SIGINT/SIGTERM, one more iteration */
cnt = 2;
rc = 0;
}
} while (rc != -1 && --cnt > 0);
return rc;
@@ -983,6 +990,12 @@ static void setprio(const char *prio)
err(EXIT_FAILURE, "Could not set realtime priority");
}
static void sig_handler(int no)
{
if (no == SIGINT || no == SIGTERM)
sigterm = 1;
}
int main(int argc, char **argv)
{
bool crypto_record = false, report = false;
@@ -1070,6 +1083,10 @@ int main(int argc, char **argv)
errx(EXIT_FAILURE, "Invalid argument for runtime");
}
if (signal(SIGTERM, sig_handler) == SIG_ERR ||
signal(SIGINT, sig_handler) == SIG_ERR)
errx(EXIT_FAILURE, "Failed to set signal handler");
ev_install(group);
ev_enable();

View File

@@ -1,11 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* Command line utilities - for pai
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#ifndef PAI_CLI_H

View File

@@ -1,11 +1,7 @@
// SPDX-License-Identifier: MIT
/*
* Autocompletion generation - for dasdfmt tool
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"

View File

@@ -1,11 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* Command line utilities - for dasdfmt
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* Copyright IBM Corp.
*/
#ifndef DASDFMT_CLI_H

View File

@@ -1,5 +1,10 @@
include ../common.mak
zsh-completions = _dasdinfo
bash-completions = dasdinfo.bash
include ../common_autocomp.mak
libs = $(rootdir)/libutil/libutil.a \
$(rootdir)/libdasd/libdasd.a

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "dasdinfo_cli.h"
int main(void)
{
generate_autocomp(opt_vec, "dasdinfo");
return 0;
}

View File

@@ -30,6 +30,8 @@
#include "lib/util_path.h"
#include "lib/zt_common.h"
#include "dasdinfo_cli.h"
#define RD_BUFFER_SIZE 80
#define TEMP_DEV_MAX_RETRIES 1000
@@ -50,49 +52,6 @@ static const struct util_prg prg = {
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("DEVICE"),
{
.option = { "block", required_argument, NULL, 'b' },
.argument = "BLOCKDEV",
.desc = "Block device name, e.g. dasdb",
},
{
.option = { "devnode", required_argument, NULL, 'd' },
.argument = "DEVNODE",
.desc = "Device node, e.g. /dev/dasda",
},
{
.option = { "busid", required_argument, NULL, 'i' },
.argument = "BUSID",
.desc = "Bus ID, e.g. 0.0.e910",
},
UTIL_OPT_SECTION("OPTIONS"),
{
.option = { "label", no_argument, NULL, 'l' },
.desc = "Print DASD volume label (volser)",
},
{
.option = { "uid", no_argument, NULL, 'u' },
.desc = "Print DASD uid (without z/VM minidisk token)",
},
{
.option = { "extended-uid", no_argument, NULL, 'x' },
.desc = "Print DASD uid (including z/VM minidisk token)",
},
{
.option = { "all", no_argument, NULL, 'a' },
.desc = "Same as -u -x -l",
},
{
.option = { "export", no_argument, NULL, 'e' },
.desc = "Export ID_BUS, ID_TYPE, ID_SERIAL for use in udev",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
/* needed because ftw can not pass arbitrary arguments */
static char *searchbusid;
static char *busiddir;
@@ -101,9 +60,9 @@ struct volume_label {
char volkey[4];
char vollbl[4];
char volid[6];
} __attribute__ ((packed));
} __packed;
static char EBCtoASC[256] = {
static char ebc_to_asc[256] = {
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
@@ -175,7 +134,7 @@ static char *dinfo_ebcdic_dec(char *source, char *target, int l)
int i;
for (i = 0; i < l; i++)
target[i] = EBCtoASC[(unsigned char)(source[i])];
target[i] = ebc_to_asc[(unsigned char)(source[i])];
return target;
}
@@ -261,7 +220,7 @@ static void *dinfo_malloc(size_t size)
void *result;
result = malloc(size);
if (result == NULL)
if (!result)
warnx("Could not allocate %lu bytes of memory", size);
return result;
@@ -274,7 +233,7 @@ static char *dinfo_make_path(char *dirname, char *filename)
len = strlen(dirname) + strlen(filename) + 2;
result = (char *)dinfo_malloc(len);
if (result == NULL)
if (!result)
return NULL;
sprintf(result, "%s/%s", dirname, filename);
return result;
@@ -296,12 +255,12 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
/* Try several locations for the temporary device node. */
for (path = 0; path < ARRAY_SIZE(pathname); path++) {
if (pathname[path] == NULL)
if (!pathname[path])
continue;
for (retry = 0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
snprintf(filename, sizeof(filename), "dasdinfo%04d", retry);
result = dinfo_make_path(pathname[path], filename);
if (result == NULL)
if (!result)
return -1;
rc = mknod(result, mode, dev);
if (rc == 0) {
@@ -342,7 +301,7 @@ static int dinfo_extract_dev(dev_t *dev, char *str)
memset(tmp, 0, RD_BUFFER_SIZE);
util_strlcpy(tmp, str, RD_BUFFER_SIZE);
p = strchr(tmp, ':');
if (p == NULL) {
if (!p) {
warnx("Error: unable to extract major/minor");
return -1;
}
@@ -401,14 +360,14 @@ dinfo_is_busiddir(const char *fpath, const struct stat *UNUSED(sb),
return -1;
linkdir = util_readlink(tempdir);
free(tempdir);
if (strstr(linkdir, "dasd") == NULL) {
if (!strstr(linkdir, "dasd")) {
free(linkdir);
return FTW_CONTINUE;
}
free(linkdir);
free(busiddir);
busiddir = strdup(fpath);
if (busiddir == NULL)
if (!busiddir)
return -1;
return FTW_STOP;
}
@@ -421,7 +380,7 @@ dinfo_find_entry(const char *dir, const char *searchstring,
struct dirent *dir_entry = NULL;
directory = opendir(dir);
if (directory == NULL)
if (!directory)
return -1;
while ((dir_entry = readdir(directory)) != NULL) {
/* compare if the found entry has exactly the same name and type
@@ -431,7 +390,7 @@ dinfo_find_entry(const char *dir, const char *searchstring,
strlen(searchstring)) == 0) &&
(dir_entry->d_type & type)) {
*result = strdup(dir_entry->d_name);
if (*result == NULL)
if (!*result)
goto out;
closedir(directory);
return 0; /* found */
@@ -477,7 +436,7 @@ dinfo_get_blockdev_from_busid(char *busid, char **blkdev)
if (rc != 0)
goto out2;
*blkdev = strdup(strchr(result, ':') + 1);
if (*blkdev == NULL)
if (!*blkdev)
rc = -1;
}
@@ -510,7 +469,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
path = util_path_sysfs("block/");
directory = opendir(path);
if (directory == NULL) {
if (!directory) {
warnx("Error: could not open directory %s", path);
free(path);
return -1;
@@ -550,8 +509,6 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
int main(int argc, char *argv[])
{
struct utsname uname_buf;
int version, release;
char *uidfile = NULL;
char *device = NULL;
char *readbuf = NULL;
@@ -611,35 +568,19 @@ int main(int argc, char *argv[])
util_prg_print_version();
exit(EXIT_SUCCESS);
default:
fprintf(stderr, "Try 'dasdinfo --help' for more "
"information.\n");
fprintf(stderr, "Try 'dasdinfo --help' for more information.\n");
exit(1);
}
}
uname(&uname_buf);
sscanf(uname_buf.release, "%d.%d", &version, &release);
if (strcmp(uname_buf.sysname, "Linux") ||
version < 2 || (version == 2 && release < 6)) {
warnx("%s %d.%d is not supported", uname_buf.sysname,
version, release);
exit(1);
}
if (!busid && !blockdev && !devnode)
errx(EXIT_FAILURE, "Error: please specify a device using either -b, -i or -d");
if (!busid && !blockdev && !devnode) {
warnx("Error: please specify a device using either -b, -i or -d");
exit(1);
}
if ((busid && blockdev) || (busid && devnode) || (blockdev && devnode))
errx(EXIT_FAILURE, "Error: please specify device only once, either -b, -i or -d");
if ((busid && blockdev) || (busid && devnode) || (blockdev && devnode)) {
warnx("Error: please specify device only once, either -b, -i or -d");
exit(1);
}
if (!print_uid && !print_extended_uid && !print_vlabel) {
warnx("Error: no action specified (e.g. -u)");
exit(1);
}
if (!print_uid && !print_extended_uid && !print_vlabel)
errx(EXIT_FAILURE, "Error: no action specified (e.g. -u)");
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
if (!readbuf)

55
dasdinfo/dasdinfo_cli.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef DASDINFO_CLI_H
#define DASDINFO_CLI_H
#include "lib/util_opt.h"
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("DEVICE"),
{
.option = { "block", required_argument, NULL, 'b' },
.argument = "BLOCKDEV",
.desc = "Block device name, e.g. dasdb",
},
{
.option = { "devnode", required_argument, NULL, 'd' },
.argument = "DEVNODE",
.desc = "Device node, e.g. /dev/dasda",
},
{
.option = { "busid", required_argument, NULL, 'i' },
.argument = "BUSID",
.desc = "Bus ID, e.g. 0.0.e910",
},
UTIL_OPT_SECTION("OPTIONS"),
{
.option = { "label", no_argument, NULL, 'l' },
.desc = "Print DASD volume label (volser)",
},
{
.option = { "uid", no_argument, NULL, 'u' },
.desc = "Print DASD uid (without z/VM minidisk token)",
},
{
.option = { "extended-uid", no_argument, NULL, 'x' },
.desc = "Print DASD uid (including z/VM minidisk token)",
},
{
.option = { "all", no_argument, NULL, 'a' },
.desc = "Same as -u -x -l",
},
{
.option = { "export", no_argument, NULL, 'e' },
.desc = "Export ID_BUS, ID_TYPE, ID_SERIAL for use in udev",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#endif

View File

@@ -1,5 +1,10 @@
include ../common.mak
zsh-completions = _dasdview
bash-completions = dasdview.bash
include ../common_autocomp.mak
libs = $(rootdir)/libdasd/libdasd.a \
$(rootdir)/libzds/libzds.a \
$(rootdir)/libvtoc/libvtoc.a \

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "dasdview_cli.h"
int main(void)
{
generate_autocomp(opt_vec, "dasdview");
return 0;
}

View File

@@ -37,6 +37,7 @@
#include "lib/zt_common.h"
#include "dasdview.h"
#include "dasdview_cli.h"
/* Characters per line */
#define DASDVIEW_CPL 16
@@ -56,61 +57,6 @@ static const struct util_prg prg = {
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("DUMP OPTIONS"),
{
.option = { NULL, no_argument, NULL, '1' },
.desc = "Show DASD content in short Hex/EBCDIC/ASCII format",
.flags = UTIL_OPT_FLAG_NOLONG,
},
{
.option = { NULL, no_argument, NULL, '2' },
.desc = "Show DASD content in detailed Hex/EBCDIC/ASCII format",
.flags = UTIL_OPT_FLAG_NOLONG,
},
{
.option = { "begin", required_argument, NULL, 'b' },
.argument = "BEGIN",
.desc = "Specify start of dump in kilobytes (suffix k), "
"megabytes (m), blocks (b), tracks (t), or cylinders (c)",
},
{
.option = { "size", required_argument, NULL, 's' },
.argument = "SIZE",
.desc = "Specify size of dump in kilobytes (suffix k), "
"megabytes (m), blocks (b), tracks (t), or cylinders (c)",
},
UTIL_OPT_SECTION("MISC"),
{
.option = { "characteristic", no_argument, NULL, 'c' },
.desc = "Print the characteristics of a device",
},
{
.option = { "info", no_argument, NULL, 'i' },
.desc = "Print general DASD information and geometry",
},
{
.option = { "volser", no_argument, NULL, 'j' },
.desc = "Print the volume serial number",
},
{
.option = { "label", no_argument, NULL, 'l' },
.desc = "Print information about the volume label",
},
{
.option = { "vtoc", required_argument, NULL, 't' },
.argument = "SPEC",
.desc = "Print the table of content (VTOC)",
},
{
.option = { "extended", no_argument, NULL, 'x' },
.desc = "Print extended DASD information",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
/*
* Generate and print an error message based on the formatted
* text string FMT and a variable amount of extra arguments.

67
dasdview/dasdview_cli.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef DASDVIEW_CLI_H
#define DASDVIEW_CLI_H
#include "lib/util_opt.h"
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("DUMP OPTIONS"),
{
.option = { NULL, no_argument, NULL, '1' },
.desc = "Show DASD content in short Hex/EBCDIC/ASCII format",
.flags = UTIL_OPT_FLAG_NOLONG,
},
{
.option = { NULL, no_argument, NULL, '2' },
.desc = "Show DASD content in detailed Hex/EBCDIC/ASCII format",
.flags = UTIL_OPT_FLAG_NOLONG,
},
{
.option = { "begin", required_argument, NULL, 'b' },
.argument = "BEGIN",
.desc = "Specify start of dump in kilobytes (suffix k), "
"megabytes (m), blocks (b), tracks (t), or cylinders (c)",
},
{
.option = { "size", required_argument, NULL, 's' },
.argument = "SIZE",
.desc = "Specify size of dump in kilobytes (suffix k), "
"megabytes (m), blocks (b), tracks (t), or cylinders (c)",
},
UTIL_OPT_SECTION("MISC"),
{
.option = { "characteristic", no_argument, NULL, 'c' },
.desc = "Print the characteristics of a device",
},
{
.option = { "info", no_argument, NULL, 'i' },
.desc = "Print general DASD information and geometry",
},
{
.option = { "volser", no_argument, NULL, 'j' },
.desc = "Print the volume serial number",
},
{
.option = { "label", no_argument, NULL, 'l' },
.desc = "Print information about the volume label",
},
{
.option = { "vtoc", required_argument, NULL, 't' },
.argument = "SPEC",
.desc = "Print the table of content (VTOC)",
},
{
.option = { "extended", no_argument, NULL, 'x' },
.desc = "Print extended DASD information",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#endif

View File

@@ -0,0 +1,136 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef DUMP2TAR_CLI_H
#define DUMP2TAR_CLI_H
#include "lib/util_opt.h"
#define OPT_NOSHORT_BASE 256
#define OPT_DEREFERENCE (OPT_NOSHORT_BASE + 0)
#define OPT_NORECURSION (OPT_NOSHORT_BASE + 1)
#define OPT_EXCLUDETYPE (OPT_NOSHORT_BASE + 2)
/* Definition of command line options */
static struct util_opt dump2tar_opts[] = {
UTIL_OPT_SECTION("OUTPUT OPTIONS"),
{
.option = { "output-file", required_argument, NULL, 'o' },
.argument = "FILE",
.desc = "Write archive to FILE (default: standard output)",
},
#ifdef HAVE_ZLIB
{
.option = { "gzip", no_argument, NULL, 'z' },
.desc = "Write a gzip compressed archive",
},
#endif /* HAVE_ZLIB */
{
.option = { "max-size", required_argument, NULL, 'm' },
.argument = "N",
.desc = "Stop adding files when archive size exceeds N bytes",
},
{
.option = { "timeout", required_argument, NULL, 't' },
.argument = "SEC",
.desc = "Stop adding files after SEC seconds",
},
{
.option = { "no-eof", no_argument, NULL, 131 },
.desc = "Do not write an end-of-file marker",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "add-cmd-status", no_argument, NULL, 132 },
.desc = "Add status of commands as separate file",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "append", no_argument, NULL, 133 },
.desc = "Append output to end of file",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("INPUT OPTIONS"),
{
.option = { "files-from", required_argument, NULL, 'F' },
.argument = "FILE",
.desc = "Read filenames from FILE (- for standard input)",
},
{
.option = { "ignore-failed-read", no_argument, NULL, 'i' },
.desc = "Continue after read errors",
},
{
.option = { "buffer-size", required_argument, NULL, 'b' },
.argument = "N",
.desc = "Read data in chunks of N byte (default: 16384)",
},
{
.option = { "file-timeout", required_argument, NULL, 'T' },
.desc = "Stop reading file after SEC seconds",
.argument = "SEC",
},
{
.option = { "file-max-size", required_argument, NULL, 'M' },
.argument = "N",
.desc = "Stop reading file after N bytes",
},
{
.option = { "jobs", required_argument, NULL, 'j' },
.argument = "N",
.desc = "Read N files in parallel (default: 1)",
},
{
.option = { "jobs-per-cpu", required_argument, NULL, 'J' },
.argument = "N",
.desc = "Read N files per CPU in parallel",
},
{
.option = { "exclude", required_argument, NULL, 'x' },
.argument = "PATTERN",
.desc = "Don't add files matching PATTERN",
},
{
.option = { "exclude-from", required_argument, NULL, 'X' },
.argument = "FILE",
.desc = "Don't add files matching patterns in FILE",
},
{
.option = { "exclude-type", required_argument, NULL,
OPT_EXCLUDETYPE },
.argument = "TYPE",
.desc = "Don't add files of specified TYPE (one of: fdcbpls)",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "dereference", no_argument, NULL, OPT_DEREFERENCE },
.desc = "Add link targets instead of links",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "no-recursion", no_argument, NULL,
OPT_NORECURSION },
.desc = "Don't add files from sub-directories",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("MISC OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
{
.option = { "verbose", no_argument, NULL, 'V' },
.desc = "Print additional informational output",
},
{
.option = { "quiet", no_argument, NULL, 'q' },
.desc = "Suppress printing of informational output",
},
UTIL_OPT_END,
};
#endif

View File

@@ -1,6 +1,11 @@
# Common definitions
include ../../common.mak
zsh-completions = _dump2tar
bash-completions = dump2tar.bash
include ../../common_autocomp.mak
ALL_CPPFLAGS += -I../include -Wno-unused-parameter
LDLIBS += -lpthread -lrt
ifneq ($(HAVE_ZLIB),0)

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "../include/dump2tar_cli.h"
int main(void)
{
generate_autocomp(dump2tar_opts, "dump2tar");
return 0;
}

View File

@@ -21,6 +21,7 @@
#include "lib/util_prg.h"
#include "dump.h"
#include "dump2tar_cli.h"
#include "global.h"
#include "idcache.h"
#include "misc.h"
@@ -28,12 +29,6 @@
#define MIN_BUFFER_SIZE 4096
#define OPT_NOSHORT_BASE 256
#define OPT_DEREFERENCE (OPT_NOSHORT_BASE + 0)
#define OPT_NORECURSION (OPT_NOSHORT_BASE + 1)
#define OPT_EXCLUDETYPE (OPT_NOSHORT_BASE + 2)
/* Program description */
static const struct util_prg dump2tar_prg = {
.desc = "Use dump2tar to create a tar archive from the contents "
@@ -52,124 +47,6 @@ static const struct util_prg dump2tar_prg = {
},
};
/* Definition of command line options */
static struct util_opt dump2tar_opts[] = {
UTIL_OPT_SECTION("OUTPUT OPTIONS"),
{
.option = { "output-file", required_argument, NULL, 'o' },
.argument = "FILE",
.desc = "Write archive to FILE (default: standard output)",
},
#ifdef HAVE_ZLIB
{
.option = { "gzip", no_argument, NULL, 'z' },
.desc = "Write a gzip compressed archive",
},
#endif /* HAVE_ZLIB */
{
.option = { "max-size", required_argument, NULL, 'm' },
.argument = "N",
.desc = "Stop adding files when archive size exceeds N bytes",
},
{
.option = { "timeout", required_argument, NULL, 't' },
.argument = "SEC",
.desc = "Stop adding files after SEC seconds",
},
{
.option = { "no-eof", no_argument, NULL, 131 },
.desc = "Do not write an end-of-file marker",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "add-cmd-status", no_argument, NULL, 132 },
.desc = "Add status of commands as separate file",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "append", no_argument, NULL, 133 },
.desc = "Append output to end of file",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("INPUT OPTIONS"),
{
.option = { "files-from", required_argument, NULL, 'F' },
.argument = "FILE",
.desc = "Read filenames from FILE (- for standard input)",
},
{
.option = { "ignore-failed-read", no_argument, NULL, 'i' },
.desc = "Continue after read errors",
},
{
.option = { "buffer-size", required_argument, NULL, 'b' },
.argument = "N",
.desc = "Read data in chunks of N byte (default: 16384)",
},
{
.option = { "file-timeout", required_argument, NULL, 'T' },
.desc = "Stop reading file after SEC seconds",
.argument = "SEC",
},
{
.option = { "file-max-size", required_argument, NULL, 'M' },
.argument = "N",
.desc = "Stop reading file after N bytes",
},
{
.option = { "jobs", required_argument, NULL, 'j' },
.argument = "N",
.desc = "Read N files in parallel (default: 1)",
},
{
.option = { "jobs-per-cpu", required_argument, NULL, 'J' },
.argument = "N",
.desc = "Read N files per CPU in parallel",
},
{
.option = { "exclude", required_argument, NULL, 'x' },
.argument = "PATTERN",
.desc = "Don't add files matching PATTERN",
},
{
.option = { "exclude-from", required_argument, NULL, 'X' },
.argument = "FILE",
.desc = "Don't add files matching patterns in FILE",
},
{
.option = { "exclude-type", required_argument, NULL,
OPT_EXCLUDETYPE },
.argument = "TYPE",
.desc = "Don't add files of specified TYPE (one of: fdcbpls)",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "dereference", no_argument, NULL, OPT_DEREFERENCE },
.desc = "Add link targets instead of links",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "no-recursion", no_argument, NULL,
OPT_NORECURSION },
.desc = "Don't add files from sub-directories",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("MISC OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
{
.option = { "verbose", no_argument, NULL, 'V' },
.desc = "Print additional informational output",
},
{
.option = { "quiet", no_argument, NULL, 'q' },
.desc = "Suppress printing of informational output",
},
UTIL_OPT_END,
};
/* Split buffer size specification in @arg into two numbers to be stored in
* @from_ptr and @to_ptr. Return %EXIT_OK on success. */
static int parse_buffer_size(char *arg, size_t *from_ptr, size_t *to_ptr)

View File

@@ -1,5 +1,10 @@
include ../common.mak
zsh-completions = _fdasd
bash-completions = fdasd.bash
include ../common_autocomp.mak
libs = $(rootdir)/libvtoc/libvtoc.a \
$(rootdir)/libzds/libzds.a \
$(rootdir)/libdasd/libdasd.a \

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "fdasd_cli.h"
int main(void)
{
generate_autocomp(opt_vec, "fdasd");
return 0;
}

View File

@@ -21,6 +21,7 @@
#include "lib/zt_common.h"
#include "fdasd.h"
#include "fdasd_cli.h"
/* global variables */
static struct hd_geometry geo;
@@ -138,58 +139,6 @@ static const struct util_prg prg = {
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("NON-INTERACTIVE MODE"),
{
.option = { "auto", no_argument, NULL, 'a' },
.desc = "Create a single partition spanning the entire disk",
},
{
.option = { "config", required_argument, NULL, 'c' },
.argument = "FILE",
.desc = "Create partitions(s) based on content of FILE",
},
{
.option = { "keep_volser", no_argument, NULL, 'k' },
.desc = "Do not change the current volume serial",
},
{
.option = { "label", required_argument, NULL, 'l' },
.argument = "VOLSER",
.desc = "Set the volume serial to VOLSER",
},
UTIL_OPT_SECTION("MISC"),
{
.option = { "check_host_count", no_argument, NULL, 'C' },
.desc = "Check if device is in use by other hosts",
},
{
.option = { "force", optional_argument, NULL, 'f' },
.argument = "TYPE,SIZE",
.desc = "Force fdasd to work on non DASD devices with assumed "
"TYPE (3390, 3380, or 9345) and blocksize SIZE",
},
{
.option = { "volser", no_argument, NULL, 'i' },
.desc = "Print volume serial",
},
{
.option = { "table", no_argument, NULL, 'p' },
.desc = "Print partition table",
},
{
.option = { "verbose", no_argument, NULL, 'r' },
.desc = "Provide more verbose output",
},
{
.option = { "silent", no_argument, NULL, 's' },
.desc = "Suppress messages",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
static int getpos(fdasd_anchor_t *anc, int dsn)
{
return anc->partno[dsn];

64
fdasd/fdasd_cli.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef FDASD_CLI_H
#define FDASD_CLI_H
#include "lib/util_opt.h"
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("NON-INTERACTIVE MODE"),
{
.option = { "auto", no_argument, NULL, 'a' },
.desc = "Create a single partition spanning the entire disk",
},
{
.option = { "config", required_argument, NULL, 'c' },
.argument = "FILE",
.desc = "Create partitions(s) based on content of FILE",
},
{
.option = { "keep_volser", no_argument, NULL, 'k' },
.desc = "Do not change the current volume serial",
},
{
.option = { "label", required_argument, NULL, 'l' },
.argument = "VOLSER",
.desc = "Set the volume serial to VOLSER",
},
UTIL_OPT_SECTION("MISC"),
{
.option = { "check_host_count", no_argument, NULL, 'C' },
.desc = "Check if device is in use by other hosts",
},
{
.option = { "force", optional_argument, NULL, 'f' },
.argument = "TYPE,SIZE",
.desc = "Force fdasd to work on non DASD devices with assumed "
"TYPE (3390, 3380, or 9345) and blocksize SIZE",
},
{
.option = { "volser", no_argument, NULL, 'i' },
.desc = "Print volume serial",
},
{
.option = { "table", no_argument, NULL, 'p' },
.desc = "Print partition table",
},
{
.option = { "verbose", no_argument, NULL, 'r' },
.desc = "Provide more verbose output",
},
{
.option = { "silent", no_argument, NULL, 's' },
.desc = "Suppress messages",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#endif

View File

@@ -7,6 +7,11 @@
include ../common.mak
zsh-completions = _hsavmcore
bash-completions = hsavmcore.bash
include ../common_autocomp.mak
ALL_CPPFLAGS += -D_FILE_OFFSET_BITS=64
ifeq (${HAVE_FUSE},0)
@@ -41,7 +46,7 @@ endif
ALL_CFLAGS += $(FUSE_CFLAGS) $(SYSTEMD_CFLAGS)
LDLIBS += $(FUSE_LDLIBS) $(SYSTEMD_LDLIBS) -lpthread
sources := $(wildcard *.c)
sources := $(filter-out %_host.c, $(wildcard *.c))
objects := $(patsubst %.c,%.o,$(sources))
libs = $(rootdir)/libutil/libutil.a

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "hsavmcore_cli.h"
int main(void)
{
generate_autocomp(opt_vec, "hsavmcore");
return 0;
}

View File

@@ -16,6 +16,7 @@
#include "lib/util_log.h"
#include "cmdline_options.h"
#include "hsavmcore_cli.h"
static const struct util_prg prg = {
.desc = "hsavmcore is designed to make the dump process with kdump more "
@@ -32,91 +33,6 @@ static const struct util_prg prg = {
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("CONFIGURATION"),
{
.option = { "config", required_argument, NULL, 'c' },
.argument = "CONFIGFILE",
.desc = "Path to the configuration file.\n"
"Default: no configuration file is used",
},
{
.option = { "vmcore", required_argument, NULL, 'C' },
.argument = "VMCOREFILE",
.desc = "Path to the vmcore file.\n"
"Default: " PROC_VMCORE,
},
{
.option = { "hsa", required_argument, NULL, 'H' },
.argument = "ZCOREHSAFILE",
.desc = "Path to the zcore HSA file.\n"
"Default: " ZCORE_HSA,
},
{
.option = { "workdir", required_argument, NULL, 'W' },
.argument = "WORKDIR",
.desc = "Path to the work directory where temporary files can be "
"stored.\nDefault: " WORKDIR,
},
{
.option = { "bmvmcore", required_argument, NULL, 'B' },
.argument = "VMCOREFILE",
.desc = "Path to the target of the bind mount for the vmcore "
"replacement.\nDefault: " PROC_VMCORE,
},
{
.option = { "swap", required_argument, NULL, 'S' },
.argument = "PATH",
.desc = "Path to a swap device or file. The specified swap "
"device or file must exist and have the proper swap "
"format.\nDefault: no swap device or file is activated",
},
{
.option = { "hsasize", required_argument, NULL, 'T' },
.argument = "HSASIZE",
.desc = "HSA size in bytes.\n"
"Default: -1 (read from the zcore HSA file)",
},
{
.option = { "dbgfsmnt", no_argument, NULL, 'D' },
.desc = "Mount the debug file system.\n"
"Default: the debug file system is not mounted",
},
{
.option = { "hsamem", no_argument, NULL, 'F' },
.desc = "Cache the HSA memory in regular memory.\n"
"Default: the HSA memory is cached as a file within "
"WORKDIR",
},
{
.option = { "norelhsa", no_argument, NULL, 'R' },
.desc = "Do NOT release the HSA memory after caching.\n"
"Default: the HSA memory is released",
},
{
.option = { "nobindmnt", no_argument, NULL, 'N' },
.desc = "Do NOT replace the system's vmcore.\n"
"Default: the system's vmcore is replaced",
},
UTIL_OPT_SECTION("LOGGING"),
{
.option = { "verbose", no_argument, NULL, 'V' },
.desc = "Print verbose messages to stdout. Repeat this option "
"for increased verbosity from just error messages to "
"also include warning, information, debug, and trace "
"messages. This option is intended for debugging",
},
{
.option = { "fusedbg", no_argument, NULL, 'G' },
.desc = "Enable FUSE debugging.\n"
"Default: FUSE debugging is disabled",
},
UTIL_OPT_SECTION("GENERAL OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
void parse_cmdline_options(int argc, char *argv[], struct config *config)
{
int opt, ret;

99
hsavmcore/hsavmcore_cli.h Normal file
View File

@@ -0,0 +1,99 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef HSAVMCORE_CLI_H
#define HSAVMCORE_CLI_H
#include "lib/util_opt.h"
#include "common.h"
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("CONFIGURATION"),
{
.option = { "config", required_argument, NULL, 'c' },
.argument = "CONFIGFILE",
.desc = "Path to the configuration file.\n"
"Default: no configuration file is used",
},
{
.option = { "vmcore", required_argument, NULL, 'C' },
.argument = "VMCOREFILE",
.desc = "Path to the vmcore file.\n"
"Default: " PROC_VMCORE,
},
{
.option = { "hsa", required_argument, NULL, 'H' },
.argument = "ZCOREHSAFILE",
.desc = "Path to the zcore HSA file.\n"
"Default: " ZCORE_HSA,
},
{
.option = { "workdir", required_argument, NULL, 'W' },
.argument = "WORKDIR",
.desc = "Path to the work directory where temporary files can be "
"stored.\nDefault: " WORKDIR,
},
{
.option = { "bmvmcore", required_argument, NULL, 'B' },
.argument = "VMCOREFILE",
.desc = "Path to the target of the bind mount for the vmcore "
"replacement.\nDefault: " PROC_VMCORE,
},
{
.option = { "swap", required_argument, NULL, 'S' },
.argument = "PATH",
.desc = "Path to a swap device or file. The specified swap "
"device or file must exist and have the proper swap "
"format.\nDefault: no swap device or file is activated",
},
{
.option = { "hsasize", required_argument, NULL, 'T' },
.argument = "HSASIZE",
.desc = "HSA size in bytes.\n"
"Default: -1 (read from the zcore HSA file)",
},
{
.option = { "dbgfsmnt", no_argument, NULL, 'D' },
.desc = "Mount the debug file system.\n"
"Default: the debug file system is not mounted",
},
{
.option = { "hsamem", no_argument, NULL, 'F' },
.desc = "Cache the HSA memory in regular memory.\n"
"Default: the HSA memory is cached as a file within "
"WORKDIR",
},
{
.option = { "norelhsa", no_argument, NULL, 'R' },
.desc = "Do NOT release the HSA memory after caching.\n"
"Default: the HSA memory is released",
},
{
.option = { "nobindmnt", no_argument, NULL, 'N' },
.desc = "Do NOT replace the system's vmcore.\n"
"Default: the system's vmcore is replaced",
},
UTIL_OPT_SECTION("LOGGING"),
{
.option = { "verbose", no_argument, NULL, 'V' },
.desc = "Print verbose messages to stdout. Repeat this option "
"for increased verbosity from just error messages to "
"also include warning, information, debug, and trace "
"messages. This option is intended for debugging",
},
{
.option = { "fusedbg", no_argument, NULL, 'G' },
.desc = "Enable FUSE debugging.\n"
"Default: FUSE debugging is disabled",
},
UTIL_OPT_SECTION("GENERAL OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#endif

View File

@@ -96,6 +96,17 @@ with an ASCII Record Separator character (0x1e) and suffixed with an ASCII Line
Feed character (0x0a) in accordance with RFC7464.
.BR
See section "OUTPUT FORMAT" for more details.
.BR
.PP
.IP \(bu 3
.B jsonl:
Line-delimited JSON data structures
Data for each iteration is formatted as a separate JSON data structure
separated by ASCII Line Feed character (0x0a, LF).
.BR
See section "OUTPUT FORMAT" for more details.
.BR
.PP
@@ -458,6 +469,14 @@ Subsequent objects each represent performance data for one iteration
.br
.PP
.SS jsonl
The jsonl output format is a data streaming variation of the JSON output format
described above with the same properties as the json\-seq output with the
difference that JSON data is separated only by an ASCII Line Feed character
(0x0a, LF).
.SH EXAMPLES
To start hyptop with the "sys_list" window in interactive mode, enter:
.br

View File

@@ -233,7 +233,7 @@ static void l_fmt_init(void)
flags |= FMT_QUOTEALL;
if (g.o.format == FMT_CSV || g.o.format_all)
flags |= FMT_KEEPINVAL;
if (g.o.format == FMT_JSON || g.o.format == FMT_JSONSEQ)
if (util_fmt_is_json(g.o.format))
flags |= FMT_HANDLEINT;
util_fmt_init(stdout, g.o.format, flags, 1);
}

View File

@@ -54,14 +54,6 @@ static char HELP_TEXT[] =
#define OPT_FORMAT 256 /* --format */
#define OPT_FORMAT_ALL 261 /* --all*/
/*
* Options with underscore to keep compatibility
*/
#define OPT_BATCH_MODE 257 /* --batch_mode */
#define OPT_SORT_FIELD 258 /* --sort | --sort_field */
#define OPT_CPU_TYPES 259 /* --cpu_types */
#define OPT_SMT_FACTOR 260 /* --smt_factor */
/*
* Initialize default settings
*/
@@ -224,7 +216,7 @@ static void l_fields_set(char *str)
}
/*
* Set the "--sort_field" option
* Set the "--sort" option
*/
static void l_sort_field_set(char *str)
{
@@ -362,19 +354,18 @@ void opts_parse(int argc, char *argv[])
{ "version", no_argument, NULL, 'v'},
{ "help", no_argument, NULL, 'h'},
{ "batch-mode", no_argument, NULL, 'b'},
{ "batch_mode", no_argument, NULL, OPT_BATCH_MODE},
{ "batch_mode", no_argument, NULL, 'b'},
{ "all", no_argument, NULL, OPT_FORMAT_ALL },
{ "delay", required_argument, NULL, 'd'},
{ "smt-factor", required_argument, NULL, 'm'},
{ "smt_factor", required_argument, NULL, OPT_SMT_FACTOR},
{ "smt_factor", required_argument, NULL, 'm'},
{ "window", required_argument, NULL, 'w'},
{ "sys", required_argument, NULL, 's'},
{ "iterations", required_argument, NULL, 'n'},
{ "fields", required_argument, NULL, 'f'},
{ "sort-field", required_argument, NULL, 'S'},
{ "sort_field", required_argument, NULL, OPT_SORT_FIELD},
{ "sort", required_argument, NULL, 'S'},
{ "cpu-types", required_argument, NULL, 't'},
{ "cpu_types", required_argument, NULL, OPT_CPU_TYPES},
{ "cpu_types", required_argument, NULL, 't'},
{ "format", required_argument, NULL, OPT_FORMAT },
{ NULL, 0, NULL, 0 }
};
@@ -393,14 +384,12 @@ void opts_parse(int argc, char *argv[])
case 'h':
l_usage();
hyptop_exit(0);
case OPT_BATCH_MODE:
case 'b':
l_batch_mode_set();
break;
case 'd':
l_delay_set(optarg);
break;
case OPT_SMT_FACTOR:
case 'm':
l_factor_set(optarg);
break;
@@ -413,14 +402,12 @@ void opts_parse(int argc, char *argv[])
case 'n':
l_iterations_set(optarg);
break;
case OPT_CPU_TYPES:
case 't':
l_cpu_types_set(optarg);
break;
case 'f':
l_fields_set(optarg);
break;
case OPT_SORT_FIELD:
case 'S':
l_sort_field_set(optarg);
break;

View File

@@ -1037,7 +1037,7 @@ void table_fmt_start(void)
{
if (!g.o.format_specified)
return;
if (g.o.format != FMT_JSONSEQ)
if (!util_fmt_is_json_stream(g.o.format))
util_fmt_obj_start(FMT_LIST, "hyptop");
}
@@ -1045,7 +1045,7 @@ void table_fmt_end(void)
{
if (!g.o.format_specified)
return;
if (g.o.format != FMT_JSONSEQ)
if (!util_fmt_is_json_stream(g.o.format))
util_fmt_obj_end(); /* hyptop[] */
}

View File

@@ -1,15 +1,7 @@
/* SPDX-License-Identifier: MIT */
/*
* autocomp - command line autocompletion
*
* Generating autocompletion scripts for bash and zsh
* based on util_opt struct
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef LIB_UTIL_AUTOCOMP_H

View File

@@ -45,12 +45,13 @@
#define FMT_DEFAULT 0
/* Names of supported output format types. */
#define FMT_TYPE_NAMES "json json-seq pairs csv"
#define FMT_TYPE_NAMES "json json-seq jsonl pairs csv"
/**
* enum util_fmt_t - Output format types.
* @FMT_JSON: JavaScript Object Notation output data structure
* @FMT_JSONSEQ: Sequence of JSON data structures according to RFC7464
* @FMT_JSONL: Line-delimited JSON
* @FMT_PAIRS: Textual key=value pairs
* @FMT_CSV: Comma-separated-values output
*
@@ -59,6 +60,7 @@
enum util_fmt_t {
FMT_JSON,
FMT_JSONSEQ,
FMT_JSONL,
FMT_PAIRS,
FMT_CSV,
};
@@ -232,4 +234,23 @@ void util_fmt_obj_end(void);
*/
void util_fmt_pair(unsigned int mflags, const char *key, const char *fmt, ...);
/**
* util_fmt_is_json() - Determine whether format is JSON.
* @type: Format type identifier.
*
* Return: %true if type is JSON, %false otherwise.
*/
bool util_fmt_is_json(enum util_fmt_t type);
/**
* util_fmt_is_json_stream() - Determine whether format is JSON stream.
* @type: Format type identifier.
*
* Determine whether a given format @type represents a JSON streaming format
* such as json-seq (@FMT_JSONSEQ) or jsonl (@FMT_JSONL).
*
* Return: %true if type is either @FMT_JSONSEQ or @FMT_JSONL, %false otherwise.
*/
bool util_fmt_is_json_stream(enum util_fmt_t type);
#endif /* LIB_UTIL_FMT_H */

View File

@@ -2172,7 +2172,7 @@ int write_public_key(const char *pem_filename, EVP_PKEY *pkey)
*/
static bool is_duplicate_name_entry(X509_NAME *name, X509_NAME_ENTRY *entry)
{
X509_NAME_ENTRY *ne;
const X509_NAME_ENTRY *ne;
int count, i;
count = X509_NAME_entry_count(name);

View File

@@ -378,8 +378,14 @@ int kmip_connection_tls_init(struct kmip_connection *conn, bool debug)
if (conn->config.tls_verify_host) {
SSL_set_hostflags(conn->plain_tls.ssl,
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
#if OPENSSL_VERSION_PREREQ(4, 0)
if (SSL_set1_ipaddr(conn->plain_tls.ssl, hostname) != 1 &&
SSL_set1_dnsname(conn->plain_tls.ssl, hostname) != 1) {
kmip_debug(debug, "SSL_set1_ipaddr/dnsname failed");
#else
if (SSL_set1_host(conn->plain_tls.ssl, hostname) != 1) {
kmip_debug(debug, "SSL_set1_host failed");
#endif
if (debug)
ERR_print_errors_fp(stderr);
rc = -EIO;

View File

@@ -395,7 +395,7 @@ const struct sk_digest_info *SK_UTIL_get_digest_info(int digest_nid)
static bool SK_UTILS_is_duplicate_name_entry(const X509_NAME *name,
const X509_NAME_ENTRY *entry)
{
X509_NAME_ENTRY *ne;
const X509_NAME_ENTRY *ne;
int count, i;
count = X509_NAME_entry_count(name);

View File

@@ -1,15 +1,7 @@
// SPDX-License-Identifier: MIT
/*
* autocomp - command line autocompletion
*
* Generating autocompletion scripts for bash and zsh
* based on util_opt struct
*
* Copyright IBM Corp. 2025
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include <errno.h>
@@ -22,18 +14,19 @@
#include "lib/util_autocomp.h"
#include "lib/util_opt.h"
static const char *bash_script_part1 = "() {\n\n\
\tlocal current_word previous_word options_array\n\n\
static const char *bash_script_part1 = "() {\n\
\tlocal current_word options_array\n\
\tCOMPREPLY=()\n\n\
\tcurrent_word=\"${COMP_WORDS[COMP_CWORD]}\"\n\n\
\tprevious_word=\"${COMP_WORDS[COMP_CWORD-1]}\"\n\n\
\tcurrent_word=\"${COMP_WORDS[COMP_CWORD]}\"\n\
\toptions_array=\"";
static const char *bash_script_part2 = "\tif [[ ${current_word} == -* || ${COMP_CWORD} -eq 1 ]] ; then\n\n\
\t\tCOMPREPLY=( $(compgen -W \"${options_array}\" -- ${current_word} ) )\n\n\
\t\treturn 0\n\n\
\tfi\n\n\
}\n\n\
static const char *bash_script_part2 = "\tif [[ ${current_word} == -* ]] ; then\n\
\t\tmapfile -t \"COMPREPLY\" < <(compgen -W \"${options_array}\" -- \"$current_word\")\n\
\telse\n\
\t\tcompopt -o bashdefault -o default\n\
\tfi\n\
\treturn 0\n\
}\n\
complete -F ";
static char *format_name(const char *fmt, char *tool_name)
@@ -63,7 +56,7 @@ static int init_scriptfile(char *file_path)
{
int fd;
fd = open(file_path, O_CREAT | O_WRONLY, 0644);
fd = open(file_path, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0)
return -EIO;
return fd;
@@ -86,7 +79,7 @@ static int start_bash_scriptfile(int fd, char *func_name)
static int start_zsh_scriptfile(int fd, char *func_name, char *tool_name)
{
const char *part3 = " {\n\n\t_arguments -C \\\n";
const char *part3 = " {\n\n\t_arguments -C -A \"*\" \\\n";
const char *part2 = "\n\nfunction ";
const char *part1 = "#compdef ";
int len, ret = 0;
@@ -127,6 +120,7 @@ static int write_bash_command_options(struct util_opt *opt_vec, int fd)
static int write_zsh_command_options(struct util_opt *opt_vec, int fd)
{
const char *end = "\t\t\"*:files:_files\"\n}\n";
const char *name, *desc;
char *str;
int len;
@@ -145,8 +139,14 @@ static int write_zsh_command_options(struct util_opt *opt_vec, int fd)
free(str);
}
}
if (write(fd, "\n}\n", 3) != 3)
len = asprintf(&str, "%s", end);
if (len == -1)
return -EIO;
if (write(fd, str, len) != len) {
free(str);
return -EIO;
}
free(str);
return 0;
}
@@ -169,35 +169,6 @@ static int finish_bash_scriptfile(char *tool_name, int fd, char *func_name)
* Adds tab completion in bash for a command.
* Works by generating an autocompletion
* script file at '/usr/share/bash-completion/completions'.
*
* The full script will be as follows, supposing the tool name is
* 'example' and it only has the options '--help' and
* '--version':
*
* _example() {
*
* local current_word previous_word options_array
*
* COMPREPLY=()
*
* current_word="${COMP_WORDS[COMP_CWORD]}"
*
* previous_word="${COMP_WORDS[COMP_CWORD-1]}"
*
* options_array="--version --help"
*
* if [[ ${current_word} == -* || ${COMP_CWORD} -eq 1 ]] ; then
*
* COMPREPLY=( $(compgen -W "${options_array}" -- ${current_word} ) )
*
* return 0
*
* fi
*
* }
*
* complete -F _example example
*
*/
static void generate_bash_autocomp(struct util_opt *opt_vec, char *tool_name)
{
@@ -244,22 +215,6 @@ end:
* Adds tab completion in zsh for a command.
* Works by generating an autocompletion
* script file at '/usr/share/zsh/site-functions'.
*
* The full script will be as follows, supposing the tool name is
* 'example' and it only has the options '--help', -h and
* '--version' (the descriptions, as well as the flags are
* taken from a util_opt struct):
*
* #compdef example_completion
*
* function _example_completion {
*
* _arguments -C \
* "-h[Show help information]" \
* "--help[Show help but long format]" \
* "--version[Show version]"
* }
*
*/
static void generate_zsh_autocomp(struct util_opt *opt_vec, char *tool_name)
{

View File

@@ -91,6 +91,7 @@ static const struct {
} formats[] = {
{ "json", FMT_JSON },
{ "json-seq", FMT_JSONSEQ },
{ "jsonl", FMT_JSONL },
{ "pairs", FMT_PAIRS },
{ "csv", FMT_CSV },
};
@@ -111,6 +112,29 @@ bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type)
return false;
}
bool util_fmt_is_json(enum util_fmt_t type)
{
switch (type) {
case FMT_JSON:
case FMT_JSONSEQ:
case FMT_JSONL:
return true;
default:
return false;
}
}
bool util_fmt_is_json_stream(enum util_fmt_t type)
{
switch (type) {
case FMT_JSONSEQ:
case FMT_JSONL:
return true;
default:
return false;
}
}
static void safe_write(const char *str)
{
size_t done, todo;
@@ -129,7 +153,7 @@ static void _indent(unsigned int off, bool safe)
{
unsigned int num, i;
if (f.type == FMT_JSONSEQ)
if (util_fmt_is_json_stream(f.type))
return;
num = f.ind_base + off;
if (f.type == FMT_JSON && f.lvl > 0)
@@ -408,8 +432,8 @@ static void emit_meta_object(void)
util_fmt_pair(quoted, "time", "%s", date);
_util_fmt_obj_end();
if (f.type == FMT_JSONSEQ) {
/* Tool meta-data is a separate object for JSONSEQ. */
if (util_fmt_is_json_stream(f.type)) {
/* Tool meta-data is a separate object for JSON streams. */
util_fmt_obj_end();
}
}
@@ -478,7 +502,7 @@ void util_fmt_obj_end(void)
{
_util_fmt_obj_end();
if (f.lvl == 1 && f.meta_done && f.type != FMT_JSONSEQ) {
if (f.lvl == 1 && f.meta_done && !util_fmt_is_json_stream(f.type)) {
/* Emit closure for top-level meta-container object. */
util_fmt_obj_end();
}
@@ -737,7 +761,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
f.do_warn = (flags & FMT_WARN);
f.handle_int = (flags & FMT_HANDLEINT);
f.api_level = api_level;
if (type == FMT_JSONSEQ)
if (util_fmt_is_json_stream(type))
f.nl = "";
else
f.nl = "\n";
@@ -750,6 +774,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
break;
case FMT_JSON:
case FMT_JSONSEQ:
case FMT_JSONL:
f.obj_start = &json_obj_start;
f.obj_end = &json_obj_end;
f.map = &json_map;

View File

@@ -193,6 +193,9 @@ int main(int UNUSED(argc), char *UNUSED(argv[]))
announce("JSON formatted as sequence");
simple_example(FMT_JSONSEQ, FMT_DEFAULT);
announce("JSON Lines format");
simple_example(FMT_JSONL, FMT_DEFAULT);
announce("Pairs output");
simple_example(FMT_PAIRS, FMT_KEEPINVAL);
@@ -232,6 +235,9 @@ int main(int UNUSED(argc), char *UNUSED(argv[]))
announce("JSON sequence output with meta-data");
meta_example(FMT_JSONSEQ);
announce("JSON Lines output with meta-data");
meta_example(FMT_JSONL);
announce("Pairs output with meta-data");
meta_example(FMT_PAIRS);

View File

@@ -1,5 +1,10 @@
include ../common.mak
zsh-completions = _lsstp
bash-completions = lsstp.bash
include ../common_autocomp.mak
libs = $(rootdir)/libutil/libutil.a
all: lsstp

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "lsstp_cli.h"
int main(void)
{
generate_autocomp(opt_vec, "lsstp");
return 0;
}

View File

@@ -22,6 +22,8 @@
#include "lib/util_prg.h"
#include "lib/util_path.h"
#include "lsstp_cli.h"
static const struct util_prg prg = {
.desc = "Display STP system information",
.args = "",
@@ -34,12 +36,6 @@ static const struct util_prg prg = {
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
struct stp_parms {
uint64_t ctn_id;
unsigned int online;

18
lsstp/lsstp_cli.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef LSSTP_CLI_H
#define LSSTP_CLI_H
#include "lib/util_opt.h"
static struct util_opt opt_vec[] = {
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#endif

View File

@@ -2,6 +2,11 @@ include ../common.mak
TESTS := tests/
zsh-completions = _opticsmon
bash-completions = opticsmon.bash
include ../common_autocomp.mak
libs =$(rootdir)/libzpci/libzpci.a $(rootdir)/libutil/libutil.a
ifneq (${HAVE_OPENSSL},0)

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#include "lib/util_autocomp.h"
#include "opticsmon_cli.h"
int main(void)
{
generate_autocomp(opt_vec, "opticsmon");
return 0;
}

View File

@@ -45,7 +45,7 @@ opticsmon - Monitor optical modules for directly attached PCI based NICs
Use
.B opticsmon
to monitor the health of the optical modules of directly attached PCI based
NICs. When executed without the \fB--daemon\fR option it will collect optical
NICs. When executed without the \fB--monitor\fR option it will collect optical
module data from all available PCI network interface physical functions and
print a summary in JSON format. Add the \fB--send-report\fR option to report
this data to the support element.
@@ -55,7 +55,7 @@ this data to the support element.
.
.SH OPTIONS
.SS Operation Options
.OD daemon "d"
.OD monitor "m"
Run continuously and report on link state changes and periodically
.PP
.

View File

@@ -27,10 +27,11 @@
#include <openssl/evp.h>
#include "optics_info.h"
#include "optics_sclp.h"
#include "ethtool.h"
#include "link_mon.h"
#include "optics_info.h"
#include "optics_sclp.h"
#include "opticsmon_cli.h"
#define API_LEVEL 1
@@ -61,44 +62,6 @@ static const struct util_prg prg = {
UTIL_PRG_COPYRIGHT_END }
};
#define OPT_DUMP 128
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPERATION OPTIONS"),
{
.option = { "monitor", no_argument, NULL, 'm' },
.desc = "Run continuously and report on link state changes "
"collecting optics health data when a change is detected",
},
{
.option = { "send-report", no_argument, NULL, 'r' },
.desc = "Report the optics health data to the Support Element",
},
{
.option = { "quiet", no_argument, NULL, 'q' },
.desc = "Be quiet and don't print optics health summary",
},
{
.option = { "module-info", no_argument, NULL, OPT_DUMP },
.desc = "Include a base64 encoded binary dump of the module's "
"SFF-8636/8472/8024 standard data for each netdev. "
"This matches \"ethtool --module-info <netdev> raw on\"",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("OPTIONS WITH ARGUMENTS"),
{
.option = { "interval", required_argument, NULL, 'i' },
.argument = "seconds",
.desc = "Interval in seconds at which to collect monitoring data "
"in the absence of link state changes. A value larger than "
"24 hours (86400 seconds) is clamped down to 24 hours.",
},
UTIL_OPT_SECTION("GENERAL OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
static void parse_cmdline(int argc, char *argv[], struct options *opts)
{
uint32_t seconds;

50
opticsmon/opticsmon_cli.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright IBM Corp.
*/
#ifndef OPTICSMON_CLI_H
#define OPTICSMON_CLI_H
#include "lib/util_opt.h"
#define OPT_DUMP 128
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPERATION OPTIONS"),
{
.option = { "monitor", no_argument, NULL, 'm' },
.desc = "Run continuously and report on link state changes "
"collecting optics health data when a change is detected",
},
{
.option = { "send-report", no_argument, NULL, 'r' },
.desc = "Report the optics health data to the Support Element",
},
{
.option = { "quiet", no_argument, NULL, 'q' },
.desc = "Be quiet and don't print optics health summary",
},
{
.option = { "module-info", no_argument, NULL, OPT_DUMP },
.desc = "Include a base64 encoded binary dump of the module's "
"SFF-8636/8472/8024 standard data for each netdev. "
"This matches 'ethtool --module-info <netdev> raw on'",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("OPTIONS WITH ARGUMENTS"),
{
.option = { "interval", required_argument, NULL, 'i' },
.argument = "seconds",
.desc = "Interval in seconds at which to collect monitoring data "
"in the absence of link state changes. A value larger than "
"24 hours (86400 seconds) is clamped down to 24 hours.",
},
UTIL_OPT_SECTION("GENERAL OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#endif

105
rust/Cargo.lock generated
View File

@@ -62,9 +62,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.95"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "autocfg"
@@ -111,6 +111,15 @@ dependencies = [
"wyz",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -212,6 +221,25 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "curl"
version = "0.4.49"
@@ -302,6 +330,16 @@ dependencies = [
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "enum_dispatch"
version = "0.3.13"
@@ -363,6 +401,16 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.16"
@@ -404,6 +452,12 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -641,6 +695,20 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "pvebc"
version = "0.12.0"
dependencies = [
"anyhow",
"clap",
"clap_complete",
"hex",
"s390_pv_core",
"sha2",
"utils",
"zerocopy",
]
[[package]]
name = "pvimg"
version = "0.12.0"
@@ -687,6 +755,7 @@ dependencies = [
"s390_pv",
"serde_yaml",
"utils",
"zerocopy",
]
[[package]]
@@ -891,6 +960,7 @@ dependencies = [
"regex",
"serde",
"serde_test",
"sha2",
"thiserror",
"zerocopy",
]
@@ -969,6 +1039,17 @@ dependencies = [
"unsafe-libyaml",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
@@ -1069,6 +1150,12 @@ dependencies = [
"winnow",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unarray"
version = "0.1.4"
@@ -1112,6 +1199,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wait-timeout"
version = "0.2.0"
@@ -1238,18 +1331,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.25"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.25"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -5,6 +5,7 @@ members = [
"pv_core",
"pvapconfig",
"pvattest",
"pvebc",
"pvimg",
"pvinfo",
"pvsecret",

View File

@@ -10,8 +10,10 @@ CARGO_TARGETS :=
PV_TARGETS :=
CARGO_TEST_TARGETS :=
SEL_EBC_MODDIR := 95sel-ebc
ifneq (${HAVE_CARGO},0)
CARGO_TARGETS :=
CARGO_TARGETS := pvebc
BUILD_TARGETS = $(CARGO_TARGETS)
INSTALL_TARGETS := install-rust-tools install-man install-shell-completions
@@ -29,6 +31,7 @@ ifneq (${HAVE_LIBCURL},0)
ifeq ($(HOST_ARCH),s390x)
PV_TARGETS += pvapconfig pvinfo
INSTALL_TARGETS += install-ebc-dracut-module
else
BUILD_TARGETS += skip-pvapconfig skip-pvinfo
endif #HOSTARCH
@@ -104,6 +107,23 @@ endif # CARGO
rust-test: $(CARGO_TEST_TARGETS)
install-ebc-dracut-module:
ifneq ($(HAVE_DRACUT),0)
$(INSTALL) -m 755 -d $(DESTDIR)$(DRACUTMODDIR)/
$(INSTALL) -m 755 -d $(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
$(INSTALL) -m 755 pvebc/$(SEL_EBC_MODDIR)/module-setup.sh \
pvebc/$(SEL_EBC_MODDIR)/override-crypttab.sh \
pvebc/$(SEL_EBC_MODDIR)/pvebc-wrapper.sh \
$(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
$(INSTALL) -m 644 pvebc/$(SEL_EBC_MODDIR)/boot.mount \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-override-crypttab.service \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-paes-enforce.service \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-pvebc.service \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc.crypttab \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc.target \
$(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
endif
install-rust-tools: $(BUILD_TARGETS)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
$(foreach target,$(CARGO_TARGETS),\

View File

@@ -104,7 +104,14 @@ pub mod request {
/// Reexports some useful OpenSSL symbols
pub mod openssl {
pub use openssl::{error::ErrorStack, hash::DigestBytes, nid::Nid, pkey, x509};
pub use openssl::{
error::ErrorStack,
hash::DigestBytes,
nid::Nid,
pkey,
sha::{Sha256, Sha512},
x509,
};
// rust-OpenSSL does not define these NIDs
#[allow(missing_docs)]
pub const NID_ED25519: Nid = Nid::from_raw(openssl_sys::NID_ED25519);
@@ -113,6 +120,8 @@ pub mod request {
}
pub use pv_core::request::*;
pub use pv_core::PolicyReference;
}
/// Functionalities for creating add-secret requests

View File

@@ -248,7 +248,7 @@ fn check_key_format(kind: UserDataType, key: &PKeyRef<Public>) -> Result<()> {
///
/// # Returns
///
/// Extracrted user-data if available
/// Extracted user-data if available
///
/// # Errors
///

View File

@@ -23,6 +23,7 @@ zerocopy = {version = "0.8", features = ["derive"]}
serde = { version = "1.0.217", features = ["derive"]}
byteorder = "1.5"
regex = "1.10"
sha2 = "0.10.9"
[dev-dependencies]
serde_test = "1.0.177"

View File

@@ -6,6 +6,7 @@ mod apdevice;
mod confidential;
mod error;
mod macros;
mod policy;
mod utils;
mod uvattest;
mod uvdevice;
@@ -13,6 +14,13 @@ mod uvsecret;
pub use error::{Error, FileAccessErrorType, FileIoErrorType, Result};
/// Early Boot Customization (EBC) utilities.
///
/// This module provides types and functions for working with Early Boot
/// Customization. The integrity and completeness of ASRs are ensured through
/// cryptographically protected table of contents files.
pub use policy::PolicyReference;
/// Functionalities for reading attestation requests
pub mod attest {
pub use crate::uvattest::{AttestationMagic, AttestationMeasAlg};

112
rust/pv_core/src/policy.rs Normal file
View File

@@ -0,0 +1,112 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp.
use crate::misc::encode_hex;
use crate::utils::open_file;
use crate::{Error, Result};
use std::{
fmt::{Display, Formatter, Result as Resfmt},
fs::File,
os::unix::ffi::OsStrExt,
path::{Path, PathBuf},
str::from_utf8,
};
use zerocopy::{FromBytes, Immutable, IntoBytes};
const HASH_LEN: usize = 32;
// UserDataType::Unsigned.max() returns 512
const USER_DATA_MAX_SIZE: usize = 512;
/// A reference to a policy file containing its SHA-256 hash and file path.
///
/// This structure is used in Early Boot Customization (EBC) to store
/// a reference to a policy file. It contains the SHA-256 hash of the policy
/// file content and the file path as a fixed-size byte array.
///
/// The total size is constrained by `USER_DATA_MAX_SIZE` (512 bytes), with
/// 32 bytes allocated for the hash and the remaining bytes for the file path.
#[derive(Debug, FromBytes, IntoBytes, Immutable, Copy, Clone)]
#[repr(C)]
pub struct PolicyReference {
/// SHA-256 hash of the policy file content (32 bytes)
pub hash: [u8; HASH_LEN],
/// File path stored as a null-terminated byte array
pub name: [u8; USER_DATA_MAX_SIZE - HASH_LEN],
}
impl PolicyReference {
/// Creates a new `PolicyReference` from a file path.
///
/// Opens the file, reads its content, and computes the SHA-256 hash.
///
/// # Parameters
///
/// * `src` - The path to the policy file
/// * `sha256` - A function that computes the SHA-256 hash of the content
///
/// # Returns
///
/// Returns a `PolicyReference` containing the SHA-256 hash and the file path,
/// or an error if the file cannot be opened or the hash computation fails.
///
/// # Note
///
/// The file path is truncated if it exceeds the available space in the `name` field.
pub fn new<P, H>(src: P, sha256: H) -> Result<Self>
where
P: AsRef<Path>,
H: Fn(File) -> Result<Vec<u8>>,
{
let mut ret = Self {
hash: [0; HASH_LEN],
name: [0; USER_DATA_MAX_SIZE - HASH_LEN],
};
let file = open_file(src.as_ref())?;
ret.hash.copy_from_slice(sha256(file)?.as_bytes());
let strbytes = src.as_ref().as_os_str().as_bytes();
let nbytes = strbytes.len().min(ret.name.len());
ret.name[..nbytes].copy_from_slice(&strbytes[..nbytes]);
Ok(ret)
}
/// Converts the stored file path back to a `PathBuf`.
///
/// # Returns
///
/// Returns the file path as a `PathBuf`, or an error if the stored name
/// is not valid UTF-8.
///
/// # Errors
///
/// * `Error::ParseError` - If the name contains invalid UTF-8
pub fn to_path(&self) -> Result<PathBuf> {
// Extract bytes until the first null byte (null-terminated string)
let name_bytes: Vec<u8> = self
.name
.iter()
.copied()
.take_while(|&byte| byte != 0)
.collect();
let rust_string = String::from_utf8(name_bytes).map_err(|e| Error::ParseError {
subject: "PolicyReference name".to_string(),
content: format!("Invalid UTF-8 in name: {}", e),
})?;
Ok(Path::new(&rust_string).to_owned())
}
}
impl Display for PolicyReference {
fn fmt(&self, f: &mut Formatter) -> Resfmt {
write!(
f,
"{} {}",
encode_hex(self.hash),
from_utf8(&self.name).expect("unable to convert name")
)
}
}

View File

@@ -35,12 +35,12 @@ pub enum Command {
/// shred it after verification. Every 'create' will generate a new, random protection key.
Create(Box<CreateAttOpt>),
/// Send the attestation request to the Ultravisor.
/// Send the attestation request to the Ultravisor (s390x only.)
///
/// Run a measurement of this system through /dev/uv. This device must be accessible and the
/// attestation Ultravisor facility must be present. The input must be an attestation request
/// created with pvattest create. Output will contain the original request and the response
/// from the Ultravisor.
/// from the Ultravisor. Only available on s390x.
Perform(PerformAttOpt),
/// Verify an attestation response.
@@ -110,27 +110,22 @@ pub enum AttAddFlags {
FirmwareState,
}
// all members s390x only
#[derive(Args, Debug)]
pub struct PerformAttOpt {
/// Specify the request to be sent.
#[cfg(target_arch = "s390x")]
#[arg(hide=true, short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub input: Option<String>,
/// Specify the request to be sent.
#[cfg(target_arch = "s390x")]
#[arg(value_name = "IN", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
pub input_pos: Option<String>,
/// Write the result to FILE.
#[cfg(target_arch = "s390x")]
#[arg(hide=true, short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub output: Option<String>,
/// Write the result to FILE.
#[arg(value_name = "OUT", value_hint = ValueHint::FilePath, required_unless_present("output"), conflicts_with("output"))]
#[cfg(target_arch = "s390x")]
pub output_pos: Option<String>,
/// Provide up to 256 bytes of user input

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2024
#![allow(unused)]
use anyhow::{anyhow, bail, Error, Result};
use pv::{assert_size, request::MagicValue, uv::AttestationCmd, uv::ConfigUid};
use std::{

View File

@@ -0,0 +1,28 @@
[Unit]
Description=Mount /boot early in initramfs
# Initramfs requirement
DefaultDependencies=no
# Make absolutely sure this only runs in initramfs (and not post-pivot if the
# unit ever appears there)
ConditionPathExists=/etc/initrd-release
ConditionKernelCommandLine=root
# we use /dev/disk/by-label because it identifies the boot partition system
# independently IF set up correctly
Requires=dev-disk-by\x2dlabel-boot.device
# Ordering dependencies
After=dev-disk-by\x2dlabel-boot.device
Before=sel-ebc-pvebc.service
[Mount]
# system independent identification of boot partition requires that the label
# boot is set for the boot partition
What=/dev/disk/by-label/boot
Where=/boot
Type=auto
Options=defaults
[Install]
WantedBy=sel-ebc-pvebc.service

View File

@@ -0,0 +1,76 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# Copyright IBM Corp.
# Called by dracut
check() {
# always include
return 0
}
# Called by dracut
depends() {
# We need systemd in the initramfs
echo systemd
echo systemd-udevd
echo crypt
echo dm
return 0
}
# Called by dracut
installkernel() {
# kernel modules needed for opening an encrypted rfs
instmods -c uvdevice
instmods -c paes_s390
instmods -c pkey_uv
instmods -c pkey_pckmo
instmods -c pkey
}
# Called by dracut
install() {
# shellcheck disable=SC2154
# moddir, systemdsystemunitdir, and initdir are provided by dracut
# Copy the units into the initramfs' systemd unit dir
inst_simple "$moddir/sel-ebc.target" \
"$systemdsystemunitdir/sel-ebc.target"
inst_simple "$moddir/sel-ebc-pvebc.service" \
"$systemdsystemunitdir/sel-ebc-pvebc.service"
inst_simple "$moddir/sel-ebc-paes-enforce.service" \
"$systemdsystemunitdir/sel-ebc-paes-enforce.service"
inst_simple "$moddir/sel-ebc-override-crypttab.service" \
"$systemdsystemunitdir/sel-ebc-override-crypttab.service"
inst_simple "$moddir/boot.mount" \
"$systemdsystemunitdir/boot.mount"
# already exisitng unit we depend on for kernel modules
inst_simple /usr/lib/systemd/system/systemd-modules-load.service \
"$systemdsystemunitdir/systemd-modules-load.service"
# wrapper for sel-ebc.service
inst_simple "$moddir/pvebc-wrapper.sh" \
"/etc/sel-ebc/pvebc-wrapper.sh"
# override crypttab
inst_simple "$moddir/override-crypttab.sh" \
"/etc/sel-ebc/override-crypttab.sh"
# copy main application
inst_binary "/usr/bin/pvebc"
inst_binary "/usr/bin/pvsecret"
inst_simple "$moddir/sel-ebc.crypttab" "/etc/sel-ebc/crypttab"
# Create the enablement symlinks in the image using host systemctl:
# shellcheck disable=SC2154
inst_dir "$initdir/etc/systemd/system"
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc.target
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-pvebc.service
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-override-crypttab.service
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-paes-enforce.service
systemctl --root "$initdir" --no-reload --quiet enable systemd-modules-load.service
systemctl --root "$initdir" --no-reload --quiet enable boot.mount
}

View File

@@ -0,0 +1,20 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# Copyright IBM Corp.
IBM_RSRC_DIR="/etc/sel-ebc"
if [[ ! -f "${IBM_RSRC_DIR}/crypttab" ]]; then
echo "Error: source file $IBM_RSRC_DIR/crypttab does not exist"
exit 1
fi
# Unconditionally override /etc/crypttab to ensure correct EBC configuration
cp "${IBM_RSRC_DIR}/crypttab" "/etc/crypttab"
systemctl daemon-reload
systemctl restart systemd-cryptsetup@cryptroot_mapper.service
exit 0

View File

@@ -0,0 +1,63 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# Copyright IBM Corp.
SYSFS=/sys/firmware/uv/prot_virt_guest
SICS=/boot/sics
EBC_TMPFS=/run/sel-ebc
TOC=toc.asr
ASR_NAME=luks-rfs-passphrase
# Early exit for non SEL guests
if [[ ! -e $SYSFS ]]; then
echo "Not running in a SEL guest."
exit 1
fi
if [[ $(cat $SYSFS) -ne 1 ]]; then
echo "Not running in a SEL guest."
exit 1
fi
echo "Running in SEL guest."
# Copy EBC resources from /boot/sics to tmpfs for security
# This protects against host injection attacks by moving resources to UV-protected RAM
echo "Copying EBC resources from $SICS to $EBC_TMPFS"
if ! mkdir -p "$EBC_TMPFS"; then
echo "Failed to create $EBC_TMPFS"
exit 1
fi
# Copy only .asr and .pol files
for file in "$SICS"/*.asr "$SICS"/*.pol; do
if [[ -f "$file" && ! -L "$file" ]]; then
cp "$file" "$EBC_TMPFS/" || {
echo "Failed to copy $file to $EBC_TMPFS"
exit 1
}
fi
done
# Verify toc.asr was copied
if [[ ! -f "$EBC_TMPFS/$TOC" ]]; then
echo "Error: $EBC_TMPFS/$TOC does not exist after copy"
exit 1
fi
# execute the actual tool with the copied toc.asr
pvebc --toc "$EBC_TMPFS/$TOC"
rc=$?
if [[ $rc -ne 0 ]]; then
exit $rc
fi
# Retrieve and check for dummy LUKS passphrase
pvsecret retrieve --inform name -o "$EBC_TMPFS/$ASR_NAME" --outform bin "$ASR_NAME"
if [[ ! -f "$EBC_TMPFS/$ASR_NAME" ]]; then
echo "$EBC_TMPFS/$ASR_NAME does not exist"
fi
chmod 400 "$EBC_TMPFS/$ASR_NAME"
exit 0

View File

@@ -0,0 +1,37 @@
[Unit]
Description=Override crypttab
# boot partition contains SICS
# Loading of kernel modules is required which are needed for protected keys
Requires=systemd-modules-load.service
Requires=boot.mount
# Ensure this runs before the handoff to the real root, if that's required:
After=boot.mount
After=systemd-modules-load.service
Before=cryptsetup-pre.target
Before=cryptsetup.target
Before=systemd-cryptsetup@.service
Before=initrd-root-device.target
After=sel-ebc-pvebc.service
# Initramfs requirement
DefaultDependencies=no
# Make absolutely sure this only runs in initramfs
ConditionPathExists=/etc/initrd-release
ConditionKernelCommandLine=rd.sel-ebc
ConditionKernelCommandLine=root
[Service]
Type=oneshot
ExecStart=/bin/bash /etc/sel-ebc/override-crypttab.sh
RemainAfterExit=yes
# If pvebc fails immediately abort boot
FailureAction=poweroff-immediate
# boot partition is unencrypted and contains SICS so we can get logs out this way
# logs do not leek any sensitive information
StandardOutput=file:/boot/sics/log
StandardError=file:/boot/sics/log
[Install]
RequiredBy=sel-ebc.target

View File

@@ -0,0 +1,27 @@
[Unit]
Description=Enforce PAES encrypted root fs for SEL guests
# Ensure this runs before the handoff to the real root, if that's required:
After=cryptsetup.target
After=initrd-root-device.target
Before=sysroot.mount
# Initramfs requirement
DefaultDependencies=no
# Make absolutely sure this only runs in initramfs
ConditionPathExists=/etc/initrd-release
ConditionKernelCommandLine=rd.sel-ebc
ConditionKernelCommandLine=root
[Service]
Type=oneshot
ExecStart=bash -c 'dmsetup table /dev/disk/by-label/root | grep "paes-xts-plain64"'
FailureAction=poweroff-immediate
RemainAfterExit=yes
# logs do not leek any sensitive information
StandardOutput=file:/boot/sics/log
StandardError=file:/boot/sics/log
[Install]
RequiredBy=sel-ebc.target

View File

@@ -0,0 +1,36 @@
[Unit]
Description=Run pvebc during early boot to process SICS
# boot partition contains SICS
# Loading of kernel modules is required which are needed for protected keys
Requires=systemd-modules-load.service
Wants=boot.mount
# Ensure this runs before the handoff to the real root, if that's required:
Before=initrd-root-device.target
Before=cryptsetup-pre.target
Before=cryptsetup.target
After=boot.mount
After=systemd-modules-load.service
# Initramfs requirement
DefaultDependencies=no
# Make absolutely sure this only runs in initramfs
ConditionPathExists=/etc/initrd-release
AssertPathIsDirectory=/boot/sics
ConditionKernelCommandLine=rd.sel-ebc
[Service]
Type=oneshot
# execute pvebc
ExecStart=/bin/bash /etc/sel-ebc/pvebc-wrapper.sh
RemainAfterExit=yes
# If pvebc fails immediately abort boot
FailureAction=poweroff-immediate
# boot partition is unencrypted and contains SICS so we can get logs out this way
# logs do not leek any sensitive information
StandardOutput=file:/boot/sics/log
StandardError=file:/boot/sics/log
[Install]
RequiredBy=sel-ebc.target

View File

@@ -0,0 +1 @@
cryptroot_mapper /dev/disk/by-label/cryptroot /run/sel-ebc/luks-rfs-passphrase

View File

@@ -0,0 +1,27 @@
[Unit]
Description=Target unit for IBM Secure Execution for Linux early boot customization
# enable for use in initramfs
DefaultDependencies=no
# if not met start the target without starting its dependencies
ConditionPathExists=/etc/initrd-release
ConditionKernelCommandLine=rd.sel-ebc
# if not met the target is considered failed
# AssertVirtualization=kvm
# if target fails abort immediately
FailureAction=poweroff-immediate
Requires=sel-ebc-pvebc.service
Requires=sel-ebc-override-crypttab.service
Requires=sel-ebc-paes-enforce.service
# ordering dependencies
After=systemd-modules-load.service
Before=initrd-root-device.target
[Install]
# most basic hook to start target by default
WantedBy=initrd.target

22
rust/pvebc/Cargo.toml Normal file
View File

@@ -0,0 +1,22 @@
[package]
name = "pvebc"
version = "0.12.0"
edition.workspace = true
license.workspace = true
rust-version.workspace = true
[dependencies]
sha2 = "0.10"
hex = "0.4"
clap = { version = "4.5", features = ["derive"] }
pv_core = { path = "../pv_core" , package = "s390_pv_core" }
utils = { path = "../utils" }
anyhow = { version = "1.0.95", features = ["std"] }
zerocopy = { version = "0.8.27", features = ["derive"] }
[build-dependencies]
clap = { version ="4.5", features = ["derive"]}
clap_complete = "4.5"
[lints]
workspace = true

165
rust/pvebc/man/pvebc.1 Normal file
View File

@@ -0,0 +1,165 @@
.\" Copyright IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVEBC" "1" "2026-03-24" "s390-tools" "EBC Management Manual"
.nh
.ad l
.SH NAME
pvebc \- Protected Virtualization Early Boot Customization Tool
.SH SYNOPSIS
.nf
.fam C
pvebc [OPTIONS] \-\-toc <FILE>
.fam C
.fi
.SH DESCRIPTION
Use the \fBpvebc\fR tool to process add-secret request files (\fBtoc.asr\fR)
that define the root of early boot customization (EBC) resources for
IBM Secure Execution for Linux (SEL) guests. The tool validates the
integrity and completeness of add-secret request (ASR) files using
cryptographic verification to prevent tampering during transmission
over unsecured channels.
The tool operates on a structure consisting of three types of files:
.RS 4
\- \fBtoc.asr\fP: The root add\-secret request file that references the table of contents (TOC policy).
\- \fBtoc.pol\fP: The table of contents policy file that contains a list of AES\-GCM authentication tags (MAC tags)
\- \fBASR files\fP: Individual add-secret request files to be added to the guest
.RE
The integrity protection mechanism works as follows:
.RS 4
.IP "1." 3
Each add-secret request file includes an AES\-GCM authentication tag (last 16 bytes), which provides integrity
protection for the file.
.IP "2." 3
The toc.pol file lists the expected message authentication code (MAC) tags of all add-secret request files.
.IP "3." 3
The toc.asr file contains a cryptographically protected reference to toc.pol, consisting
of the relative file path and a SHA\-512 hash of the policy file.
.IP "4." 3
The AES\-GCM authentication tag of toc.asr protects the integrity of this reference.
.RE
This structure prevents attackers from:
.RS 4
\- Removing add-secret request files from the set
\- Inserting unauthorized add-secret request files
\- Modifying existing add-secret request files
\- Altering the policy file
.RE
\fBpvebc\fR validates the entire chain of trust by:
.RS 4
\- Verifying that the SHA\-512 hash of toc.pol matches the reference stored in toc.asr
\- Checking that all MAC tags listed in toc.pol correspond to existing add-secret request files
\- Ensuring that all add-secret request files are present and unmodified
.RE
The tool can run in one of two modes:
.RS 4
\- \fBNormal mode\fP: Validates add\-secret requests and adds the defined secrets to the SEL guest (z/Architecture only)
\- \fBDry\-run mode\fP: Validates the request structure without adding secrets; useful for verification on non\-SEL systems
.RE
.SH OPTIONS
.PP
\-t, \-\-toc <FILE>
.RS 4
Specify the table\-of\-contents add\-secret request file toc.asr, which serves as the root of the EBC
resources. This file must contain a reference to toc.pol in its user data field,
as generated by \fBpvsecret\fR with the \fB\-\-policy\fR option. The toc.asr
file cryptographically links to the policy file by using a relative path and
SHA\-512 hash, ensuring the integrity of the complete EBC structure.
.RE
.RE
.PP
\-\-dry\-run
.RS 4
Validate the EBC structure without adding the add\-secret requests to the
ultravisor. Use this option to verify the integrity of the generated
policy file and the links between add\-secret request files and the policy.
This mode can be run on non\-SEL guests to validate the
structure before deployment. When \fB\-\-dry\-run\fR is specified, the tool
performs all cryptographic verifications but skips the actual addition of
secrets to the ultravisor secret store.
.RE
.RE
.PP
\-\-version
.RS 4
Print version information and exit.
.RE
.RE
.PP
\-h, \-\-help
.RS 4
Print help information.
.RE
.RE
.SH FILES
.PP
The \fBpvebc\fR tool operates on the following file types (actual names may
differ):
.PP
\fBtoc.asr\fR
.RS 4
The root add\-secret request file that contains a reference to the table\-of\-content \fBtoc.pol\fR in its
user data field. This file is generated by using \fBpvsecret create\fR with the
\fB\-\-policy\fR option.
.RE
.PP
\fBtoc.pol\fR
.RS 4
The policy file containing a newline\-separated list of AES\-GCM authentication
tags (MAC tags) in hexadecimal format. Each entry corresponds to one
add\-secret request file.
This file is generated by using \fBpvsecret create\fR with the
\fB\-\-toc\-policy\fR option.
.RE
.PP
\fB*.asr\fR
.RS 4
Individual add\-secret request files that contain the actual secrets to be added to
the SEL guest. Each add\-secret request file includes an AES\-GCM authentication tag (the last 16 bytes), which
provides integrity protection.
.RE
.SH EXIT STATUS
.PP
\fBpvebc\fR returns the following exit codes:
.PP
\fB0\fR
.RS 4
Success. All validations passed and secrets were added (if not in dry\-run mode).
.RE
.PP
\fB1\fR
.RS 4
Failure. An error occurred during validation or secret addition. Error details
are printed to stderr.
.RE
.SH NOTES
.PP
\- All file paths in a policy reference must be relative to the directory
that contains the referencing file.
.PP
\- On z/Architecture systems, the tool requires access to the ultravisor device
(\fB/dev/uv\fR) to add secrets.
.PP
.SH "SEE ALSO"
.sp
\fBpvsecret\fR(1), \fBpvsecret\-create\fR(1), \fBpvsecret\-add\fR(1)

39
rust/pvebc/src/cli.rs Normal file
View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp.
use std::{path::PathBuf, sync::OnceLock};
use clap::{ArgAction, Parser, ValueHint};
static VERSION: OnceLock<String> = OnceLock::new();
/// The pvebc command processes an AddSecretRequest file (toc.asr) that defines the root of EBC
/// resources. It validates references to the associated toc.pol policy and manages their addition,
/// with options for verification and dry-run execution.
#[derive(Parser)]
#[command(long_version=ver(), disable_version_flag(true))]
pub struct Cli {
/// Print version information and exit.
#[arg(long, action=ArgAction::Version)]
version: (),
/// Specifies the toc.asr which is the root of the EBC resources
///
/// Specify the add-secret request file toc.asr that serves as the root of the EBC resources.
/// Its user data must contain a reference to toc.pol as generated by pvsecret with the --policy
/// option.
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath)]
pub toc: PathBuf,
/// Prevents adding of the AddSecretRequest
///
/// Do not add the AddSecretRequest. Use this option to validate a generated policy. It can be
/// run on a non-SEL guest to verify ASR-to-policy links and the associated policy toc.pol.
#[arg(long)]
pub dry_run: bool,
}
fn ver() -> &'static str {
VERSION.get_or_init(|| utils::tools_version_fmt!(2026))
}

View File

@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp.
use anyhow::{bail, Context, Result};
use pv_core::misc::open_file;
use std::{io::Read, path::Path};
/// Length of the MAC tag in bytes (last 16 bytes of AddSecretRequest files)
pub const MAC_TAG_LEN: usize = 16;
/// Opens a file and returns a boxed reader
pub fn get_reader_from_filepath<P: AsRef<Path>>(filepath: P) -> Result<Box<dyn Read>> {
Ok(Box::new(open_file(filepath)?))
}
/// Get reader from &Path with additional context on error
pub fn get_reader(filepath: &Path) -> Result<Box<dyn Read>> {
get_reader_from_filepath(filepath)
.with_context(|| format!("unable to get reader from {:?}", filepath))
}
/// Read all data from a reader into a Vec<u8>
pub fn get_data(rd_in: &mut Box<dyn Read>) -> Result<Vec<u8>> {
let mut data_in = Vec::new();
rd_in
.read_to_end(&mut data_in)
.context("Cannot read input file")?;
Ok(data_in)
}
/// Extract the MAC tag (last 16 bytes) from an AddSecretRequest file
///
/// # Errors
///
/// Returns an error if:
/// - The file cannot be read
/// - The file is smaller than MAC_TAG_LEN bytes
pub fn get_mac_tag(filepath: &Path) -> Result<Vec<u8>> {
let mut rd_in = get_reader(filepath)?;
let data_in = get_data(&mut rd_in)?;
if data_in.len() < MAC_TAG_LEN {
bail!(
"File {:?} too small to contain MAC tag (expected at least {} bytes, got {})",
filepath,
MAC_TAG_LEN,
data_in.len()
);
}
Ok(data_in[data_in.len() - MAC_TAG_LEN..].to_vec())
}

369
rust/pvebc/src/main.rs Normal file
View File

@@ -0,0 +1,369 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp.
//! # pvebc - Protected Virtualization Early Boot Customization Tool
//!
//! This tool processes AddSecretRequest files (toc.asr) that define the root of EBC
//! (Early Boot Customization) resources. It validates references to associated
//! toc.pol policies and manages their addition to the system.
//!
//! ## Features
//!
//! - Validates AddSecretRequest files and their associated policies
//! - Verifies cryptographic hashes of policy files using SHA-256
//! - Supports dry-run mode for validation without system changes
//! - MAC tag validation for AddSecretRequest files
#![allow(missing_docs)]
mod cli;
mod ebc_utils;
#[cfg(target_arch = "s390x")]
use pv_core::uv::{AddCmd, UvDevice};
#[cfg(target_arch = "s390x")]
use utils::get_reader_from_cli_file_arg;
use anyhow::{bail, Context, Error, Result};
use clap::Parser;
use pv_core::{
misc::{decode_hex, encode_hex},
PolicyReference,
};
use std::{
fs::{self, File},
io::{BufRead, Read},
path::{Path, PathBuf},
process::ExitCode,
str::from_utf8,
};
// Don't use openssl here because this tool is intended to run in the initramfs
// phase of the boot and there we don't want to dynamically link against a C lib
use sha2::{self, Digest};
use zerocopy::TryFromBytes;
use crate::cli::Cli;
use crate::ebc_utils::{get_data, get_mac_tag, get_reader};
/// Offset in bytes where user data starts in an ASRCB v1 structure
const V1_USER_DATA_OFFS: usize = 536;
/// Size in bytes of the user data field in an ASRCB
const USER_DATA_SIZE: usize = 512;
/// Validates and resolves a policy name relative to a base directory
///
/// # Errors
/// Returns an error if path traversal is detected or the resolved path
/// is outside the base directory
fn validate_and_resolve_policy_path(base: &Path, name: &str) -> Result<PathBuf> {
// Validate path to prevent directory traversal
if name.contains("..") || name.starts_with('/') {
bail!("Invalid policy name: path traversal detected in '{}'", name);
}
let resolved = base.join(name);
// Ensure the resulting path is within the expected directory
if !resolved.starts_with(base) {
bail!(
"Policy path '{}' is outside the expected directory",
resolved.display()
);
}
Ok(resolved)
}
/// Extracts and validates the policy name from a PolicyReference
///
/// # Errors
/// Returns an error if the policy name contains invalid UTF-8 or is empty
fn extract_policy_name(policy_ref: &PolicyReference) -> Result<String> {
let name = from_utf8(&policy_ref.name)
.context("Policy name contains invalid UTF-8")?
.trim_matches('\0')
.to_string();
if name.is_empty() {
bail!("Policy name is empty");
}
Ok(name)
}
/// Computes the SHA-256 hash of data from a reader.
///
/// Reads data from the provided reader in 4096-byte chunks and computes
/// the SHA-256 hash of the entire content.
///
/// # Parameters
///
/// * `r` - A reader providing the data to hash
///
/// # Returns
///
/// Returns a `Vec<u8>` containing the 32-byte SHA-256 hash, or an error
/// if reading fails.
///
/// # Errors
///
/// Returns an error if reading from the reader fails.
pub fn sha256_hash<R: Read>(mut r: R) -> Result<Vec<u8>, Error> {
let mut hasher = sha2::Sha256::new();
let mut buf: [u8; 4096] = [0; 4096];
loop {
let read = r.read(&mut buf)?;
if read == 0 {
break;
}
hasher.update(&buf[..read]);
}
Ok(hasher.finalize().to_vec())
}
/// Extract the user data from an ASRCB
///
/// # Errors
///
/// Returns an error if the ASRCB is too small to contain user data
fn get_user_data(asrcb: &[u8]) -> Result<Option<Vec<u8>>> {
if asrcb.len() < V1_USER_DATA_OFFS + USER_DATA_SIZE {
bail!(
"ASRCB too small (expected at least {} bytes, got {})",
V1_USER_DATA_OFFS + USER_DATA_SIZE,
asrcb.len()
);
}
let user_data = &asrcb[V1_USER_DATA_OFFS..V1_USER_DATA_OFFS + USER_DATA_SIZE];
Ok(Some(user_data.to_vec()))
}
/// Get user data from AddSecretRequest
fn verify_user_data(filepath: &Path) -> Result<Option<Vec<u8>>> {
let mut rd_in = get_reader(filepath)?;
let data_in = get_data(&mut rd_in)?;
get_user_data(&data_in).context("Could not verify the Add-secret request")
}
/// Adds the given AddSecretRequest (if dryrun == false) and parses the contained user data
///
/// # Returns
///
/// On Success returns the PolicyReference parsed from the given AddSecretRequest
///
/// # Errors
///
/// returns an error if
/// - unable to open UvDevice
/// - reader from path fails
/// - adding of ASR fails
/// - verify_user_data fails
/// - unable to convert user data to PolicyReference
fn asr_to_pol_ref(filepath: &Path, dryrun: bool) -> Result<Option<PolicyReference>> {
print!("Add-Secret-Request: \"{}\"", filepath.display());
if !dryrun {
#[cfg(target_arch = "s390x")]
{
let uv = UvDevice::open()?;
let mut rd_in = get_reader_from_cli_file_arg(filepath)?;
let mut cmd = AddCmd::new(&mut rd_in)
.context(format!("Processing input file {:?}", filepath.to_str()))?;
uv.send_cmd(&mut cmd)?;
println!();
}
#[cfg(not(target_arch = "s390x"))]
{
println!(" (skip adding: not running on s390x architecture)");
}
} else {
println!(" (skip adding: dry-run mode)");
}
Ok(match verify_user_data(filepath)? {
Some(ud) => {
let ret = PolicyReference::try_read_from_bytes(&ud).map_err(|e| {
anyhow::anyhow!("Failed to parse PolicyReference from user data: {:?}", e)
})?;
println!(" Reference: {}", ret);
Some(ret)
}
None => None,
})
}
/// Read the mac tag list of the toc policy, parse and verify every tag
fn execute_toc_pol(path: &Path, toc_pol_ref: PolicyReference) -> Result<Vec<PathBuf>> {
let name = extract_policy_name(&toc_pol_ref)?;
let toc_path = validate_and_resolve_policy_path(path, &name)?;
let mut ret: Vec<PathBuf> = Vec::new();
let mut rd_in = get_reader(&toc_path)?;
let data_in = get_data(&mut rd_in)?;
let macs = data_in.lines();
let base = get_base_dir(&toc_path);
println!("Mac tags in {:?}:", toc_path);
for mac in macs {
let mut mac_tag = Vec::new();
let mac_tag_ref = match mac {
Ok(s) => s,
_ => continue,
};
print!(" {}", mac_tag_ref);
let entries = fs::read_dir(base)?;
for entry in entries {
let path = entry?;
let filepath = path.path();
let ext = match filepath.extension() {
Some(e) => e,
None => continue,
};
if ext == "asr" {
mac_tag = get_mac_tag(filepath.as_path())?;
if mac_tag == decode_hex(&mac_tag_ref)? {
println!(" -> {}", filepath.display());
ret.push(filepath.clone());
break;
}
}
}
if mac_tag != decode_hex(&mac_tag_ref)? {
bail!(
"No ASR with mac tag \"{}\" found in {:?}",
mac_tag_ref,
base
);
}
}
println!();
Ok(ret)
}
/// Checks whether the given hash in polref matches the actual hash of the referenced file
fn verify_policy(basename: &Path, polref: PolicyReference) -> Result<()> {
let name = extract_policy_name(&polref)?;
let filepath = validate_and_resolve_policy_path(basename, &name)?;
println!("Verify \"{}\"", filepath.display());
println!(" Referenced: {}", encode_hex(polref.hash));
let f = File::open(filepath.as_path())?;
let check_hash = sha256_hash(f)?;
println!(" Calculated: {}", encode_hex(&check_hash));
if check_hash != polref.hash {
bail!(
"{:?} ({}) does not match expected hash ({})",
filepath,
encode_hex(&check_hash),
encode_hex(polref.hash)
);
}
Ok(())
}
/// For every AddSecretRequest find the corresponding policy
fn execute_asrs(asrs: Vec<PathBuf>, dryrun: bool) -> Result<()> {
// loop over ASRs
for asr in asrs {
// get the referenced policy
let pol_ref = match asr_to_pol_ref(asr.as_path(), dryrun)? {
Some(pr) => pr,
None => continue,
};
if pol_ref.hash.iter().all(|&b| b == 0) {
continue;
}
let base = get_base_dir(asr.as_path());
let name = extract_policy_name(&pol_ref)?;
let _pol_path = validate_and_resolve_policy_path(base, &name)?;
// verify the integrity of the referenced policy
verify_policy(base, pol_ref)?;
}
Ok(())
}
/// Get the parent directory of the given file
fn get_base_dir(filepath: &Path) -> &Path {
match filepath.parent() {
Some(p) => p,
None => Path::new(""),
}
}
/// Print a given error and return the failure exit code
fn error_to_exit_code(err: Error) -> ExitCode {
eprintln!("Error: {}", err);
ExitCode::FAILURE
}
/// main function
pub fn main() -> ExitCode {
let opt: Cli = Cli::parse();
let dryrun = opt.dry_run;
if dryrun {
println!("Dry-run mode detected, skipping secret addition");
println!();
}
// get toc asr filepath - wrapper script has already copied files to tmpfs
let toc_asr = &opt.toc;
let basename = match toc_asr.parent() {
Some(p) => p,
None => {
return error_to_exit_code(Error::msg("Unable to get directory from specified path"))
}
};
// get the PolicyReference from toc.asr to toc.pol
let toc_pol = match asr_to_pol_ref(toc_asr, dryrun) {
Ok(o) => match o {
Some(r) => r,
None => {
return error_to_exit_code(Error::msg(
"There is no linked policy in the supplied ASR",
))
}
},
Err(e) => return error_to_exit_code(e),
};
// verify the integrity on the referenced toc.pol
if let Err(e) = verify_policy(basename, toc_pol) {
return error_to_exit_code(e);
}
println!();
// get and verify ASRs from mac list of toc policy
let asr_list = match execute_toc_pol(basename, toc_pol) {
Ok(v) => v,
Err(e) => return error_to_exit_code(e),
};
// execute ASRs
if let Err(e) = execute_asrs(asr_list, dryrun) {
return error_to_exit_code(e);
}
ExitCode::SUCCESS
}

View File

@@ -28,7 +28,7 @@ use std::{fmt::Display, fmt::LowerHex, marker::PhantomData, mem::size_of};
use pv::misc::{Flags, Msb0Flags64};
pub trait IntoEnumIterator {
pub trait IntoEnumIterator: Sized {
/// Returns an iterator over all variants of this enum.
fn iter() -> impl Iterator<Item = Self>;
}

View File

@@ -98,7 +98,7 @@ pub mod serde_base64 {
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
BASE64_STANDARD.decode(&s).map_err(serde::de::Error::custom)
BASE64_STANDARD.decode(s).map_err(serde::de::Error::custom)
}
}
@@ -124,7 +124,7 @@ pub mod serde_base64_array {
{
let s = String::deserialize(deserializer)?;
let decoded = BASE64_STANDARD
.decode(&s)
.decode(s)
.map_err(serde::de::Error::custom)?;
try_copy_slice_to_array(&decoded).map_err(serde::de::Error::custom)
}

View File

@@ -13,6 +13,7 @@ anyhow = { version = "1.0.95", features = ["std"] }
clap = { version ="4.5", features = ["derive", "wrap_help"]}
log = { version = "0.4.25", features = ["std", "release_max_level_debug"] }
serde_yaml = "0.9"
zerocopy = "0.8"
pv = { path = "../pv" , package = "s390_pv" }
utils = { path = "../utils"}

View File

@@ -194,6 +194,28 @@ Optional. No user\-data by default.
.RE
.RE
.PP
\-\-policy <FILE>
.RS 4
Links an add\-secret request to a policy file.
This option embeds a reference to a policy in the add\-secret request user data field. The
reference includes the relative file path and the SHA-512 hash of the
policy file, enabling verification of the policy files integrity.
This option conflicts with \fB\-\-user\-data\fR, because both options use the
same user data field in the add\-secret request structure.
.RE
.RE
.PP
\-\-toc\-policy <FILE>
.RS 4
Adds the AES\-GCM authentication tag to a table-of-contents (TOC) policy file.
This option appends the AES\-GCM authentication tag to the specified TOC policy
file. This allows the TOC policy to maintain a list of all add\-secret request MAC tags for
completeness verification during boot. During verification, the TOC checks the
AES\-GCM tags against this list to ensure that all expected add\-secret request are present and
unmodified.
.RE
.RE
.PP
\-\-user\-sign\-key <FILE>
.RS 4
Use the content of FILE as user signing key. Adds a signature calculated from

View File

@@ -130,6 +130,30 @@ pub struct CreateSecretOpt {
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub user_data: Option<String>,
/// Links an AddSecret-Request (ASR) to a policy file.
///
/// This option embeds a PolicyReference in the ASR user data field. The PolicyReference
/// includes the relative file path and the SHA512 hash of the policy file, allowing the
/// policys integrity to be verified.
///
/// This option conflicts with --user-data, because both options use the same user data field in
/// the ASR structure.
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath, conflicts_with("user_data"))]
pub policy: Option<String>,
/// Adds the AESGCM authentication tag to a TOC policy file.
///
/// This option appends the AESGCM authentication tag to the specified TOC policy file. This
/// allows the TOC policy to maintain a list of all ASR MAC tags for completeness verification
/// during boot. During verification, the TOC checks the MAC tags against this list to ensure
/// that all expected ASRs are present and unmodified.
#[arg(
long = "toc-policy",
value_name = "FILE",
value_hint = ValueHint::FilePath,
)]
pub tocpolicy: Option<String>,
/// Use the content of FILE as user signing key.
///
/// Adds a signature calculated from the key in FILE to the add-secret request. The
@@ -265,12 +289,10 @@ impl Display for RetrieveableSecretInpKind {
}
}
// all members s390x only
#[derive(Args, Debug)]
pub struct AddSecretOpt {
/// Specify the request to be sent.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath,)]
#[cfg(target_arch = "s390x")]
pub input: String,
/// Force the addition of add-secret requests.
@@ -282,7 +304,6 @@ pub struct AddSecretOpt {
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)]
#[cfg(target_arch = "s390x")]
pub enum ListSecretOutputType {
/// Human-focused, non-parsable output format
#[default]
@@ -293,17 +314,14 @@ pub enum ListSecretOutputType {
Bin,
}
// all members s390x only
#[derive(Args, Debug)]
pub struct ListSecretOpt {
/// Store the result in FILE
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath,)]
#[cfg(target_arch = "s390x")]
pub output: String,
/// Define the output format of the list.
#[arg(long, value_enum, default_value_t)]
#[cfg(target_arch = "s390x")]
pub format: ListSecretOutputType,
}
@@ -331,7 +349,6 @@ pub struct VerifyOpt {
pub output: String,
}
// all members s390x only
#[derive(Args, Debug)]
pub struct RetrSecretOptions {
/// Specify the secret ID to be retrieved.
@@ -341,22 +358,18 @@ pub struct RetrSecretOptions {
/// handle encodes in hexadecimal. Leading zeros are required. If there are multiple secrets in
/// the store with the same Id there are no guarantees on which specific secret is retrieved.
/// Use --inform=idx to make sure a specific secret is retrieved.
#[cfg(target_arch = "s390x")]
#[arg(value_name = "ID", value_hint = ValueHint::FilePath)]
pub input: String,
/// Specify the output path to place the secret value
#[cfg(target_arch = "s390x")]
#[arg(short, long, value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath)]
pub output: String,
/// Define input type for the Secret ID
#[cfg(target_arch = "s390x")]
#[arg(long, value_enum, default_value_t)]
pub inform: RetrInpFmt,
/// Define the output format for the retrieved secret
#[cfg(target_arch = "s390x")]
#[arg(long, value_enum, default_value_t)]
pub outform: RetrOutFmt,
}
@@ -478,10 +491,7 @@ mod test {
vec!["pvsecret", "lock"],
vec!["pvsecret", "version"],
vec!["pvsecret", "list"],
#[cfg(target_arch = "s390x")]
vec!["pvsecret", "add", "abc"],
#[cfg(not(target_arch = "s390x"))]
vec!["pvsecret", "add"],
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "meta"],
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "association", "name" ],
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "update-cck", "--secret", "abc"],
@@ -492,11 +502,8 @@ mod test {
"--root-ca", "tttt", "--cck", "cck", "--cuid-hex", "0x11223344556677889900aabbccddeeff", "--pcf", "0x123", "association", "name", "--stdout",
"--output-secret", "secret"],
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "association", "name", "--output-secret", "secret"],
#[cfg(target_arch = "s390x")]
vec!["pvsecret", "list", "--format", "human"],
#[cfg(target_arch = "s390x")]
vec!["pvsecret", "list", "--format", "yaml"],
#[cfg(target_arch = "s390x")]
vec!["pvsecret", "list", "--format", "bin"],
];
// Test for the minimal amount of flags to yield an invalid combination

View File

@@ -2,24 +2,30 @@
//
// Copyright IBM Corp. 2023, 2024
use std::path::Path;
use std::{
fs::OpenOptions,
io::{Read, Write},
path::Path,
};
use anyhow::{anyhow, bail, Context, Error, Result};
use log::{debug, info, trace, warn};
use pv::request::openssl;
use pv::{
misc::{
decode_hex, open_file, pv_guest_bit_set, read_exact_file, read_file, try_parse_u128,
try_parse_u64, write,
decode_hex, encode_hex, open_file, pv_guest_bit_set, read_exact_file, read_file,
try_parse_u128, try_parse_u64, write,
},
request::{
openssl::pkey::{PKey, Private},
BootHdrTags, ReqEncrCtx, Request, SymKeyType,
BootHdrTags, PolicyReference, ReqEncrCtx, Request, SymKeyType,
},
secret::{AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret, GuestSecret},
uv::ConfigUid,
};
use serde_yaml::Value;
use utils::get_writer_from_cli_file_arg;
use zerocopy::IntoBytes;
use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt, RetrieveableSecretInpKind};
@@ -33,6 +39,38 @@ where
Ok(())
}
/// Computes the SHA-256 hash of data from a reader.
///
/// Reads data from the provided reader in 4096-byte chunks and computes
/// the SHA-256 hash of the entire content.
///
/// # Parameters
///
/// * `r` - A reader providing the data to hash
///
/// # Returns
///
/// Returns a `Vec<u8>` containing the 32-byte SHA-256 hash, or an error
/// if reading fails.
///
/// # Errors
///
/// Returns an error if reading from the reader fails.
pub fn sha256_hash<R: Read>(mut r: R) -> Result<Vec<u8>, pv::PvCoreError> {
let mut hasher = openssl::Sha256::new();
let mut buf: [u8; 4096] = [0; 4096];
loop {
let read = r.read(&mut buf)?;
if read == 0 {
break;
}
hasher.update(&buf[..read]);
}
Ok(hasher.finish().to_vec())
}
fn retrievable(name: &str, secret: &str, kind: &RetrieveableSecretInpKind) -> Result<GuestSecret> {
let secret_data = read_file(secret, &format!("retrievable {kind}"))?.into();
@@ -76,6 +114,14 @@ pub fn create(opt: &CreateSecretOpt) -> Result<()> {
let rq =
ReqEncrCtx::random(SymKeyType::Aes256Gcm).context("Failed to generate random input")?;
let ser_asrbc = asrcb.encrypt(&rq)?;
if let Some(path) = &opt.tocpolicy {
let mac_tag = encode_hex(&ser_asrbc[(ser_asrbc.len() - 16)..]);
let mut file = OpenOptions::new().create(true).append(true).open(path)?;
writeln!(file, "{mac_tag}")?;
}
warn!("Successfully generated the request");
write_out(&opt.output, ser_asrbc, "add-secret request")?;
info!("Successfully wrote the request to '{}'", &opt.output);
@@ -157,6 +203,17 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result<AddSecretRequest> {
warn!("Added empty user-data file.");
}
let supplied_ref = opt
.policy
.as_ref()
.map(|s| -> Result<PolicyReference> {
let p = Path::new(s);
let reference = PolicyReference::new(p, sha256_hash)?;
println!("{}", encode_hex(reference.hash));
Ok(reference)
})
.transpose()?;
let user_key = opt
.user_sign_key
.as_ref()
@@ -169,6 +226,8 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result<AddSecretRequest> {
if user_data.is_some() || user_key.is_some() {
asrcb.set_user_data(user_data.unwrap_or_default(), user_key)?;
} else if let Some(ref_val) = supplied_ref {
asrcb.set_user_data(ref_val.as_bytes(), None)?;
}
Ok(asrcb)
}

View File

@@ -14,7 +14,7 @@ use utils::{print_cli_error, print_error, print_version, PvLogger};
static LOGGER: PvLogger = PvLogger;
static EXIT_LOGGER: u8 = 3;
const FEATURES: &[&[&str]] = &[cmd::CMD_FN, cmd::UV_CMD_FN];
const FEATURES: &[&[&str]] = &[cmd::CMD_FN, cmd::UV_CMD_FN, &["+ebc"]];
fn main() -> ExitCode {
let cli: CliOptions = match CliOptions::try_parse() {

View File

@@ -1,9 +1,10 @@
include ../common.mak
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg sclpdbf
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg sclpdbf pvics
# Helper scripts controlled by corresponding systemd services
SD_HELPER_SCRIPTS = cpictl dumpconf
MAN_PAGES = dbginfo.sh.8 zfcpdbf.8 zipl-switch-to-blscfg.8
MAN_PAGES = dbginfo.sh.8 zfcpdbf.8 zipl-switch-to-blscfg.8 pvics.8
FILE_MAN_PAGES = pvics.yaml.5
all:
@@ -33,6 +34,12 @@ install:
$(DESTDIR)$(MANDIR)/man8; \
done
@for i in $(FILE_MAN_PAGES); \
do \
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 $$i \
$(DESTDIR)$(MANDIR)/man5; \
done
clean:
.zfcpdbf.ct: zfcpdbf

View File

@@ -2,7 +2,7 @@
#
# dbginfo.sh - Tool to collect runtime, configuration, and trace information
#
# Copyright IBM Corp. 2002, 2025
# Copyright IBM Corp. 2002, 2026
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -14,7 +14,7 @@ export LC_ALL
########################################
# Global used variables
readonly SCRIPTNAME="${0##*/}" # general name of this script
readonly SCRIPTNAME="${0##*/}" # current name of this script
readonly FULLPATHSCRIPT="$(readlink -f "${0}")"
#
readonly DATETIME="$(date +%Y-%m-%d-%H-%M-%S 2>/dev/null)"
@@ -84,7 +84,7 @@ paramWORKDIR_BASE="/tmp" # initial default path
print_version() {
cat <<EOF
${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2002, 2025
Copyright IBM Corp. 2002, 2026
EOF
}
@@ -124,7 +124,7 @@ EOF
}
########################################
# check for oversize logfiles and missing rotation
# check for oversized logfiles and missing rotation
logfile_checker() {
local counter
local logfile
@@ -485,6 +485,7 @@ CMDS="uname -a\
:lscpu -ye\
:lscpumf -i\
:lsmem\
:zmemtopo -t\
:lsmod\
:lsshut\
:lsstp\

1579
scripts/pvics Executable file

File diff suppressed because it is too large Load Diff

340
scripts/pvics.8 Normal file
View File

@@ -0,0 +1,340 @@
.\" Copyright IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH PVICS 8 "April 2026" "s390-tools"
.SH NAME
pvics \- Convert qcow2 KVM guest images to EBC-ready SEL images
.SH SYNOPSIS
.B pvics
.I ACTION
.RB [ \-h | \-\-help ]
.RB [ \-c | \-\-config
.IR CONFIG_FILE ]
.RB [ \-i | \-\-image
.IR BASE_IMAGE ]
.SH DESCRIPTION
Use the \fBpvics\fR tool to convert existing QEMU Copy/-On/-Write version 2(qcow2) KVM
guest images into images that are ready for Early Boot Customization (EBC) and Secure Execution for Linux (SEL).
The tool encrypts the root file system and prepares all resources required for EBC.
The tool operates on a copy of the original base image and performs operations
in three main phases:
.IP \(bu 2
Retrieving information about a given base image
.IP \(bu 2
Converting a base image according to a configuration
.IP \(bu 2
Encrypting the root file system and preparing EBC resources
All operations preserve the original base image. Logs are written to a
temporary file, with the filename logged as the first message during runtime.
Temporary artifacts are automatically cleaned up on completion or failure.
.SH ACTIONS
.TP
.B list
Retrieve information about a given base image. This action displays available
boot loader entries from \fB/boot/loader/entries\fR, along with kernel and
initramfs hashes and the kernel command line. This is useful for:
.RS
.IP \(bu 2
Determining valid values for the \fBboot-loader-entry\fR configuration option
.IP \(bu 2
Comparing components between base and converted images
.IP \(bu 2
Verifying image contents before conversion
.RE
.TP
.B convert
Convert a base image according to the configuration file. This action:
.RS
.IP \(bu 2
Fetches kernel, initramfs, and kernel command line from the specified boot
loader entry
.IP \(bu 2
Builds a SEL image using \fBpvimg\fR(1)
.IP \(bu 2
Updates \fB/boot/bootmap\fR to boot into the SEL image
.RE
.IP
The resulting image will be a SEL guest image. It requires encryption to be
fully EBC-ready (unless \fBno-ebc\fR is enabled in the configuration).
.TP
.B encrypt
Encrypt the root file system and prepare EBC resources. This action:
.RS
.IP \(bu 2
Generates secure defaults (CCK, extension secret, LUKS keys) if not provided
.IP \(bu 2
Encrypts the root file system using LUKS with PAES
.IP \(bu 2
Populates \fB/boot/sics/\fR with add/-secret requests
.IP \(bu 2
Creates \fBtoc.pol\fR and \fBtoc.asr\fR for integrity protection
.RE
.IP
This action requires EBC. The guest can boot only by using PAES to open the root file system.
.TP
.B full
Perform both \fBconvert\fR and \fBencrypt\fR actions in sequence. This is
equivalent to running \fBconvert\fR followed by \fBencrypt\fR, but in a single
invocation.
.SH ARGUMENTS
.TP
.I ACTION
The action to perform: \fBlist\fR, \fBconvert\fR, \fBencrypt\fR, or \fBfull\fR.
.SH OPTIONS
.TP
.BR \-h ", " \-\-help
Display help message and exit.
.TP
.BR \-c ", " \-\-config " " \fICONFIG_FILE\fR
Path to the YAML configuration file. See \fBpvics.yaml\fR(5) for the
configuration file format and options.
.br
Required for \fBconvert\fR, \fBencrypt\fR, and \fBfull\fR actions.
.br
Not required for the \fBlist\fR action.
.TP
.BR \-i ", " \-\-image " " \fIBASE_IMAGE\fR
Path to the base qcow2 image file to process. Required for all actions.
.SH CONVERSION PROCESS
The conversion process consists of three phases:
.SS Component Fetching
The tool retrieves the kernel, initramfs, and kernel command line from the
boot loader entry specified in the configuration file. The components are
validated to ensure they meet SEL EBC requirements.
The tool prepends \fBrd.sel-ebc\fR to the kernel command line to trigger the
SEL EBC dracut module (unless \fBno-ebc\fR is enabled) and appends any
user-provided kernel parameters from the configuration.
.SS SEL Image Build
The SEL image is built using \fBpvimg\fR(1) with the fetched components.
Additional options may be specified in the configuration file via
\fB.convert.pvimg-create-options\fR.
.SS Bootmap Update
The tool updates the bootmap to boot into the new SEL image:
.IP \(bu 2
Existing boot loader entries in \fB/boot/loader/entries/*.conf\fR are renamed
to \fB*.conf.old\fR
.IP \(bu 2
A new entry \fBsel-ebc.conf\fR is created that points to \fB/boot/sel-ebc.img\fR
.IP \(bu 2
\fBzipl\fR(8) is run to update the bootmap.
The guest is temporarily started to update the bootmap using libvirt on z/Architecture
or qemu on non-z/Architecture architectures. Failures are logged to
\fB/var/log/sel-ebc-zipl.log\fR.
.SH ENCRYPTION PROCESS
The encryption process consists of three phases:
.SS Secure Default Generation
If not provided in the configuration, the following are generated from
\fB/dev/random\fR:
.IP \(bu 2
Customer communication key (CCK)
.IP \(bu 2
Root file system LUKS encryption key
.IP \(bu 2
Extension secret for add/-secret requests
.IP \(bu 2
LUKS passphrase
.SS Root File System Encryption
The root file system is encrypted using the following steps:
.IP 1. 3
Resize the qcow2 image to accommodate the LUKS header
.IP 2. 3
Resize the root partition (but not the file system) to fit the LUKS header
.IP 3. 3
Encrypt the root file system using LUKS
.IP 4. 3
Reformat the LUKS header from AES to PAES (Protected AES)
.SS AES to PAES Conversion
The LUKS header is converted from standard AES encryption to protected AES (PAES).
With PAES, encryption secrets are stored in the ultravisor secret store rather than directly in the LUKS header.
.SS SICS Population
The SEL Image Customization Source directory (\fB/boot/sics\fR) is populated
with the following secrets as add/-secret requests:
.IP \(bu 2
Customer communication key (CCK)
.IP \(bu 2
LUKS encryption key
.IP \(bu 2
LUKS passphrase
.IP \(bu 2
Any additional add/-secret requests specified in the configuration
All automatically built add/-secret requests are added to \fBtoc.pol\fR, which verifies the
completeness of \fB/boot/sics\fR. User-supplied add/-secret requests from the configuration
are also added. Finally, \fBtoc.asr\fR is built as a meta secret that links
to \fBtoc.pol\fR for integrity protection.
.SH BUILDING SEL IMAGES WITHOUT EBC
While the primary purpose of \fBpvics\fR is to create EBC-ready SEL images with
encrypted root file systems, it can also build SEL images without EBC
functionality using the \fBno-ebc\fR configuration option.
When \fBno-ebc: true\fR is set in the configuration:
.IP \(bu 2
The \fBconvert\fR action builds a SEL image without EBC-specific flags
.IP \(bu 2
The \fBencrypt\fR action is completely skipped
.IP \(bu 2
The \fBfull\fR action becomes equivalent to \fBconvert\fR only
.IP \(bu 2
The \fBrd.sel-ebc\fR kernel parameter is not added
.IP \(bu 2
\fB--enable-cck-update\fR and \fB--disable-image-encryption\fR flags are not
passed to \fBpvimg\fR
This mode is useful for:
.IP \(bu 2
Single-party image creation where the same entity performs conversion,
customization, and encryption
.IP \(bu 2
Testing SEL guest functionality without EBC complexity
.IP \(bu 2
Development and debugging scenarios
.IP \(bu 2
Simplified SEL image generation workflows
.SH OUTPUT FILES
All output files are written to the directory specified by the \fBout\fR
configuration option:
.TP
\fB<out>/image.qcow2\fR
The converted SEL image (after \fBconvert\fR or \fBfull\fR action)
.TP
\fB<out>/cck.key\fR
Customer communication key (generated if not provided)
.TP
\fB<out>/extension.secret\fR
Extension secret for add/-secret requests (generated if not provided)
.TP
\fB<out>/rfs.key\fR
Root file system LUKS encryption key (generated if not provided)
.TP
\fB<out>/passphrase\fR
LUKS passphrase (generated if not provided)
.TP
\fB<out>/*.asr\fR
Generated add-secret request files
.SH TEMPORARY FILES
.TP
\fB/tmp/tmp.*\fR
Log file (filename logged at startup)
.SH EXIT STATUS
.TP
.B 0
Success
.TP
.B 1
General error (invalid arguments, missing files, operation failure)
.SH EXAMPLES
.SS List Boot Loader Entries
.nf
pvics list \-\-image /path/to/base-image.qcow2
.fi
.SS Convert Image Only
.nf
pvics convert \-\-config /path/to/config.yaml \-\-image /path/to/base-image.qcow2
.fi
.SS Encrypt Image Only
.nf
pvics encrypt \-\-config /path/to/config.yaml \-\-image /path/to/converted-image.qcow2
.fi
.SS Full Conversion and Encryption
.nf
pvics full \-\-config /path/to/config.yaml \-\-image /path/to/base-image.qcow2
.fi
.SS Build SEL Image Without EBC
.nf
# config.yaml contains: no-ebc: true
pvics convert \-\-config /path/to/config.yaml \-\-image /path/to/base-image.qcow2
.fi
.SH FILES
.TP
\fB/boot/loader/entries/*.conf\fR
Boot loader entry files in the base image
.TP
\fB/boot/sel-ebc.img\fR
The resulting SEL image file in the guest
.TP
\fB/boot/sics/\fR
SEL image-customization source directory that contains EBC resources
.TP
\fB/boot/sics/toc.pol\fR
Table-of-contents policy file that lists all add/-secret requests
.TP
\fB/boot/sics/toc.asr\fR
Meta secret for integrity protection of toc.pol
.TP
\fB/var/log/sel-ebc-zipl.log\fR
Log file for zipl bootmap update operations
.SH NOTES
.IP \(bu 2
All operations are performed on a copy of the original base image.
.IP \(bu 2
The tool requires root privileges for file-system operations.
.IP \(bu 2
The LUKS device is named \fBcryptroot\fR.
.IP \(bu 2
The temporary working directory is created at \fB/opt/sel-<UUID>\fR.
.IP \(bu 2
The \fBno-verify\fR option should not be used in production environments.
.IP \(bu 2
Generated secrets are written to the output directory and should be secured
appropriately.
.SH SEE ALSO
.BR pvics.yaml (5),
.BR pvsecret (1),
.BR pvimg (1),
.BR pvebc (8),
.BR zipl (8),
.BR cryptsetup (8),
.BR lsinitrd (1)
.PP
Linux on IBM Z and IBM LinuxONE: Secure Execution for Linux documentation
.SH AUTHOR
IBM Corporation

106
scripts/pvics.yaml Normal file
View File

@@ -0,0 +1,106 @@
# SPDX-License-Identifier: MIT
#
# Copyright IBM Corp.
# OPTIONAL (default: false)
no-verify: false
# This option controls whether the --no-verify flag is used with the pv commands.
# OPTIONAL (default: false)
no-ebc: false
# This option controls whether to trigger the SEL EBC related systemd units.
# It can be used to create a SEL guest image from an existing qcow2 image without utilizing SEL EBC.
# Setting this to true will prevent the encrypt action from running.
# In this case, the full action equals the convert action.
# Setting this to true will prevent the default pvimg options (see below) from being added and instead
# only add the user provided ones in .convert.pvimg-options.
# REQUIRED
out: data/output
# This specifies the local directory used for output.
# REQUIRED
hkds:
- data/*.hkd
# These are the paths to all relevant Host-Key-Documents.
# The paths may contain wildcard patterns.
# REQUIRED if .no-verify is false
# UNUSED if .no-verify is true
# This section contains all relevant files for verification of the certificate chain.
# See man pvsecret for more detailed information about any of the keys in this section.
certificate-chain:
# The paths may contain wildcard patterns.
certs:
- data/*.cert
# The paths may contain wildcard patterns.
crls:
- data/*.crl
# This is the pvsecret create offline option.
offline: true
# This is the root CA of the given certificates.
root-ca: data/root.ca
# This section contains relevant information for the first phase: conversion.
convert:
# REQUIRED
boot-loader-entry: boot_loader_entry_title
# This is the boot loader entry name to be used for kernel, initramfs and kernel parameter.
# You can list available boot loader entries with the list action.
# OPTIONAL
sel-kernel-parameter: swiotlb=524288
# These are additional kernel parameters for the resulting SEL image.
# The parameter rd.sel-ebc will always be added.
# OPTIONAL (default: --enable-pckmo-hmac)
pvimg-create-options: --enable-pckmo-hmac
# These are additional pvimg options for the resulting SEL image.
# The options --disable-image-encryption and --enable-update-cck are always used except when .no-ebc is true.
# This section contains relevant information for the second phase: encryption.
encrypt:
# OPTIONAL
cck: data/cck.key
# This is the local path to the CCK.
# If none is supplied, one will be generated and written to .out/cck.key.
# OPTIONAL
extension-secret: data/extension.secret
# This is the local path to the extension secret for pvsecret create.
# This is REQUIRED if .encrypt.add-secret-requests is used.
# In this case, the extension secret must be the one from the supplied ASRs.
# If none is supplied, one will be generated and written to .out/extension.secret.
# OPTIONAL
luks-key: data/rfs.key
# This is the local path to the LUKS encryption key.
# If none is supplied, one will be generated and written to .out/rfs.key.
# OPTIONAL
luks-passphrase: data/passphrase
# This is the local path to a file containing the LUKS passphrase.
# If none is supplied, one will be generated and written to .out/passphrase.
# OPTIONAL (default: rfs-luks-key)
luks-key-asr-name: aes-xts-segment-key
# This is the name of the ASR containing the LUKS encryption key.
# OPTIONAL (default: depending on .encrypt.luks-key)
luks-key-size: 512
# This is the key size of the LUKS encryption key (256 or 512).
# If .encrypt.luks-key is supplied, this will default to a size depending on the key.
# Otherwise, this will default to 512 and generate a matching key.
# If this is supplied but no key is supplied, a key of the requested size will be generated.
# OPTIONAL
add-secret-requests:
- data/*.asr
# These are additional secrets to be added during boot.
# Using this will make .encrypt.extension-secret a required argument.
# The supplied extension secret and the extension secret of supplied ASRs must be the same.
# The paths may contain wildcard patterns.

321
scripts/pvics.yaml.5 Normal file
View File

@@ -0,0 +1,321 @@
.\" Copyright IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH PVICS.YAML 5 "April 2026" "s390-tools"
.SH NAME
pvics.yaml \- Configuration file for pvics SEL EBC image conversion tool
.SH DESCRIPTION
The \fBpvics.yaml\fR file is a YAML-formatted configuration file used by the
\fBpvics\fR tool to control the conversion of existing qcow2 KVM guest images
to EBC-ready Secure Execution for Linux (SEL) images. The configuration file
specifies parameters for image conversion, root file system encryption, and
early boot customization (EBC) resource preparation.
See \fBpvics\fR(8) for detailed information about the tool's actions and the
conversion process.
.SH FILE FORMAT
The configuration file uses YAML syntax with the following top-level sections:
.TP
\fBGlobal Options\fR
General settings that apply to all actions
.TP
\fBCertificate Chain\fR
Certificate verification configuration
.TP
\fBConversion Options\fR
Settings specific to the \fBconvert\fR action
.TP
\fBEncryption Options\fR
Settings specific to the \fBencrypt\fR action
.SH GLOBAL OPTIONS
.TP
\fBno-verify:\fR \fIboolean\fR
Disables certificate chain verification for pv commands when set to true.
Default: \fBfalse\fR.
.br
\fBWARNING:\fR Do not disable certificate chain verification in production environments.
.TP
\fBno-ebc:\fR \fIboolean\fR
Controls whether EBC functionality is used. When set to
\fBtrue\fR, a SEL guest image is created without using EBC.
Default: \fBfalse\fR.
.br
When enabled:
.RS
.IP \(bu 2
The \fBencrypt\fR action is skipped
.IP \(bu 2
The \fBfull\fR action behaves the same as the \fBconvert\fR action
.IP \(bu 2
Default \fBpvimg\fR options are not added; only user-provided options specified in
\fB.convert.pvimg-create-options\fR are used
.IP \(bu 2
The \fBrd.sel-ebc\fR kernel parameter is not added
.RE
.TP
\fBout:\fR \fIpath\fR
\fB(REQUIRED)\fR Local directory path used for output files. All generated
files (converted images, keys, ASRs) will be written to this directory.
.TP
\fBhkds:\fR \fIlist\fR
\fB(REQUIRED)\fR List of paths to host-key-documents (HKDs). Paths may contain
wildcard patterns, for example \fBdata/*.hkd\fR.
.br
Example:
.RS
.nf
hkds:
- data/*.hkd
- /path/to/specific.hkd
.fi
.RE
.SH CERTIFICATE CHAIN
The \fBcertificate-chain\fR section contains all relevant files for verification
of the certificate chain. This section is \fBREQUIRED\fR if \fBno-verify\fR is
\fBfalse\fR, and \fBUNUSED\fR if \fBno-verify\fR is \fBtrue\fR.
See \fBpvsecret\fR(1) for more detailed information about certificate chain
verification.
.TP
\fBcertificate-chain.certs:\fR \fIlist\fR
List of paths to certificate files. Paths may contain wildcard patterns.
.br
Example:
.RS
.nf
certs:
- data/*.cert
.fi
.RE
.TP
\fBcertificate-chain.crls:\fR \fIlist\fR
List of paths to certificate revocation list (CRL) files. Paths may contain
wildcard patterns.
.br
Example:
.RS
.nf
crls:
- data/*.crl
.fi
.RE
.TP
\fBcertificate-chain.offline:\fR \fIboolean\fR
Enables offline mode for the \fBpvsecret create\fR command. When \fBtrue\fR, no
network access is attempted for certificate verification.
.TP
\fBcertificate-chain.root-ca:\fR \fIpath\fR
Path to the root Certificate Authority (CA) file for the certificate chain.
.SH CONVERSION OPTIONS
The \fBconvert\fR section contains configuration options for the image
conversion phase. These options are used only when running the \fBconvert\fR or
\fBfull\fR actions and have no effect on other actions.
.TP
\fBconvert.boot-loader-entry:\fR \fIstring\fR
\fB(REQUIRED)\fR Title of an existing boot loader entry from the base image.
This entry specifies which kernel, initramfs, and kernel command line to use
for the SEL image.
.br
Use the \fBlist\fR action to display available boot loader entries in the
base image.
.TP
\fBconvert.sel-kernel-parameter:\fR \fIstring\fR
\fB(OPTIONAL)\fR Additional kernel parameters to append to the kernel command
line of the resulting SEL image. The \fBrd.sel-ebc\fR parameter is always
prepended automatically (unless \fBno-ebc\fR is \fBtrue\fR).
.br
Example:
.RS
.nf
sel-kernel-parameter: swiotlb=524288
.fi
.RE
.TP
\fBconvert.pvimg-create-options:\fR \fIstring\fR
\fB(OPTIONAL)\fR Additional options to pass to the \fBpvimg\fR command during
SEL image creation.
.br
See \fBpvimg\fR(1) for available options.
.SH ENCRYPTION OPTIONS
The \fBencrypt\fR section contains configuration options specific to the root filesystem
encryption and EBC resource preparation phase. These options are only used when running
the \fBencrypt\fR or \fBfull\fR actions and are ignored when \fBno-ebc\fR
is \fBtrue\fR.
.TP
\fBencrypt.cck:\fR \fIpath\fR
\fB(OPTIONAL)\fR Path to the customer communication key (CCK) file. If not
supplied, a CCK will be generated from \fB/dev/random\fR and written to
\fB<out>/cck.key\fR.
.TP
\fBencrypt.extension-secret:\fR \fIpath\fR
\fB(OPTIONAL)\fR Path to the extension secret file used for \fBpvsecret create\fR
commands. If not supplied, an extension secret will be generated from
\fB/dev/random\fR and written to \fB<out>/extension.secret\fR.
.br
\fBREQUIRED\fR if \fBencrypt.add-secret-requests\fR is used. In this case, the
extension secret must match the one used in the supplied add/-secret requests.
.TP
\fBencrypt.luks-key:\fR \fIpath\fR
\fB(OPTIONAL)\fR Path to the LUKS encryption key file for the root filesystem.
If not supplied, a key will be generated from \fB/dev/random\fR and written to
\fB<out>/rfs.key\fR.
.TP
\fBencrypt.luks-passphrase:\fR \fIpath\fR
\fB(OPTIONAL)\fR Path to a file that contains the LUKS passphrase. If not supplied,
a passphrase will be generated from \fB/dev/random\fR and written to
\fB<out>/passphrase\fR.
.TP
\fBencrypt.luks-key-asr-name:\fR \fIstring\fR
\fB(OPTIONAL)\fR Name of the add-secret request that contains the LUKS
encryption key. Default: \fBrfs-luks-key\fR.
.TP
\fBencrypt.luks-key-size:\fR \fIinteger\fR
\fB(OPTIONAL)\fR Key size in bits for the LUKS encryption key. Valid values:
\fB256\fR or \fB512\fR. If not specified, the size is determined from the
supplied key file or a default size is used for generated keys.
.TP
\fBencrypt.add-secret-requests:\fR \fIlist\fR
\fB(OPTIONAL)\fR List of paths to additional add/-secret request files to
be added during boot. Paths may contain wildcard patterns.
.br
When using this option:
.RS
.IP \(bu 2
\fBencrypt.extension-secret\fR is \fBREQUIRED\fR
.IP \(bu 2
The supplied extension secret must match the extension secret used in all
supplied add/-secret requests
.RE
.br
Example:
.RS
.nf
add-secret-requests:
- data/*.asr
- /path/to/custom.asr
.fi
.RE
.SH EXAMPLES
.SS Minimal Configuration for EBC
.nf
out: /path/to/output
hkds:
- /path/to/*.hkd
certificate-chain:
certs:
- /path/to/*.cert
crls:
- /path/to/*.crl
offline: true
root-ca: /path/to/root.ca
convert:
boot-loader-entry: "My Boot Entry"
.fi
.SS Configuration with Custom Encryption Keys
.nf
out: /path/to/output
hkds:
- /path/to/*.hkd
certificate-chain:
certs:
- /path/to/*.cert
crls:
- /path/to/*.crl
offline: true
root-ca: /path/to/root.ca
convert:
boot-loader-entry: "My Boot Entry"
sel-kernel-parameter: swiotlb=524288
pvimg-create-options: --enable-pckmo-hmac
encrypt:
cck: /path/to/cck.key
luks-key: /path/to/rfs.key
luks-passphrase: /path/to/passphrase
luks-key-size: 512
.fi
.SS Configuration with Additional ASRs
.nf
out: /path/to/output
hkds:
- /path/to/*.hkd
certificate-chain:
certs:
- /path/to/*.cert
crls:
- /path/to/*.crl
offline: true
root-ca: /path/to/root.ca
convert:
boot-loader-entry: "My Boot Entry"
encrypt:
extension-secret: /path/to/extension.secret
add-secret-requests:
- /path/to/*.asr
.fi
.SS SEL Image Without EBC
.nf
no-ebc: true
out: /path/to/output
hkds:
- /path/to/*.hkd
convert:
boot-loader-entry: "My Boot Entry"
.fi
.SH FILES
.TP
\fB/boot/loader/entries/*.conf\fR
Boot loader entry files in the base image
.TP
\fB/boot/sel-ebc.img\fR
The resulting SEL image file
.TP
\fB/boot/sics/\fR
SEL Image customization source directory containing EBC resources
.TP
\fB/boot/sics/toc.pol\fR
Table of contents policy file listing all add/-secret requests
.TP
\fB/boot/sics/toc.asr\fR
Meta-secret for integrity protection of toc.pol
.TP
\fB/var/log/sel-ebc-zipl.log\fR
Log file for zipl bootmap update operations
.SH SEE ALSO
.BR pvics (8),
.BR pvsecret (1),
.BR pvimg (1),
.BR zipl (8),
.BR cryptsetup (8)
.PP
Linux on IBM Z and IBM LinuxONE: Secure Execution for Linux documentation

View File

@@ -2,7 +2,7 @@
#
# zfcpdbf - Tool to interpret the information from logging/tracing sources
#
# Copyright IBM Corp. 2010, 2020
# Copyright IBM Corp. 2010, 2026
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -102,6 +102,7 @@ use POSIX qw(strftime floor difftime mktime);
use File::Spec::Functions qw/catfile catdir rel2abs/;
use File::Basename;
use Getopt::Long;
use List::Util qw(min);
use constant TOD_UNIX_EPOCH => 0x7d91048bca000000;
use constant STD_DEBUG_DIR => "/sys/kernel/debug/s390dbf/";
@@ -595,6 +596,9 @@ sub _print_hba_id1
my $rec_received = shift();
my $rec_issued;
my $pay_rec = $PAYLOAD_RECORDS{$fsf_req_id}{"fsf_res"};
my $plogi_length = hex(substr($rec, 112, 8));
my $prli_length = hex(substr($rec, 120, 8));
my $els_rec = $PAYLOAD_RECORDS{$fsf_req_id}{"fsf_els"};
$rec_issued = stck_to_timeval(substr($rec, 0, 16));
@@ -627,6 +631,19 @@ sub _print_hba_id1
print "QTCB log length: ", $payload_length, "\n" if ($payload_length);
print_payload($payload_length, $pay_rec, "QTCB log info")
if ($payload_length);
if ($plogi_length) {
print "PLOGI length : ", $plogi_length, "\n";
$plogi_length = min($plogi_length, 256);
}
if ($prli_length) {
print "PRLI length : ", $prli_length, "\n";
$prli_length = min($prli_length, 256 - $plogi_length);
}
if ($plogi_length || $prli_length) {
print_payload($plogi_length + $prli_length, $els_rec,
"PLOGI/PRLIinfo");
}
}
sub _print_hba_id2
@@ -641,8 +658,15 @@ sub _print_hba_id2
print "SRB D_ID : 0x", substr($rec, 16, 8), "\n";
print "SRB LUN : 0x", substr($rec, 24, 16), "\n";
print "SRB q-design. : 0x", substr($rec, 40, 16), "\n";
print "SRB length : 0x", substr($rec, 56, 8), "\n";
print "SRB res1 : 0x", substr($rec, 64, 8), "\n";
print "SRB res2 : 0x", substr($rec, 72, 2), "\n";
print "SRB class : 0x", substr($rec, 74, 8), "\n";
print "SRB res3 : 0x", substr($rec, 82, 2), "\n";
print "SRB S_ID : 0x", substr($rec, 84, 8), "\n";
print "SRB res4 : ", payload_format(substr($rec, 92, 40));
print "SRB length : ", $payload_length, "\n" if ($payload_length);
print "SRB pay length : ", $payload_length, "\n" if ($payload_length);
print_payload($payload_length, $pay_rec, "SRB info")
if ($payload_length);
}
@@ -714,6 +738,19 @@ sub _print_hba_id5
print "FCES new : 0x", substr($rec, 56, 8), "\n";
}
sub _print_hba_id6
{
my $fsf_req_id = shift();
my $rec = shift();
my $payload_length = shift();
my $rec_received = shift();
my $rec_issued;
print "WWPN : 0x", substr($rec, 0, 16), "\n";
print "LUN : 0x", substr($rec, 16, 16), "\n";
print "Return Value : 0x", substr($rec, 32, 8), "\n";
}
sub print_deferr_common
{
my $rec = shift();
@@ -916,6 +953,7 @@ sub assign_callback_subs
$print_hba_id[2] = \&_print_hba_id2;
$print_hba_id[3] = \&_print_hba_id3;
$print_hba_id[5] = \&_print_hba_id5;
$print_hba_id[6] = \&_print_hba_id6;
$print_rec_id[1] = \&_print_rec_id1;
$print_rec_id[2] = \&_print_rec_id2;

View File

@@ -1,25 +0,0 @@
include ../common.mak
ALL_CPPFLAGS += -D_FILE_OFFSET_BITS=64
all: tape390_display tape390_crypt
tape390_display: tape390_display.o tape390_common.o
tape390_crypt: tape390_crypt.o tape390_common.o
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 tape390_display \
$(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 tape390_display.8 \
$(DESTDIR)$(MANDIR)/man8
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 tape390_crypt \
$(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 tape390_crypt.8 \
$(DESTDIR)$(MANDIR)/man8
clean:
rm -f *.o *~ tape390_display tape390_crypt core
.PHONY: all install clean

View File

@@ -1,86 +0,0 @@
/*
* tape_390 - Common functions
*
* Copyright IBM Corp. 2006, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include "tape390_common.h"
#define PROC_DEVICES_FILE "/proc/devices"
#define PROC_DEVICES_FILE_WIDTH 100
char *prog_name; /* Name of tool */
/*
* Set name of tool
*/
void set_prog_name(char *name)
{
prog_name = name;
}
/*
* Check whether specified device node is tape device
*/
int is_not_tape(char *device)
{
FILE* fh;
char line[PROC_DEVICES_FILE_WIDTH];
char last_line[PROC_DEVICES_FILE_WIDTH];
int found = 0;
struct stat stat_struct;
if (stat(device, &stat_struct)) {
ERRMSG("%s: Unable to get device status for "
"'%s'. \n", prog_name, device);
perror("");
return 1;
}
fh = fopen(PROC_DEVICES_FILE,"r");
if (!fh) {
ERRMSG("%s: WARNING: Cannot check for tape in file "
PROC_DEVICES_FILE ".\n", prog_name);
perror("");
return(0); /* check not possible, just continue */
}
while (!found && (fscanf(fh, "%s", line) != EOF)) {
if (strcmp(line, "tape") == 0)
found = 1;
else
strcpy(last_line, line);
}
fclose(fh);
if (found && (major(stat_struct.st_rdev) ==
(unsigned int) atoi(last_line)))
return (0);
else {
ERRMSG("%s: '%s' is not a tape device. \n", prog_name, device);
return 1;
}
}
/*
* Open the tape device
*/
int open_tape(char *device)
{
int fd;
fd = open(device,O_RDONLY);
if (fd < 0) {
ERRMSG("%s: Cannot open device %s.\n",
prog_name,device);
perror("");
exit(EXIT_MISUSE);
}
return fd;
}

View File

@@ -1,22 +0,0 @@
/*
* tape_390 - Common functions
*
* Copyright IBM Corp. 2006, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _TAPE390_COMMON_H
#define _TAPE390_COMMON_H
#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
#define ERRMSG_EXIT(ec,x...) do {fflush(stdout);fprintf(stderr,x);exit(ec);} while(0)
#define EXIT_MISUSE 1
extern int is_not_tape(char *);
extern int open_tape(char *);
extern void set_prog_name(char *);
extern char *prog_name;
#endif

Some files were not shown because too many files have changed in this diff Show More