Compare commits

...

29 Commits

Author SHA1 Message Date
Jan Höppner
f75c923627 New release s390-tools-2.25.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-12-08 13:40:15 +01:00
Fedor Loshakov
bca8fa3f9c ziomon: fix Makefile install step chown warnings
Since coreutils v9.1 commit 8f31074cb ("chown: warn about USER.GROUP")
chown utility now warns about using of wrong separator for USER and
GROUP options. This leads to warnings during intall step in ziomon:

$ make install
  INSTALL ziomon
  SED     ziomon/install
chown: warning: '.' should be ':': ‘root.root’
  SED     ziomon/install
chown: warning: '.' should be ':': ‘root.root’
  SED     ziomon/install
chown: warning: '.' should be ':': ‘root.root’

To fix those warnings use ':' as separator instead of '.'. With this
patch applied those warnings are no longer present.

Signed-off-by: Fedor Loshakov <loshakov@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:54:09 +01:00
Joern Siglen
d713ea6389 dbginfo.sh: log the work dir state in dbginfo.log
As on space problems the packing may fail, incomplete tgz are send.
Today no evidence for this is in dbginfo.log, packed upfront into the tgz.
This update helps to identify space related corruption of tgz files.

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:54:09 +01:00
Niklas Schnelle
f9fbe79e4f ipl_tools: Fix chreipl node for NVMes with CONFIG_NVME_MULTIPATH
When the kernel is build with CONFIG_NVME_MULTIPATH enabled and an NVMe
where the driver exposes its controller separately is used, chreipl node
on a mount point of the NVMe fails. The failure occurs because chreipl
tries to get the function_id from the NVMe's nvmeXnY block device via
the path '/sys/block/nvmeXnY/device/device/function_id' which does not
exist.

The underlying problem is that with NVMe multipath support the PCI
function is not associated directly with a particular NVMe namespace but
instead with the entire NVMe device which may host multiple NVMe
namespaces. The correct way to get from the block device to the
underlying PCI device and its function ID is then to extract the device
name i.e. the 'nvmeX' part from 'nvmeXnY' and use that to get the
function ID via '/sys/class/nvme/nvme<X>/device/function_id'.

Fixes: 0472b5ea5c ("ipl-tools: Add nvme device support to lsreipl/chreipl")
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:54:09 +01:00
Steffen Eiden
3cc0b4cdea pvattest/tools: remove xxd dependency from scripts
xxd has vim-common as a dependency. We can avoid that by using od
instead which is from coreutils.

While at it, add the require_command function from the
pvattest-info script to the pvextract-hdr script and use it.

Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:53:37 +01:00
Steffen Eiden
eef9f622c0 pvattest/man: fix wording
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:50:16 +01:00
Daniel S. Haischt
889293e557 zdev: implement --shell command line switch
Fix issue in the lszdev command where column names if using the --pairs
command line switch can contain characters that are not allowed to be
used as variable names in a shell environment.

Replace bad characters in column names by an underscore if the --shell
command line switch is specified along with the --pairs switch.

The additional --shell switch mimics what is already available in the
lsblk command and thus it shall be used along with the --pairs switch.

Signed-off-by: Daniel S. Haischt <modean@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:50:16 +01:00
Jan Höppner
0c5b9f5d11 mon_tools: Silence address-of-packed-member compile warning
The proc_sum_t struct is defined with the packed attribute and
produces the following compile warning:

mon_procd.c: In function ‘read_cpu’:
mon_procd.c:351:27: warning: taking address of packed member of ‘struct proc_sum_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
  351 |         cal_cpu(&cpudata, &proc_sum.cpu);
      |                           ^~~~~~~~~~~~~

Silence the warning with -Wno-address-of-packed-member compile flag
since the struct is required to be as is.

Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:50:09 +01:00
Jan Höppner
02af069d48 boot_defs.h: Fix compile warning in zfcpdump
The struct scsi_dump_sb is defined with the __packed attribute and
produces the following compile warning in zfcpdump:

zfcpdump_part.c: In function ‘csum_update’:
zfcpdump_part.c:125:41: warning: taking address of packed member of ‘struct scsi_dump_sb’ may result in an unaligned pointer value [-Waddress-of-packed-member]
  125 |                      dump_sb.csum_size, &dump_sb.csum)) {
      |                                         ^~~~~~~~~~~~~

However, all members are of the same size and the __packed attribute is
unnecessary. Remove the attribute to get rid of the warning.
Add assertion to ensure correct size of the struct during compile time.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2022-12-07 16:49:04 +01:00
Steffen Eiden
5e0056db8d util_lockfile: fix includes
The 'unistd.h' header was missing. Under some circumstances the
-D_GNU_SOURCE gcc flag does not trigger including that file.
Therefore, explicitly include this file here.

Fixes: e1aec24e84 ("libutil: introduce util_lockfile")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-30 15:51:15 +01:00
Matthew Rosato
4b5937f142 ap_tools/ap-check: use new mdevctl install location
mdevctl has been updated to use /usr/lib/mdevctl/scripts.d/callouts/
instead of /etc/mdevctl.d/scripts.d/callouts/.  The /etc location
is considered deprecated, meaning mdevctl will also look at that
location for now but might eventually stop looking in /etc for
callout scripts.
Based on that, update the installation location for the ap-check
callout.  However, because older versions of mdevctl will still
only look in /etc, let's also put a wrapper script in /etc for now
to provide backward compatibility, and plan to remove it at a
later time.

Link: df6bb57429
Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/139
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-30 15:50:33 +01:00
Marc Hartmayer
8d8d5e9746 zdump: Fix Makefile dependencies
The Makefile target `check_dep_fuse` was declared as .PHONY and
therefore it was always rebuilt. This caused zgetdump to always be
relinked. While at it, remove the non-existent Makefile target
`check_dep_zlib` and add the cache files to `.gitignore`.

Closes: https://github.com/ibm-s390-linux/s390-tools/issues/144
Fixes: e537ab902e ("zdump: Makefile: add basic libpv support")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Jan Höppner
5bdabe3e06 common.mak: Fix pretty print for linking
Commit ae7217806b ("common.mak: remove `LINK` and `LINKXX`") changed
the LINK and LINKXX definition to ensure that the same compiler is used
for compilation and linking when specified with CC= (or CXX=
respectively) on the commandline.

However, the commit also removed the pretty print for both commands. Add
the pretty print back in and use the already defined $(CC) and $(CXX)
variables to preserve the original change.

Fixes: ae7217806b ("common.mak: remove `LINK` and `LINKXX`")
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Marc Hartmayer
8a1db94d37 zdump: add missing newlines for log messages
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Marc Hartmayer
1911cba130 zdump: check provided sizes for reasonableness
Check the dump provided sizes for reasonableness. This avoids that a
corrupted dump leads to allocation of large buffers on the heap.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Marc Hartmayer
f4ed0b0ec6 zdump: check size before mmap'ing
Verify that the size is large enough before doing the mmap. Otherwise
this can result in a SIGBUS signal if there is an attempt to access a
page that lies beyond the end of the mapped file (see `man 2 mmap`).

Fixes: 8fa1b5a00b ("zdump: dfi: add support to read Protected Virtualization dumps")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Marc Hartmayer
6e42c527d7 zdump: pv_process_pglist: convert assertions into errors
Corrupted dumps might have invalid page states. Therefore, let's convert
the assertions into errors.

Fixes: 8fa1b5a00b ("zdump: dfi: add support to read Protected Virtualization dumps")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Eduard Shishkin
f7d2339c6a zipl: List-Directed IPL from ECKD DASD
Make zipl tool prepare ECKD DASD for booting by different IPL
programs (with the same boot record installed).

Besides standard CCW-type IPL, user gets an ability to trigger
(with the same boot record installed!) List-Directed IPL. This
allows to use the feature of secure boot from ECKD DASD (which
is not available for CCW-type IPL).

When using the old boot interfaces, the usual CCW-type IPL is
triggered for DASD. Also for compatibility reasons zipl(8) tool
is modified to create and install one, or two "similar" program
tables per boot partition, depending on job and disk type. The
"similar" program tables differ only in block pointers format.
The old IPL programs (CCW-type IPL) use program table based on the
old format.

All program tables are packed to the same bootmap file. Their
order and logical offsets in the file are not significant (not
used by anyone).

The picture below shows which program table is used for IPL of
specified type from disk of specified type. Here "0" and "1" are
identifiers of program tables based on the old and new block
pointers format respectively. E.g. program table "0" is used for
CCW-type IPL from ECKD DASD. LD-IPL from DASD FBA is unsupported
(respectively, only one program table "0" is used), etc.

                            CCW-IPL   LD-IPL

 SCSI                          X        0
 DASD FBA                      0        X
 ECKD DASD LDL                 0        X
 ECKD DASD CDL                 0        1

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Eduard Shishkin
cf5f373142 zipl: Rename component_type enum
Rename component_type enum from COMPONENT_* to COMPONENT_TYPE_*

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Eduard Shishkin
e09c675b70 libvtoc: Introduce is_vol1() check
Introduce is_vol1() in vtoc.h and update the user in libzds.c

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Eduard Shishkin
6bd93f475c Clean up of libdasd
Remove standalone IOCTLs definitions and use sys/mount.h instead

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00
Stefan Haberland
3f12bdf4c7 tunedasd: add copy_pair swap capability
Add an option to tunedasd to trigger a copy pair swap using the appropriate
ioctl for DASD devices.

      -s, --copy-pair-swap COPY_PAIR

This command requires a comma separated pair of primary,secondary to be
specified. In case of success the old secondary will become the new primary
device and the old primary will become a secondary device.

Example:

tunedasd /dev/dasda -s 0.0.9700,0.0.9740

This will set the old secondary device 0.0.9740 as the new primary.
The old primary device 0.0.9700 will automatically become a secondary
device.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Stefan Haberland
3aa7f6e298 libdasd: fix ioctl macro to return also positive return codes
In case of an error the ioctl macro only returns errno to the calling
function.
This misses positive returncodes from ioctls.
Change the macro to also return positive return codes.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Stefan Haberland
4e28047eb4 tunedasd: move tunedasd ioctls to libdasd
Move all DASD IOCTLs to libdasd and adapt all affected
users accordingly.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Stefan Haberland
f654b971d0 zdev: add copy_pair attribute for DASD devices
The DASD device driver has a new attribute copy_pair to make storage
server copy pairs known to the driver.
Add this attribute to zdev.

Usage example:

Add two copy pairs 1000,2000 and 1000,3000 to a DASD device 1000
$ chzdev dasd 1000 copy_pairs=1000,2000 copy_pairs=1000,3000

or

$ chzdev dasd 1000 copy_pairs="1000,2000 1000,3000"

To add a third copy pair later on:
$ chzdev dasd 1000 copy_pairs=1000,4000

To remove all copy pairs from the device 1000:
$ chzdev dasd 1000 -r copy_pairs

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Stefan Haberland
e742d1c9ae zdev: correctly handle multiple values for CCW devices
Correctly create multiple lines in the udev rule for CCW device attributes
with multi bit set that contain multiple values.

Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Stefan Haberland
803b87e324 zconf/lsdasd: add Copy Pair output option
Add an option -P|--copy-pairs to show all DASD devices with copy
relations set up in the system and their roles.

The output looks like:

    # ./s390-tools/zconf/lsdasd -h
    [...]
            -P|--copy-pairs
	             Print information about copy pairs.

     # ./s390-tools/zconf/lsdasd -P
     Bus-ID    Role       Name      Paired devices
     ================================================================================
     0.0.9700  primary    dasdd     0.0.9740,0.0.9743,0.0.9744,0.0.9745
     0.0.9740  secondary            0.0.9700
     0.0.9701  primary    dasdf     0.0.9741
     0.0.9741  secondary            0.0.9701
     0.0.9702  primary    dasdh     0.0.9742
     0.0.9742  secondary            0.0.9702

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Stefan Haberland
5107a7be16 zconf/lsdasd: fix Copy Pair related output
Fix the default output for copy pair secondary devices to not show
a faulty blockdevice entry and major:minor combination.

The new output looks like:

    # lsdasd
    Bus-ID    Status    Name      Device  Type         BlkSz  Size      Blocks
    ================================================================================
    0.0.9740  secondary                   ECKD
    0.0.9741  secondary                   ECKD
    0.0.9742  secondary                   ECKD
    0.0.e964  active    dasda     94:0    ECKD         4096   21129MB   5409180
    0.0.e967  active    dasdb     94:4    ECKD         4096   21129MB   5409180
    0.0.9330  active    dasdc     94:8    ECKD         4096   782MB     200340
    0.0.9700  active    dasdd     94:12   ECKD         4096   782MB     200340
    0.0.9701  active    dasdf     94:20   ECKD         4096   782MB     200340
    0.0.9702  active    dasdh     94:28   ECKD         4096   782MB     200340

Also add copy_pairs to extended output:

     # lsdasd -l 9700
     0.0.9700/dasdd/94:12
       status:                               active
       type:                                 ECKD
       blksz:                                4096
       size:                                 782MB
       blocks:                               200340
       extent_size:                          1113
       logical_capacity:                     1113
       space_allocated:                      1113
       use_diag:                             0
       readonly:                             0
       eer_enabled:                          0
       erplog:                               0
       hpf:                                  1
       uid:                                  IBM.750000000ABT31.9700.00
       fc_security:                          Unsupported
       paths_installed:                      38 39 3a 3b
       paths_in_use:                         38 39 3a 3b
       paths_non_preferred:
       paths_invalid_cabling:
       paths_cuir_quiesced:
       paths_invalid_hpf_characteristics:
       paths_error_threshold_exceeded:
       copy_pairs:                           0.0.9700,0.0.9740 0.0.9700,0.0.9743 0.0.9700,0.0.9744 0.0.9700,0.0.9745

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-15 10:24:42 +01:00
Jan Höppner
1178291686 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-09 17:11:48 +01:00
57 changed files with 2067 additions and 1012 deletions

3
.gitignore vendored
View File

@@ -95,6 +95,9 @@ zdev/src/chzdev_usage.c
zdev/src/lszdev
zdev/src/lszdev_usage.c
zdsfs/zdsfs
zdump/.check_dep_fuse
zdump/.check_dep_zgetdump
zdump/.detect_openssl.dep.c
zdump/zgetdump
zfcpdump/10-zfcpdump.install
zfcpdump/cpioinit

View File

@@ -21,6 +21,7 @@ List of all individuals having contributed content to s390-tools
- Colin Walters
- Dan Horak
- Dan Horák
- Daniel S. Haischt
- Despina Papadopoulou
- Dimitri John Ledkov
- Eberhard Pasch

View File

@@ -1,6 +1,20 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.25.0 (2022-12-08)__
For Linux kernel version: 6.1
Changes of existing tools:
- ap_tools: Use new mdevctl installation location
- lsdasd/tunedasd/zdev: Add support to handle copy pair relations presented by the DASD driver
- zdev: Add --shell command line switch to generate output suitable for shell environments
- zipl: Add List-Directed IPL from ECKD DASD to support secure boot
Bug Fixes:
- ipl_tools: Fix chreipl node for NVMes with CONFIG_NVME_MULTIPATH
- libdasd: Fix bug that prevented positive ioctl return codes
* __v2.24.0 (2022-11-09)__
For Linux kernel version: 6.0

View File

@@ -1,8 +1,11 @@
include ../common.mak
MDEVCTL_DIR = /etc/mdevctl.d/
MDEVCTL_SCRIPTS = /etc/mdevctl.d/scripts.d/
MDEVCTL_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
MDEVCTL_DIR = /usr/lib/mdevctl/
MDEVCTL_SCRIPTS = /usr/lib/mdevctl/scripts.d/
MDEVCTL_CALLOUTS = /usr/lib/mdevctl/scripts.d/callouts/
MDEVCTL_DEP_DIR = /etc/mdevctl.d/
MDEVCTL_DEP_SCRIPTS = /etc/mdevctl.d/scripts.d/
MDEVCTL_DEP_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
libs = $(rootdir)/libap/libap.a \
$(rootdir)/libutil/libutil.a
@@ -32,6 +35,17 @@ install: all
fi; \
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check \
$(DESTDIR)$(MDEVCTL_CALLOUTS)
@if [ ! -d $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS) ]; then \
mkdir -p $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_DIR); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_SCRIPTS); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_DIR); \
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_SCRIPTS); \
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
fi; \
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check.sh \
$(DESTDIR)$(MDEVCTL_DEP_CALLOUTS)
endif
clean:

15
ap_tools/ap-check.sh Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
#
# ap-check.sh - Wrapper script for 'ap-check' binary
#
# mdevctl has deprecated the /etc/mdevctl.d/scripts.d/callouts/ location in
# newer releases. This wrapper ensures that mdevctl 1.2.0 and older can
# still access 'ap-check' for now, and will be removed at a later time.
#
# Copyright 2022 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.
#
[ -e /usr/lib/mdevctl/scripts.d/callouts/ap-check ] && /usr/lib/mdevctl/scripts.d/callouts/ap-check "$@"

View File

@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 24
RELEASE = 25
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -60,8 +60,10 @@ endef
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
$(eval $(call cmd_define, LINK," LINK ",$(CC)))
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CXX)))
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
$(eval $(call cmd_define, NM," NM ",$(CROSS_COMPILE)nm))
@@ -81,8 +83,6 @@ CHECKTOOL = $(call echocmd," CHECK ",/$@)$(CHECK_SILENT)
SKIP = echo " SKIP $(call reldir) due to"
INSTALL = install
LINK = $(CC)
LINKXX = $(CXX)
CP = cp
ifneq ("${V}","1")
MAKEFLAGS += --quiet

View File

@@ -57,11 +57,41 @@ struct linear_blockptr {
uint8_t reserved[4];
} __packed;
/*
* Format of a boot record on ECKD DASD for List-Directed IPL
*/
struct eckd_boot_record {
uint8_t magic[4];
uint32_t version_id;
uint8_t unused[8];
uint8_t program_table_pointer[16];
uint8_t reserved[478];
uint16_t os_id;
} __packed;
/*
* Layout of block pointer for cylinder/head/sector devices
* e.g. ECKD
*/
struct eckd_blockptr {
enum blkptr_format_id {
/*
* this is the old format which serves only CCW-type IPL,
* and doesn't fit List-Directed IPL. Still supported for
* compatibility reasons.
*/
LEGACY_BLKPTR_FORMAT_ID,
/*
* this is the "new" format which serves only List-Directed IPL,
* but is also suitable for CCW-type IPL.
*/
BLKPTR_FORMAT_ID
};
/*
* Block pointers format identified as LEGACY_BLKPTR_FORMAT_ID.
*/
struct eckd_blockptr_legacy {
uint16_t cyl;
uint16_t head;
uint8_t sec;
@@ -70,10 +100,22 @@ struct eckd_blockptr {
uint8_t reserved[8];
} __packed;
/*
* Block pointers format identified as BLKPTR_FORMAT_ID.
*/
struct eckd_blockptr {
uint32_t cyl;
uint8_t head;
uint8_t sec;
uint8_t reserved1[4];
uint16_t blockct;
uint8_t reserved2[4];
} __packed;
typedef enum {
COMPONENT_EXECUTE = 0x01,
COMPONENT_LOAD = 0x02,
COMPONENT_SIGNATURE = 0x03
COMPONENT_TYPE_EXECUTE = 0x01,
COMPONENT_TYPE_LOAD = 0x02,
COMPONENT_TYPE_SIGNATURE = 0x03
} component_type;
typedef enum {
@@ -117,7 +159,8 @@ struct scsi_dump_sb {
uint64_t csum_offset;
uint64_t csum_size;
uint64_t csum;
} __packed;
};
STATIC_ASSERT(sizeof(struct scsi_dump_sb) == 72);
#define SCSI_DUMP_SB_MAGIC 0x5a46435044554d50ULL /* ZFCPDUMP */
/* To avoid a csum entry of 0 a seed is used */
@@ -153,6 +196,7 @@ struct boot_info_bp_dump {
struct boot_info_bp_ipl {
union {
struct eckd_blockptr_legacy eckd_legacy;
struct eckd_blockptr eckd;
struct linear_blockptr lin;
} bm_ptr;

View File

@@ -20,8 +20,8 @@
#include <stdio.h>
#include <sys/ioctl.h>
/* A bus id of a DASD is 8 characters long. E.g. 0.0.4711 */
#define DASD_BUS_ID_SIZE 9
/* the definition of a BUSID in the DASD driver is 20 */
#define DASD_BUS_ID_SIZE 20
typedef struct dasd_information2_t {
unsigned int devno; /* S/390 devno */
@@ -187,6 +187,68 @@ typedef struct format_check_t {
#define DASD_FMT_ERR_RECORD_ID 4
#define DASD_FMT_ERR_KEY_LENGTH 5
/*
* struct profile_info_t
* holds the profiling information
*/
typedef struct dasd_profile_info_t {
unsigned int dasd_io_reqs; /* # of requests processed at all */
unsigned int dasd_io_sects; /* # of sectors processed at all */
unsigned int dasd_io_secs[32]; /* request's sizes */
unsigned int dasd_io_times[32]; /* requests's times */
unsigned int dasd_io_timps[32]; /* requests's times per sector */
unsigned int dasd_io_time1[32]; /* time from build to start */
unsigned int dasd_io_time2[32]; /* time from start to irq */
unsigned int dasd_io_time2ps[32]; /* time from start to irq */
unsigned int dasd_io_time3[32]; /* time from irq to end */
unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */
} dasd_profile_info_t;
/*
* struct attrib_data_t
* represents the operation (cache) bits for the device.
* Used in DE to influence caching of the DASD.
*/
typedef struct attrib_data_t {
unsigned char operation : 3; /* cache operation mode */
unsigned char reserved : 5;
unsigned short nr_cyl; /* no of cyliners for read ahaed */
unsigned char reserved2[29]; /* for future use */
} __attribute__((packed)) attrib_data_t;
/* definition of operation (cache) bits within attributes of DE */
#define DASD_NORMAL_CACHE 0x0
#define DASD_BYPASS_CACHE 0x1
#define DASD_INHIBIT_LOAD 0x2
#define DASD_SEQ_ACCESS 0x3
#define DASD_SEQ_PRESTAGE 0x4
#define DASD_REC_ACCESS 0x5
/*
* Data returned by Sense Path Group ID (SNID)
*/
struct dasd_snid_data {
struct {
__u8 group : 2;
__u8 reserve : 2;
__u8 mode : 1;
__u8 res : 3;
} __attribute__((packed)) path_state;
__u8 pgid[11];
} __attribute__((packed));
struct dasd_snid_ioctl_data {
struct dasd_snid_data data;
__u8 path_mask;
} __attribute__((packed));
struct dasd_copypair_swap_data {
char primary[DASD_BUS_ID_SIZE]; /* BUSID of primary */
char secondary[DASD_BUS_ID_SIZE]; /* BUSID of secondary */
/* Reserved for future updates. */
char reserved[64];
};
#ifndef __linux__
/* definition from hdreg.h */
struct hd_geometry {
@@ -207,27 +269,29 @@ struct hd_geometry {
#define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2)
/* Release the device for the current LPAR */
#define BIODASDRLSE _IO(DASD_IOCTL_LETTER, 3)
/* Unconditional reserve the device for the current LPAR */
#define BIODASDSLCK _IO(DASD_IOCTL_LETTER, 4)
/* reset profiling information of a device */
#define BIODASDPRRST _IO(DASD_IOCTL_LETTER, 5)
/* retrieve profiling information of a device */
#define BIODASDPRRD _IOR(DASD_IOCTL_LETTER, 2, dasd_profile_info_t)
/* Get information on a dasd device (enhanced) */
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
/* Get Attributes (cache operations) */
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER, 5, attrib_data_t)
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER, 1, format_data_t)
/* Set Attributes (cache operations) */
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER, 2, attrib_data_t)
/* Release Allocated Space */
#define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t)
/* Swap copy pair */
#define BIODASDPPRCSWAP _IOW(DASD_IOCTL_LETTER, 4, struct dasd_copypair_swap_data)
/* Get Sense Path Group ID (SNID) data */
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
/* Check device format according to format_data_t */
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
/********************************************************************************
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h)
*******************************************************************************/
/* get read-only status (0 = read_write) */
#define BLKROGET _IO(0x12, 94)
/* re-read partition table */
#define BLKRRPART _IO(0x12, 95)
/* get block device sector size */
#define BLKSSZGET _IO(0x12, 104)
/* return device size in bytes (u64 *arg) */
#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
#ifndef __linux__ /* from <linux/hdreg.h> */
#define HDIO_GETGEO 0x0301
#endif
@@ -245,5 +309,12 @@ int dasd_is_ro(const char *device, bool *ro);
int dasd_reread_partition_table(const char *device, int ntries);
int dasd_disk_reserve(const char *device);
int dasd_disk_release(const char *device);
int dasd_slock(const char *device);
int dasd_get_cache(const char *device, attrib_data_t *attrib_data);
int dasd_set_cache(const char *device, attrib_data_t *attrib_data);
int dasd_query_reserve(const char *device);
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info);
int dasd_reset_profile(const char *device);
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data);
#endif /* LIB_DASD_BASE_H */

View File

@@ -97,6 +97,24 @@ typedef struct volume_label
unsigned long long formatted_blocks; /* valid when ldl_version >= f2 */
} __attribute__ ((packed)) volume_label_t;
/**
* This represents a volume label specific for OS/390 compatible disk layout
*/
struct vol_label_cdl {
char volkey[4];
char vollbl[4];
char opaq[70];
cchhb_t br; /* boot record address */
char stdv[1]; /* standard version ID */
} __attribute__ ((packed));
static inline int is_vol1(char *this)
{
char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00} /* "VOL1" in EBCDIC */;
return !strncmp(this, vol1, 4);
}
typedef struct extent
{
u_int8_t typeind; /* extent type indicator */

View File

@@ -75,6 +75,7 @@ extern void fcp_busid_get(const char *device, char *devno);
* NVME
*/
#define FID_MAX_LEN 11 /* 8 characters + 0x + null */
#define NVME_DEV_MAX_LEN 15 /* "nvme" + u32 in decimal + null */
#define NVME_PATH_MAX (PATH_MAX + NAME_MAX + 1)
extern void nvme_fid_get(const char *device, char *fid);

View File

@@ -18,15 +18,31 @@
#include "lib/util_file.h"
#include "ipl_tools.h"
static void nvme_dev_from_bdev(char *dev_name)
{
char *delim = strrchr(dev_name, 'n');
if (delim)
*delim = 0;
}
/*
* Return the fid of a device
*/
void nvme_fid_get(const char *device, char *fid)
{
char path[PATH_MAX], buf[FID_MAX_LEN];
char nvme_dev[NVME_DEV_MAX_LEN];
snprintf(path, PATH_MAX, "/sys/block/%s/device/device/function_id",
device);
/*
* An NVMe may present multiple namespaces and thus block devices, even
* before partitioning, so we need the nvme<NUM> part of the block
* device name to get to the PCI function ID.
*/
util_strlcpy(nvme_dev, device, sizeof(nvme_dev));
nvme_dev_from_bdev(nvme_dev);
snprintf(path, PATH_MAX, "/sys/class/nvme/%s/device/function_id", nvme_dev);
if (util_file_read_line(buf, FID_MAX_LEN, path))
ERR_EXIT_ERRNO("Could not read from \"%s\"", path);

View File

@@ -15,7 +15,9 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include "lib/dasd_base.h"
@@ -27,11 +29,13 @@
#define RUN_IOCTL(fd, req, argp) \
do { \
if (ioctl(fd, req, argp) != 0) { \
int err = errno; \
if (err != EBADF) \
int rc = ioctl(fd, req, argp); \
if (rc != 0) { \
if (rc == -1) \
rc = errno; \
if (rc != EBADF) \
dasd_close_device(fd); \
return err; \
return rc; \
} \
} while (0)
@@ -321,3 +325,159 @@ int dasd_disk_release(const char *device)
return 0;
}
/*
* Unconditionally reserve DASD disk
*
* An existing reserve lock is lifted (steal lock) and the device
* is reserved.
*
* @param[in] device node device node's name
*
* @retval 0 in case of success
* @retval errno in case of failure
*/
int dasd_slock(const char *device)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDSLCK, NULL);
dasd_close_device(fd);
return 0;
}
/*
* Get the caching algorithm used for the channel programs of this device.
*
* @param[in] device node device node's name
* @param[out] attrib_data pointer to dasd attrib data with:
* 'cache' is the caching mode
* 'no_cyl' the number of cylinders to be cached.
*
* @retval 0 in case of success
* @retval errno in case of failure
*/
int dasd_get_cache(const char *device, attrib_data_t *attrib_data)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDGATTR, attrib_data);
dasd_close_device(fd);
return 0;
}
/*
* Set the caching algorithm used for the channel programs of this device.
*
* @param[in] device node device node's name
* @param[in] attrib_data pointer to dasd attrib data with:
* 'cache' is the caching mode
* 'no_cyl' the number of cylinders to be cached.
*
* @retval 0 in case of success
* @retval errno in case of failure
*/
int dasd_set_cache(const char *device, attrib_data_t *attrib_data)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDSATTR, attrib_data);
dasd_close_device(fd);
return 0;
}
/*
* Get reserve status of device.
*
* @param[in] device node device node's name
*
* @retval errno in case of failure
* @retval 0 unreserved
* @retval 1 implicit reserved
* @retval 2 other reservation
* @retval 3 reserved
*/
int dasd_query_reserve(const char *device)
{
struct dasd_snid_ioctl_data snid = { 0 };
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDSNID, &snid);
dasd_close_device(fd);
return snid.data.path_state.reserve;
}
/*
* Get and print the profiling info of the device.
*
* @param[in] device node device node's name
* @param[in] dasd_profile_info pointer to dasd profile info
*
* @retval 0 in case of success
* @retval errno in case of failure
*/
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDPRRD, dasd_profile_info);
dasd_close_device(fd);
return 0;
}
/*
* Reset the profiling counters of the device.
*
* @param[in] device node device node's name
*
* @retval 0 in case of success
* @retval errno in case of failure
*/
int dasd_reset_profile(const char *device)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDPRRST, NULL);
dasd_close_device(fd);
return 0;
}
/*
* Initiate the swap of a copy pairs primary,secondary relation.
* The old secondary will become the new primary and vice versa.
*
* @param[in] device node device node's name
* @param[in] copy_pair data pointer to dasd copypair data with:
* 'primary' old primary, becoming secondary
* 'secondary' old secondary, becoming primary.
*
* @retval errno in case of failure
* @retval 0 in case of success
* @retval 1 swap data invalid
* @retval 2 no active device found
* @retval 3 wrong primary specified
* @retval 4 secondary device not found
* @retval 5 swap already running
*/
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDPPRCSWAP, data);
dasd_close_device(fd);
return 0;
}

View File

@@ -18,6 +18,7 @@
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "lib/util_libc.h"
#include "lib/util_lockfile.h"

View File

@@ -1419,7 +1419,6 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc)
volume_label_t *vlabel = NULL;
char *trackdata = NULL;
char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00}; /* "VOL1" in EBCDIC */
errorlog_clear(dasd->log);
@@ -1431,8 +1430,7 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc)
goto cleanup;
}
/* verify that we have a proper VOL1 label */
if (strncmp(vlabel->volkey, vol1, 4) ||
strncmp(vlabel->vollbl, vol1, 4)) {
if (!is_vol1(vlabel->volkey) || !is_vol1(vlabel->vollbl)) {
rc = EINVAL;
errorlog_add_message(
&dasd->log, NULL, rc,

View File

@@ -1,5 +1,7 @@
include ../common.mak
ALL_CFLAGS += -Wno-address-of-packed-member
all: mon_fsstatd mon_procd
mon_fsstatd: mon_fsstatd.o

View File

@@ -24,7 +24,7 @@ Prints usage information, then exits.
.B
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
Specify one or more host key documents. At least one is required.
Specify this option multiple times to enable the image to run on more than one host.
Specify this option multiple times to create an attestation request control block that is usable on multiple hosts.
.TP
.B
\fB-C\fP, \fB--cert\fP=\fBFILE\fP

View File

@@ -14,6 +14,8 @@ set -o pipefail
set -o nounset
set -e
XDUMP='od -A x -t x2z -v'
usage() {
cat <<-EOF
Usage: $(basename "$0") FILE
@@ -33,16 +35,16 @@ function check_is_pvattest_binary() {
exit 1
fi
xxd -l 16 "${input}" | grep -q pvattest ||
${XDUMP} --read-bytes 16 -- "${input}" 2>/dev/null | grep -q pvattest ||
{ echo "ERROR: ${input} does not contain a pvattest binary output." >&2 && exit 1; }
size=$(xxd -s 12 -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
size=$(${XDUMP} --skip-bytes 12 --read-bytes 4 -- "${input}" 2>/dev/null | awk 'NR==1 {print "0x" $2 $3}')
if [ $((size)) -lt 64 ]; then
echo "ERROR: ${input} does not contain a pvattest binary output." >&2
exit 1
fi
version=$(xxd -s 8 -l 4 "$input")
version=$(${XDUMP} --skip-bytes 8 --read-bytes 4 -- "$input" 2>/dev/null)
echo "$version" | grep -q "0000 0100" ||
{ echo -n "WARNING: unknown hdr version " >&2 &&
echo "$version" | awk '{print "0x" $2 $3}'>&2 ; }
@@ -55,24 +57,28 @@ function print_entry() {
local size
local off
size=$(xxd -s $((file_off)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
off=$(xxd -s $((file_off + 4)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
size=$(${XDUMP} --skip-bytes $((file_off)) --read-bytes 4 -- "${input}" 2>/dev/null |
awk 'NR==1 {print "0x" $2 $3}')
off=$(${XDUMP} --skip-bytes $((file_off + 4)) --read-bytes 4 -- "${input}" 2>/dev/null |
awk 'NR==1 {print "0x" $2 $3}')
if [[ $size != "0x00000000" ]] || [[ $off != "0x00000000" ]]; then
echo "${text}:"
xxd -s $((off)) -l $((size)) -p "${input}"
od -A n -w$((size)) -t x8 --skip-bytes $((off)) --read-bytes $((size)) -- "${input}" 2>/dev/null |\
sed -e 's/\s//g'
fi
}
function require_command() {
local cmd="$1"
command -v "$cmd" >/dev/null 2>&1 || { echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
command -v "$cmd" >/dev/null 2>&1 || \
{ echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
}
require_command xxd
require_command awk
require_command wc
require_command od
if [ $# -eq 0 ]; then
echo "ERROR: Input not set. Use '$(basename "$0") [FILE]' to specify the Input file" >&2

View File

@@ -14,7 +14,9 @@ set -o pipefail
set -o nounset
set -e
def_output="sehdr.bin"
XDUMP='od -A x -t x2z -v'
def_output='sehdr.bin'
def_skip=0x14
def_len=0x4
@@ -37,11 +39,22 @@ function check_file() {
function check_hdr_ver() {
local hdr_start="$1"
local input="$2"
xxd -s $((hdr_start + 8)) -l 4 "$input" | grep -q "000 0100" ||
${XDUMP} --skip-bytes $((hdr_start + 8)) --read-bytes 4 -- "$input" 2>/dev/null | grep -q "000 0100" ||
{ echo -n "WARNING: unknown hdr version " &&
xxd -s $((hdr_start + 8)) -l 4 "$input" | awk '{print "0x" $2 $3}'; }
${XDUMP} --skip-bytes $((hdr_start + 8)) --read_bytes 4 -- "$input" 2>/dev/null | awk '{print "0x" $2 $3}'; }
}
function require_command() {
local cmd="$1"
command -v "$cmd" >/dev/null 2>&1 || \
{ echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
}
require_command od
require_command awk
require_command grep
output=${def_output}
parsed_skip=${def_skip}
parsed_len=${def_len}
@@ -77,13 +90,15 @@ if [ $# -eq 0 ]; then
fi
check_file "$input"
hdr_start=$(xxd -s $((skip)) -l $((len)) "${input}" | grep IBMSecEx || { echo ERROR: "${input} does not contain an SE header." >&2 && exit 1; })
hdr_start=$(${XDUMP} --skip-bytes $((skip)) --read-bytes $((len)) -- "${input}" 2>/dev/null | grep IBMSecEx ||
{ echo ERROR: "${input} does not contain an SE header." >&2 && exit 1; })
hdr_start=$(echo "${hdr_start}" | awk '{print "0x" $1}' | cut -c 1-10)
echo "SE header found at offset ${hdr_start}"
check_hdr_ver "$hdr_start" "$input"
size=$(xxd -s $((hdr_start + 12)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
size=$(${XDUMP} --skip-bytes $((hdr_start + 12)) --read-bytes 4 -- "${input}" 2>/dev/null |
awk 'NR==1 {print "0x" $2 $3}')
dd if="${input}" of="${output}" bs=1 count=$((size)) skip=$((hdr_start)) status=none
echo "SE header written to '${output}' ($((size)) bytes)"

View File

@@ -1192,6 +1192,10 @@ post_processing() {
rm -f "${file_name}"
fi
done
echo "log work directory state after post processing:"
echo "du summary: $(du -ks ${WORKPATH})"
df -k ${WORKPATH}
}
########################################

View File

@@ -31,6 +31,7 @@ int disk_query_reserve_status(char* device);
int disk_profile (char* device, char* prof_item);
int disk_reset_prof(char *device);
int disk_reset_chpid(char *device, char *chpid);
int disk_copy_swap(char *device, char *copy_pair);
#endif /* not DISK_H */

View File

@@ -174,6 +174,14 @@ Reset all channel paths of the selected device. The channel paths
might be suspended due to high IFCC error rates or a High Performance
FICON failure. Use this option to resume considering all defined
channel paths for I/O.
.TP
.BR "\-s" " or " "\-\-copy\-pair\-swap <copy_pair>"
Swap the copy roles of the specified copy pair. The <copy_pair> has to
be a comma separated pair of \fBPRIMARY,SECONDARY\fR where
\fBPRIMARY\fR is the old primary device that will become a secondary
automatically. The old \fBSECONDARY\fR device will become the new
primary device. Both devices have to be online for this operation to
succeed.
.\"
.\".TP
.\".BR "\-o" " or " "\-\-online"
@@ -197,6 +205,12 @@ channel paths for I/O.
.br
tunedasd -p 45 /dev/dasdc
.br
4. Scenario: Swap copy pair 0.0.9700 and 0.0.9740
.br
tunedasd -s 0.0.9700,0.0.9740 /dev/dasdc
.br
.SH "SEE ALSO"
.BR dasdview (8),

View File

@@ -19,98 +19,13 @@
#include <sys/types.h>
#include <unistd.h>
#include "lib/dasd_base.h"
#include "lib/dasd_sys.h"
#include "lib/util_libc.h"
#include "disk.h"
#include "tunedasd.h"
#define BUS_ID_SIZE 30
/*
* DASD DEFINITIONS (copied from dasd.h)
*/
#define DASD_IOCTL_LETTER 'D'
/*
* struct profile_info_t
* holds the profiling information
*/
typedef struct dasd_profile_info_t {
unsigned int dasd_io_reqs; /* # of requests processed at all */
unsigned int dasd_io_sects; /* # of sectors processed at all */
unsigned int dasd_io_secs[32]; /* request's sizes */
unsigned int dasd_io_times[32]; /* requests's times */
unsigned int dasd_io_timps[32]; /* requests's times per sector */
unsigned int dasd_io_time1[32]; /* time from build to start */
unsigned int dasd_io_time2[32]; /* time from start to irq */
unsigned int dasd_io_time2ps[32]; /*time from start to irq */
unsigned int dasd_io_time3[32]; /* time from irq to end */
unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */
} dasd_profile_info_t;
/*
* struct attrib_data_t
* represents the operation (cache) bits for the device.
* Used in DE to influence caching of the DASD.
*/
typedef struct attrib_data_t {
unsigned char operation:3; /* cache operation mode */
unsigned char reserved:5;
unsigned short nr_cyl; /* no of cyliners for read ahaed */
unsigned char reserved2[29]; /* for future use */
} __attribute__ ((packed)) attrib_data_t;
/* definition of operation (cache) bits within attributes of DE */
#define DASD_NORMAL_CACHE 0x0
#define DASD_BYPASS_CACHE 0x1
#define DASD_INHIBIT_LOAD 0x2
#define DASD_SEQ_ACCESS 0x3
#define DASD_SEQ_PRESTAGE 0x4
#define DASD_REC_ACCESS 0x5
/*
* Data returned by Sense Path Group ID (SNID)
*/
struct dasd_snid_data {
struct {
__u8 group:2;
__u8 reserve:2;
__u8 mode:1;
__u8 res:3;
} __attribute__ ((packed)) path_state;
__u8 pgid[11];
} __attribute__ ((packed));
struct dasd_snid_ioctl_data {
struct dasd_snid_data data;
__u8 path_mask;
} __attribute__ ((packed));
/*
* DASD-IOCTLs (copied from dasd.h)
*/
/* Issue a reserve/release command, rsp. */
#define BIODASDRSRV _IO (DASD_IOCTL_LETTER,2) /* reserve */
#define BIODASDRLSE _IO (DASD_IOCTL_LETTER,3) /* release */
#define BIODASDSLCK _IO (DASD_IOCTL_LETTER,4) /* steal lock */
/* reset profiling information of a device */
#define BIODASDPRRST _IO (DASD_IOCTL_LETTER,5)
/* retrieve profiling information of a device */
#define BIODASDPRRD _IOR (DASD_IOCTL_LETTER,2,dasd_profile_info_t)
/* Get Attributes (cache operations) */
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
/* Set Attributes (cache operations) */
#define BIODASDSATTR _IOW (DASD_IOCTL_LETTER,2,attrib_data_t)
/* Get Sense Path Group ID (SNID) data */
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
/* id definition for profile items */
enum prof_id {
prof_reqs = 0,
@@ -241,48 +156,33 @@ check_prof_item (char* prof_item)
* 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl'
* the number of cylinders to be cached.
*/
int
disk_get_cache (char* device)
int disk_get_cache(char *device)
{
int fd;
attrib_data_t attrib_data;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
int rc;
/* Get the given caching attributes */
if (ioctl (fd, BIODASDGATTR, &attrib_data)) {
error_print ("Could not get cache attributes for device <%s>",
device);
close (fd);
return -1;
}
rc = dasd_get_cache(device, &attrib_data);
if (rc)
return rc;
printf ("%s (%i cyl)\n",
get_cache_name(attrib_data.operation),
attrib_data.nr_cyl);
close (fd);
return 0;
}
/*
* Set the caching algorithm used for the channel programs of this device.
* 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl'
* the number of cylinders to be cached.
*/
int
disk_set_cache (char* device, char* cache, char* no_cyl)
int disk_set_cache(char *device, char *cache, char *no_cyl)
{
int fd;
attrib_data_t attrib_data;
/* get caching mode and # cylinders */
int rc;
/* get caching mode and # cylinders */
attrib_data.operation = check_cache (cache);
attrib_data.nr_cyl = check_no_cyl (no_cyl);
@@ -292,52 +192,34 @@ disk_set_cache (char* device, char* cache, char* no_cyl)
attrib_data.nr_cyl);
}
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
/* Set the given caching attributes */
printf ("Setting cache mode for device <%s>...\n", device);
if (ioctl (fd, BIODASDSATTR, &attrib_data)) {
error_print ("Could not set caching for device <%s>", device);
close (fd);
rc = dasd_set_cache(device, &attrib_data);
if (rc) {
error_print("Could not set caching for device <%s>", device);
return -1;
}
printf ("Done.\n");
close (fd);
return 0;
}
/*
* Reserve the device.
*/
int
disk_reserve (char* device)
int disk_reserve(char *device)
{
int fd;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
int rc;
/* Reserve device */
printf ("Reserving device <%s>...\n", device);
if (ioctl (fd, BIODASDRSRV)) {
error_print ("Could not reserve device <%s>", device);
close (fd);
rc = dasd_disk_reserve(device);
if (rc) {
error_print("Could not reserve device <%s>", device);
return -1;
}
printf ("Done.\n");
close (fd);
printf("Done.\n");
return 0;
}
@@ -345,28 +227,18 @@ disk_reserve (char* device)
/*
* Release the device.
*/
int
disk_release (char* device)
int disk_release(char *device)
{
int fd;
int rc;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
/* Release device */
printf ("Releasing device <%s>...\n", device);
if (ioctl (fd, BIODASDRLSE)) {
error_print ("Could not release device <%s>", device);
close (fd);
rc = dasd_disk_release(device);
if (rc) {
error_print("Could not release device <%s>", device);
return -1;
}
printf ("Done.\n");
close (fd);
printf("Done.\n");
return 0;
}
@@ -376,29 +248,19 @@ disk_release (char* device)
* This means to reserve the device even if it was already reserved.
* The current reserve is broken (steal lock).
*/
int
disk_slock (char* device)
int disk_slock(char *device)
{
int fd;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
int rc;
/* Unconditional reserve device */
printf ("Unconditional reserving device <%s>...\n", device);
if (ioctl (fd, BIODASDSLCK)) {
error_print ("Could not unconditional reserve device <%s>",
device);
close (fd);
rc = dasd_slock(device);
if (rc) {
error_print("Could not unconditional reserve device <%s>", device);
return -1;
}
printf ("Done.\n");
close (fd);
return 0;
}
@@ -407,27 +269,16 @@ disk_slock (char* device)
* Uses the Sense Path Group ID (SNID) ioctl to find out if
* a device is reserved to it's path group.
*/
int
disk_query_reserve_status(char* device)
int disk_query_reserve_status(char *device)
{
int fd;
struct dasd_snid_ioctl_data snid;
int rc;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
rc = dasd_query_reserve(device);
if (rc < 0) {
error_print("Could not read reserve status for device <%s>", device);
return -1;
}
snid.path_mask = 0;
/* Release device */
if (ioctl(fd, BIODASDSNID, &snid)) {
error_print("Could not read reserve status"
" for device <%s>", device);
close (fd);
return -1;
}
switch (snid.data.path_state.reserve) {
switch (rc) {
case 0:
printf("none\n");
break;
@@ -441,7 +292,7 @@ disk_query_reserve_status(char* device)
printf("reserved\n");
break;
}
close (fd);
return 0;
}
@@ -615,21 +466,14 @@ static int disk_profile_item(dasd_profile_info_t dasd_profile_info,
/*
* Get and print the profiling info of the device.
*/
int
disk_profile (char* device, char* prof_item)
int disk_profile(char *device, char *prof_item)
{
int fd, rc;
dasd_profile_info_t dasd_profile_info;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
int rc;
/* Get the profile info */
if (ioctl (fd, BIODASDPRRD, &dasd_profile_info)) {
rc = dasd_profile(device, &dasd_profile_info);
if (rc) {
switch (errno) {
case EIO: /* profiling is not active */
error_print ("Profiling (on device <%s>) is not "
@@ -639,7 +483,6 @@ disk_profile (char* device, char* prof_item)
error_print ("Could not get profile info for device "
"<%s>.", device);
}
close (fd);
return -1;
}
/* Check for profile item or summary */
@@ -648,38 +491,26 @@ disk_profile (char* device, char* prof_item)
} else {
rc = disk_profile_item (dasd_profile_info, prof_item);
}
close (fd);
return rc;
}
/*
* Reset the profiling counters of the device.
*/
int
disk_reset_prof (char* device)
int disk_reset_prof(char *device)
{
int fd;
/* Open device file */
fd = open (device, O_RDONLY);
if (fd == -1) {
error_print ("<%s> - %s", device, strerror (errno));
return -1;
}
int rc;
/* reset profile info */
printf ("Resetting profile info for device <%s>...\n", device);
if (ioctl (fd, BIODASDPRRST)) {
error_print ("Could not reset profile info for device <%s>",
device);
close (fd);
rc = dasd_reset_profile(device);
if (rc) {
error_print("Could not reset profile info for device <%s>", device);
return -1;
}
printf ("Done.\n");
close (fd);
return 0;
}
@@ -717,3 +548,50 @@ int disk_reset_chpid(char *device, char *chpid)
return -1;
}
int disk_copy_swap(char *device, char *copy_pair)
{
struct dasd_copypair_swap_data data = { 0 };
char *primary, *secondary;
int rc = 0;
primary = strtok(copy_pair, ",");
secondary = strtok(NULL, ",");
if (!primary || !secondary) {
error_print("%s: Error parsing Copy Pair %s", device, copy_pair);
return -1;
}
util_strlcpy(data.primary, primary, DASD_BUS_ID_SIZE);
util_strlcpy(data.secondary, secondary, DASD_BUS_ID_SIZE);
printf("Swapping copy pair %s %s on device <%s>...\n", primary, secondary, device);
rc = dasd_copy_swap(device, &data);
switch (rc) {
case 0:
printf("Done.\n");
return 0;
case 1:
error_print("Swap data invalid");
break;
case 2:
error_print("No active device found");
break;
case 3:
error_print("Wrong primary device specified");
break;
case 4:
error_print("Secondary device not found");
break;
case 5:
error_print("Swap already running");
break;
default:
error_print("Swap not successful rc %d", rc);
break;
}
return -1;
}

View File

@@ -119,12 +119,17 @@ static struct util_opt opt_vec[] = {
.desc = "Reset all channel paths of a device",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "copy-pair-swap", required_argument, NULL, 's' },
.argument = "COPY_PAIR",
.desc = "Swap a specified, comma separated copy pair.",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#define CMD_KEYWORD_NUM 16
#define CMD_KEYWORD_NUM 17
#define DEVICES_NUM 256
enum cmd_keyword_id {
@@ -144,6 +149,7 @@ enum cmd_keyword_id {
cmd_keyword_path_all,
cmd_keyword_enable_stats,
cmd_keyword_disable_stats,
cmd_keyword_copy_swap,
};
@@ -167,7 +173,8 @@ static const struct {
{ "path_reset", cmd_keyword_path },
{ "path_reset_all", cmd_keyword_path_all },
{ "enable-stats", cmd_keyword_enable_stats },
{ "disable-stats", cmd_keyword_disable_stats }
{ "disable-stats", cmd_keyword_disable_stats },
{ "copy-swap", cmd_keyword_copy_swap },
};
@@ -180,26 +187,27 @@ enum cmd_key_state {
/* Determines which combination of keywords are valid */
static enum cmd_key_state cmd_key_table[CMD_KEYWORD_NUM][CMD_KEYWORD_NUM] = {
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path
* ion cach e yl rve ase k ile _ite t_pr y_re _all
* e m of serv
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path enab disa copy
* ion cach e yl rve ase k ile _ite t_pr y_re _all le-s ble- -swa
* e m of serv tats stat p
*/
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv },
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv },
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv },
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv },
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv, inv },
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv, inv },
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv, inv },
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv },
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
/* copy-swap */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
};
struct parameter {
@@ -439,7 +447,9 @@ static int get_command_line(int argc, char *argv[], struct command_line *line)
rc = store_option (&cmdline, cmd_keyword_query_reserve,
optarg);
break;
case 's':
rc = store_option(&cmdline, cmd_keyword_copy_swap, optarg);
break;
case -1:
/* End of options string - start of devices list */
cmdline.device_id = optind;
@@ -508,6 +518,9 @@ static int do_command(char *device, struct command_line cmdline)
case cmd_keyword_path_all:
rc = disk_reset_chpid(device, NULL);
break;
case cmd_keyword_copy_swap:
rc = disk_copy_swap(device, cmdline.parm[cmd_keyword_copy_swap].data);
break;
default:
error_print ("Unknown command '%s' specified",
get_keyword_name (i));

View File

@@ -35,6 +35,8 @@ function PrintUsage() {
Print extended information about DASDs.
-H|--host-access-list
Print information about hosts accessing DASDs.
-P|--copy-pairs
Print information about copy pairs.
-v|--verbose
For compatibility/future use. Currently ignored.
--version
@@ -146,6 +148,62 @@ function findDASDDebugfsDirectorie() {
fi
}
#------------------------------------------------------------------------------
# The blockpath can usually be found over the DEVPATH
# In case of a swapped Copy Pair device the blockdev is likely associated
# with one of the secondary devices
# this function checks if the blockdev is associated with the primary device
# and if not search for it in the secondary device list
#------------------------------------------------------------------------------
function setCorrectBlockPath() {
local DRIVERECKD="$SYSFSDIR/bus/ccw/drivers/dasd-eckd/"
local DRIVERFBA="$SYSFSDIR/bus/ccw/drivers/dasd-fba/"
local SEARCHDIRS=
local SEARCHLIST=
if [[ "$COPYROLE" == "none" ]] || [[ -d "$DEVPATH/block" ]]; then
BLOCKPATH="$DEVPATH"/block/dasd*
return
fi
if [[ -d "$DRIVERECKD" ]]; then
SEARCHDIRS="$DRIVERECKD"
fi
if [[ -d "$DRIVERFBA" ]]; then
SEARCHDIRS="$SEARCHDIRS $DRIVERFBA"
fi
SEARCHLIST=$(echo $SECONDARY_LIST | sed 's/,/ /g')
for SEARCHDEV in $SEARCHLIST
do
if [[ -n "$SEARCHDIRS" ]]; then
PRIM_DEVPATH=$(find $SEARCHDIRS -type l -name $SEARCHDEV \
-printf "%h/%l\n" 2> /dev/null)
if [[ -d "$PRIM_DEVPATH/block" ]]; then
break
fi
else
# The above paths may become invalid in the future, so we keep the
# following query as backup:
PRIM_DEVPATH=$(find "$SYSFSDIR/devices" -type l -name $SEARCHDEV \
"driver" -lname "*/dasd*" -printf "%h\n" \
2> /dev/null)
fi
done
BLOCKPATH="$PRIM_DEVPATH"/block/dasd*
}
#------------------------------------------------------------------------------
# gather Copy Pair related data
#------------------------------------------------------------------------------
function gatherCopyPairData() {
read COPYPAIR 2> /dev/null < $DEVPATH/copy_pair
PRIMARY_UID=`echo $COPYPAIR | cut -d " " -f1 | cut -d "," -f1`
COPYPAIR=`echo "$COPYPAIR" | sed 's/ /,/g' | sed 's/^,//' `
SECONDARY_LIST=`echo ${COPYPAIR//$PRIMARY_UID","/} `
}
#------------------------------------------------------------------------------
# gather device data and call appropriate output function
#------------------------------------------------------------------------------
@@ -165,16 +223,18 @@ function gatherDeviceData() {
read READONLY 2> /dev/null < $DEVPATH/readonly || continue
read DISCIPLINE 2> /dev/null < $DEVPATH/discipline || continue
read ESE 2> /dev/null < $DEVPATH/ese
read COPYROLE 2> /dev/null < $DEVPATH/copy_role
if [[ "$COPYROLE" != "none" ]]; then
gatherCopyPairData
fi
# Block device specific information is only available for
# devices that are online and not a PAV alias
if [[ ! "$ONLINE" == 0 ]] && [[ ! "$ALIAS" == 1 ]]; then
#find device Path to the block device
if [[ -d "$DEVPATH/block" ]]; then
set - "$DEVPATH"/block/dasd*
else
set - "$DEVPATH"/block:dasd*
fi
if [[ ! "$ONLINE" == 0 ]] && [[ ! "$ALIAS" == 1 ]] &&
[[ ! "$COPYROLE" == "secondary" ]]; then
#find device Path to the block device
setCorrectBlockPath
set - $BLOCKPATH
MAJMIN=
MAJOR=
MINOR=
@@ -194,10 +254,12 @@ function gatherDeviceData() {
fi
fi
else
# BLOCKNAME for offline and alias devices will not be
# printed, it's just a key for sorting
# BLOCKNAME for offline, alias and secondary devices
# will not be printed, it's just a key for sorting
if [[ "$ONLINE" == 0 ]]; then
BLOCKNAME=""
elif [[ "$COPYROLE" == "secondary" ]]; then
BLOCKNAME="b"
else
BLOCKNAME="a"
fi
@@ -232,6 +294,8 @@ function gatherDeviceData() {
uid
elif [[ "$OUTPUT" == "host" ]]; then
host
elif [[ "$OUTPUT" == "copy" ]]; then
copy
else
newoutput
fi
@@ -261,6 +325,15 @@ function newoutput()
return
fi
if [[ "$COPYROLE" == "secondary" ]]; then
printf "%s:%s:%-8s secondary %-8s %13s\n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$PRIMARY_BLOCKNAME" \
"$DISCIPLINE"
return
fi
if [[ "$READONLY" == 0 ]]; then
ROSTRING=""
else
@@ -519,10 +592,14 @@ function extended()
"${HPF_PATHS[@]}" \
"${IFCC_PATHS[@]}" ;
return
elif [[ "$ALIAS" == 1 ]]; then
if [[ "$BASEONLY" == "false" ]]; then
ACTIVE="alias"
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
elif [[ "$ALIAS" == 1 ]] || [[ "$COPYROLE" == "secondary" ]]; then
if [[ "$BASEONLY" == "false" ]] || [[ "$COPYROLE" == "secondary" ]]; then
if [[ "$COPYROLE" == "secondary" ]]; then
ACTIVE="secondary"
else
ACTIVE="alias"
fi
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s# copy_pairs:\t\t\t\t%s#\n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$ACTIVE" \
@@ -540,7 +617,8 @@ function extended()
"${CABLE_PATHS[@]}" \
"${CUIR_PATHS[@]}" \
"${HPF_PATHS[@]}" \
"${IFCC_PATHS[@]}" ;
"${IFCC_PATHS[@]}" \
"${COPYPAIR}" ;
fi
return
elif [[ -z "$BLOCKNAME" ]] || [[ -z "$SIZE" ]]; then
@@ -565,7 +643,7 @@ function extended()
DISCIPLINE="${DISCIPLINE} (ESE)"
fi
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s# copy_pairs:\t\t\t\t%s#\n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$BLOCKNAME" \
@@ -593,7 +671,8 @@ function extended()
"${CABLE_PATHS[@]}" \
"${CUIR_PATHS[@]}" \
"${HPF_PATHS[@]}" \
"${IFCC_PATHS[@]}" ;
"${IFCC_PATHS[@]}" \
"${COPYPAIR}" ;
}
function host()
@@ -694,6 +773,41 @@ printf "\n";
rm -f $temp
}
# pad sortkey with given number zeroes
function padSortKey()
{
local LEN=$1
for (( i=0; i<$LEN; i++ ))
do
printf -v SORTKEY "%s0" $SORTKEY
done
}
function copy()
{
if [[ "$COPYROLE" == "none" ]]; then
return
fi
SORTKEYLEN=$((${#PRIMARY_UID}+${#DEV_UID}))
if [[ "$COPYROLE" == "secondary" ]]; then
SORTKEY=$PRIMARY_UID$DEV_UID
PAIREDDEVICES=$PRIMARY_UID
BLOCKNAME=""
else
SORTKEY=$PRIMARY_UID
padSortKey ${#DEV_UID}
PAIREDDEVICES=$SECONDARY_LIST
fi
printf "%s:%s:%-8s %-10s %-8s %-8s %s \n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$COPYROLE" \
"$BLOCKNAME" \
"$PAIREDDEVICES";
}
function uid()
{
#-------------------------------------------#
@@ -710,7 +824,11 @@ function uid()
fi
fi
printf "%s:%s:%-8s %-8s %s\n" \
if [[ "$COPYROLE" == "secondary" ]]; then
BLOCKNAME="secondary"
fi
printf "%s:%s:%-8s %-10s %s\n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$BLOCKNAME" \
@@ -756,6 +874,9 @@ while [ $# -gt 0 ]; do
--host-access-list|-H)
OUTPUT="host"
;;
--copy-pairs|-P)
OUTPUT="copy"
;;
--version)
PrintVersion
exit 0
@@ -810,6 +931,9 @@ if [[ "$PRINTUID" == "true" ]] && [[ "$OUTPUT" != "old" ]]; then
elif [[ "$OUTPUT" == "new" ]]; then
printf "Bus-ID Status Name Device Type BlkSz Size Blocks\n"
printf "================================================================================\n"
elif [[ "$OUTPUT" == "copy" ]]; then
printf "Bus-ID Role Name Paired devices\n";
printf "================================================================================\n";
elif [[ "$OUTPUT" == "extended" ]]; then
PROCESSING=" $PROCESSING | sed 's/#/\n/g' "
fi

View File

@@ -66,7 +66,7 @@ typedef char *(*table_value_cb_t)(void *item, int id, const char *heading,
struct column *table_get_column(struct column *, const char *);
exit_code_t table_print(struct column *, table_value_cb_t, void *,
struct util_list *, struct util_list *, int, int, int,
int);
int, int);
exit_code_t table_check_columns(struct column *, struct util_list *);
void table_print_columns(struct column *, struct util_list *, int, int);
void table_set_default(struct column *, int, int);

View File

@@ -23,7 +23,7 @@ struct table_attrib {
};
struct table_attrib *table_attrib_new(struct subtype *, struct attrib *);
void table_attribs_show(struct util_list *, int, int, struct devtype *);
void table_attribs_show(struct util_list *, int, int, int, struct devtype *);
void table_attribs_show_details(struct util_list *, struct devtype *);
#endif /* TABLE_ATTRIBS_H */

View File

@@ -423,6 +423,17 @@ with the name of the corresponding column. Values are enclosed in double
quotation marks. Any quotation marks or slashes in the value string are
escaped by placing a slash in front of it.
.PP
.OD shell "" ""
Produces KEY="VALUE" format usable as shell variables.
You can use this option together with the --pairs option to generate
output that is suitable to be sourced in a shell environment. This
option generates similar output as it would be provided by the --pairs
option but it would take care of replacing any character of a column
name that would not be appropriate to be used as part of a shell
variable name by an underscore.
.PP
.
.OD persistent "p" ""
List information from the persistent configuration only.

View File

@@ -2532,7 +2532,7 @@ static exit_code_t do_list_attribs(struct options *opts)
remove_duplicate_attribs(attribs, devtype_count_subtypes(dt));
if (attribs) {
table_attribs_show(attribs, 1, 0, dt);
table_attribs_show(attribs, 1, 0, 0, dt);
ptrlist_free(attribs, 1);
} else
rc = EXIT_ATTRIB_NOT_FOUND;

View File

@@ -137,6 +137,21 @@ static struct attrib dasd_attr_readonly = {
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
};
static struct attrib dasd_attr_copy_pair = {
.name = "copy_pair",
.title = "Modify copy-pair relations",
.desc = "Make a copy-pair relation for this device known to the DASD "
"driver.\n"
"A copy-pair is a comma-separated pair of device bus-IDs\n"
"<primary>,<secondary>.\n"
"Example: 0.0.1000,0.0.2000\n"
"Up to 4 copy-pairs are accepted by the DASD driver for each "
"device.\n",
.unstable = 1,
.multi = 1,
.activerem = 1,
};
static struct attrib dasd_attr_erplog = {
.name = "erplog",
.title = "Enable logging of Error Recovery Processing",
@@ -600,6 +615,81 @@ persistent:
return rc;
}
/* Remove all entries from the copy_pair attribute by writing 'clear' to it. */
static void dasd_clear_copy_pair(struct setting *s)
{
free(s->value);
s->value = misc_strdup("clear");
strlist_free(s->values);
s->values = strlist_new();
strlist_add(s->values, "clear");
s->removed = 0;
s->modified = 1;
}
/*
* Copy-pair values may contain multiple values in one line
* those need to be split up and put in multiple values entries
* delimiter is " " and "\n" depending on the source
* values read from sysfs have " " as delimiter and values from
* zdev have "\n"
*/
static void dasd_split_copy_pair(struct setting *s)
{
struct util_list *new = NULL;
struct strlist_node *node;
new = strlist_new();
util_list_iterate(s->values, node)
strlist_add_multi(new, node->str, "\n ", 0);
strlist_free(s->values);
s->values = new;
}
/*
* For persistent configurations one value per values[] entry is required
* to achieve a correct multi-line copy-pair statement in the resulting
* udev-rule.
*/
static exit_code_t dasd_st_configure_persistent(struct subtype *st,
struct device *dev)
{
struct setting *s;
util_list_iterate(&dev->persistent.settings->list, s) {
if (strcmp(s->name, "copy_pair") == 0)
dasd_split_copy_pair(s);
}
return st->super->configure_persistent(st, dev);
}
/*
* For active configurations one value per values[] entry is required to
* correctly operate the sysfs attribute.
*
* In case of removal the string "clear" has to be written to the
* value and values[] entry.
*/
static exit_code_t dasd_st_configure_active(struct subtype *st,
struct device *dev)
{
struct setting *s;
util_list_iterate(&dev->active.settings->list, s) {
if (strcmp(s->name, "copy_pair") != 0)
continue;
if (s->removed)
dasd_clear_copy_pair(s);
else
dasd_split_copy_pair(s);
}
return st->super->configure_active(st, dev);
}
/*
* DASD device sub-types.
*/
@@ -634,10 +724,13 @@ struct subtype dasd_subtype_eckd = {
&dasd_attr_last_known_reservation_state,
&dasd_attr_safe_offline,
&dasd_attr_fc_security,
&dasd_attr_copy_pair,
&internal_attr_early,
),
.unknown_dev_attribs = 1,
.configure_active = &dasd_st_configure_active,
.configure_persistent = &dasd_st_configure_persistent,
.check_pre_configure = &dasd_st_check_pre_configure,
.add_modules = &dasd_st_add_modules,
};

View File

@@ -70,6 +70,7 @@ struct options {
unsigned int no_headings:1;
struct util_list *base; /* List of struct strlist_node */
unsigned int pairs:1;
unsigned int shell:1;
unsigned int verbose:1;
unsigned int quiet:1;
unsigned int site_id;
@@ -106,6 +107,7 @@ enum {
OPT_VERBOSE = 'V',
OPT_QUIET = 'q',
OPT_PAIRS = 'P',
OPT_SHELL = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_SITE = 's',
};
@@ -167,6 +169,7 @@ static const struct option opt_list[] = {
{ "no-headings", no_argument, NULL, OPT_NO_HEADINGS },
{ "base", required_argument, NULL, OPT_BASE },
{ "pairs", no_argument, NULL, OPT_PAIRS },
{ "shell", no_argument, NULL, OPT_SHELL },
{ "verbose", no_argument, NULL, OPT_VERBOSE },
{ "quiet", no_argument, NULL, OPT_QUIET },
{ "site", required_argument, NULL, OPT_SITE },
@@ -699,6 +702,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
opts->pairs = 1;
break;
case OPT_SHELL:
/* --shell */
opts->shell = 1;
break;
case OPT_VERBOSE:
/* --verbose */
opts->verbose = 1;
@@ -761,6 +769,13 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
if (rc)
goto out;
/* check whether --pairs and --columns is used */
if (opts->shell == 1 && (opts->pairs != 1 || util_list_is_empty(opts->columns))) {
syntax("'--shell' must be used together with "
"'--pairs' and '--columns'\n");
return EXIT_USAGE_ERROR;
}
/* Determine configuration set. */
if (!opts->active && !opts->persistent && !opts->auto_conf) {
/* Default display targets are active + persistent - note that
@@ -1209,7 +1224,7 @@ static exit_code_t do_list_devices(struct options *opts)
/* Display table. */
rc = table_print(dev_table, dev_table_get_value, opts, items,
opts->columns, !opts->no_headings, opts->pairs, 0,
util_list_is_empty(opts->columns));
util_list_is_empty(opts->columns), opts->shell);
ptrlist_free(items, 0);
return rc;
@@ -1443,7 +1458,7 @@ static void settings_table_print(struct setting_list *active,
data.pairs = opts->pairs;
table_print(settings_table, settings_table_get_value, &data, items,
NULL, 1, opts->pairs, ind, 0);
NULL, 1, opts->pairs, ind, 0, opts->shell);
out:
ptrlist_free(items, 1);

View File

@@ -41,6 +41,7 @@ OPTIONS
-n, --no-headings Do not print column headings
--base PATH Use PATH as base for accessing files
--pairs Produce output in KEY="VALUE" format
--shell Produces KEY="VALUE" format usable as shell variables
--auto-conf Only show auto-configuration data
-s, --site ID Only show data configured for the specified site
-V, --verbose Print additional run-time information

View File

@@ -7,6 +7,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -116,6 +117,40 @@ static struct cell *cells_get_default(struct column *columns)
return cells;
}
bool is_shell_char(const char c)
{
/* check whether character is alphabetic */
if (tolower(c) >= 'a' && tolower(c) <= 'z')
return true;
if (isdigit(c) || c == '_')
return true;
return false;
}
/* replaces bad characters that won't work if using them
* as part of variable names in a shell environment
*/
char *replace_bad_chars(const char *value)
{
int i;
char *copy, c;
/* remove bad characters and replace them by an underscore */
copy = misc_strdup(value);
for (i = 0; (c = value[i]); i++) {
/*
* check whether character is alphabetic,
* first character of an env var can't be a digit
*/
if (!is_shell_char(c) || (i == 0 && isdigit(c)))
c = '_';
/* copy character into string copy */
copy[i] = c;
}
return copy;
}
/* Return a newly allocated array of struct cells containing a struct cell for
* each column definition whose name was specified in strlist @names. */
static struct cell *cells_get(struct column *columns, struct util_list *names)
@@ -320,17 +355,23 @@ do_print:
}
/* Print all cells in a row in pairs format. */
static void print_row_pairs(struct cell *cells)
static void print_row_pairs(struct cell *cells, int shell)
{
int i;
struct cell *c;
char *val;
char *heading;
for (i = 0; cells[i].heading; i++) {
c = &cells[i];
val = quote_str(c->value ? c->value : "", 1);
printf("%s%s=%s", i > 0 ? " " : "", c->heading, val);
if (shell)
heading = replace_bad_chars(c->heading);
else
heading = misc_strdup(c->heading);
printf("%s%s=%s", i > 0 ? " " : "", heading, val);
free(val);
free(heading);
}
printf("\n");
}
@@ -342,7 +383,7 @@ static void print_row_pairs(struct cell *cells)
exit_code_t table_print(struct column *columns, table_value_cb_t get_value_cb,
void *data, struct util_list *items,
struct util_list *names, int heading, int pairs,
int indent, int wrap)
int indent, int wrap, int shell)
{
struct cell *cells;
struct ptrlist_node *p;
@@ -372,7 +413,7 @@ exit_code_t table_print(struct column *columns, table_value_cb_t get_value_cb,
util_list_iterate(items, p) {
cells_get_values(cells, p->ptr, get_value_cb, data);
if (pairs)
print_row_pairs(cells);
print_row_pairs(cells, shell);
else
print_row(cells, space, indent, wrap);
}
@@ -434,7 +475,7 @@ void table_print_columns(struct column *columns, struct util_list *names,
for (i = 0; columns[i].name; i++)
ptrlist_add(items, &columns[i]);
table_print(columns_table, columns_table_get_value, NULL, items, names,
heading, pairs, 0, 0);
heading, pairs, 0, 0, 0);
ptrlist_free(items, 0);
}

View File

@@ -115,7 +115,7 @@ void print_type(struct devtype *dt, struct subtype *st, bool multiple)
/* Display table of attributes. */
void table_attribs_show(struct util_list *attribs, int headings, int pairs,
struct devtype *dt)
int shell, struct devtype *dt)
{
struct util_list *subtypes, *subattribs;
struct ptrlist_node *p;
@@ -145,7 +145,7 @@ void table_attribs_show(struct util_list *attribs, int headings, int pairs,
print_type(dt, st, multiple);
table_print(table_attribs, table_attribs_get_value, st,
subattribs, NULL, headings, pairs, indent, 0);
subattribs, NULL, headings, pairs, shell, indent, 0);
ptrlist_free(subattribs, 0);
}

View File

@@ -83,7 +83,7 @@ exit_code_t table_types_show(struct util_list *columns, int headings, int pairs)
items = table_types_build();
rc = table_print(table_types, table_types_get_value, NULL,
items, columns, headings, pairs, 0, 0);
items, columns, headings, pairs, 0, 0, 0);
ptrlist_free(items, 1);
return rc;

View File

@@ -221,6 +221,7 @@ static void write_attr_to_file(FILE *fd, struct device_state *state, const char
struct ptrlist_node *p;
struct setting *s;
struct util_list *list = NULL;
struct strlist_node *str;
/* Apply attributes in correct order. */
list = setting_list_get_sorted(state->settings);
@@ -229,8 +230,13 @@ static void write_attr_to_file(FILE *fd, struct device_state *state, const char
s = p->ptr;
if (s->removed)
continue;
if ((s->attrib && s->attrib->internal) ||
internal_by_name(s->name)) {
if (s->values) {
util_list_iterate(s->values, str) {
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n",
id, s->name, str->str);
}
} else if ((s->attrib && s->attrib->internal) ||
internal_by_name(s->name)) {
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
internal_get_name(s->name), s->value);
} else {

View File

@@ -7,17 +7,18 @@ ALL_CFLAGS += -Wno-address-of-packed-member
#
ifeq (${HAVE_FUSE},0)
check_dep_fuse:
.check_dep_fuse:
touch $@
else
check_dep_fuse:
.check_dep_fuse:
$(call check_dep, \
"zgetdump mount support", \
"fuse.h", \
"fuse3-devel or libfuse3-dev", \
"HAVE_FUSE=0", \
"-DFUSE_USE_VERSION=30")
touch $@
endif
.detect_openssl.dep.c:
@@ -30,7 +31,7 @@ endif
echo " EVP_MD_CTX_free(ctx);" >> $@
echo "}" >> $@
.check_dep_zgetdump: .detect_openssl.dep.c check_dep_fuse
.check_dep_zgetdump: .detect_openssl.dep.c .check_dep_fuse
$(call check_dep, \
"zgetdump", \
"zlib.h", \
@@ -131,6 +132,6 @@ install-zgetdump: zgetdump
install: $(INSTALL_TARGETS)
clean:
rm -f -- *.o *~ zgetdump core.* .detect_openssl.dep.c .check_dep_zgetdump
rm -f -- *.o *~ zgetdump core.* .detect_openssl.dep.c .check_dep_zgetdump .check_dep_fuse
.PHONY: all install clean check_dep_fuse check_dep_zlib skip-zgetdump install-zgetdump
.PHONY: all install clean skip-zgetdump install-zgetdump

View File

@@ -121,7 +121,8 @@ Elf64_Shdr *read_elf_shdrs(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, unsig
return shdrs;
}
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size)
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size,
const size_t max_size)
{
const size_t sh_size = shdr->sh_size;
unsigned char *ret;
@@ -133,6 +134,9 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s
if (shdr->sh_offset > OFF_T_MAX)
ERR_EXIT("Unsupported offset");
if (sh_size > max_size)
ERR_EXIT("Unsupported section size: %#lx > %#lx", sh_size, max_size);
ret = util_malloc(sh_size);
zg_seek(fh, (off_t)shdr->sh_offset, ZG_CHECK);
zg_read(fh, ret, sh_size, ZG_CHECK);
@@ -141,7 +145,8 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s
}
char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const Elf64_Shdr *shdrs,
const unsigned int shnum, size_t *shstrtab_size)
const unsigned int shnum, size_t *shstrtab_size,
const size_t max_shstrtab_size)
{
const size_t shstrndx = ehdr->e_shstrndx;
Elf64_Xword tmp_shstrtab_size;
@@ -166,6 +171,10 @@ char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const El
ERR_EXIT("Unsupported offset");
tmp_shstrtab_size = shdrs[shstrndx].sh_size;
if (tmp_shstrtab_size > max_shstrtab_size)
ERR_EXIT("Unsupported shstrtab size: %#lx > %#lx", tmp_shstrtab_size,
max_shstrtab_size);
shstrtab = util_malloc(tmp_shstrtab_size);
zg_seek(fh, (off_t)shstrndx_off, ZG_CHECK);
zg_read(fh, shstrtab, tmp_shstrtab_size, ZG_CHECK);

View File

@@ -195,7 +195,8 @@ Elf64_Shdr *read_elf_shdrs(const struct zg_fh *fh, const Elf64_Ehdr *ehdr,
*
* To read the section content the offset of @fh is changed.
*/
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size);
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size,
const size_t max_size);
/*
* Read ELF section header string table
@@ -203,7 +204,8 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s
* To read the section header string table the offset of @fh is changed.
*/
char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const Elf64_Shdr *shdrs,
const unsigned int shnum, size_t *shstrtab_size);
const unsigned int shnum, size_t *shstrtab_size,
const size_t max_shstrtab_size);
/*
* Find ELF section header by section name

View File

@@ -46,17 +46,19 @@ WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf64_Ehdr, free);
* read_elf_section_data_as_gbytes:
* @fh: (not nullable): open input file
* @shdr: (not nullable): section header of the section to read
* @max_size: maximum section data size in bytes
*
* Try to read section data and return it as #GBytes.
*
* Returns: #GBytes on success, %NULL if an error occurred
*/
static GBytes *read_elf_section_data_as_gbytes(const struct zg_fh *fh, const Elf64_Shdr *shdr)
static GBytes *read_elf_section_data_as_gbytes(const struct zg_fh *fh, const Elf64_Shdr *shdr,
const size_t max_size)
{
unsigned char *data;
size_t size;
data = read_elf_section_data(fh, shdr, &size);
data = read_elf_section_data(fh, shdr, &size, max_size);
if (!data)
return NULL;
return g_bytes_new_with_free_func(data, size, free, data);
@@ -106,6 +108,12 @@ static dfi_cpu_t *nt_s390_pv_cpu_data_read(const struct zg_fh *fh, const Elf64_N
g_assert(dump_key);
if (note_descsz > PV_MAX_NT_S390_PV_CPU_DATA_SIZE) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_CORRUPTED_NOTE,
_("Unable to read confidential CPU data. Dump probably corrupted."));
return NULL;
}
note_data = g_malloc(note_descsz);
if (nt_read(fh, note_hdr, note_data, note_descsz) < 0) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_CORRUPTED_NOTE,
@@ -164,7 +172,7 @@ static int pt_notes_add(const struct zg_fh *fh, const Elf64_Phdr *phdr, const un
dfi_cpu_add(g_steal_pointer(&cpu_current));
break;
default:
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-Note %#x"), note.n_type);
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-Note %#x\n"), note.n_type);
__attribute__((fallthrough));
case NT_PRSTATUS:
case NT_FPREGSET:
@@ -224,7 +232,7 @@ static int dfi_pv_elf_init(void)
if (!shdrs)
return -ENODEV;
shstrtab = read_elf_shstrtab(fh, ehdr, shdrs, shnum, &shstrtab_size);
shstrtab = read_elf_shstrtab(fh, ehdr, shdrs, shnum, &shstrtab_size, PV_MAX_SHSTRTAB_SIZE);
if (!shstrtab)
return -ENODEV;
@@ -255,7 +263,8 @@ static int dfi_pv_elf_init(void)
return -EINVAL;
/* Read the PV completion configuration section data */
completion_sdata = read_elf_section_data_as_gbytes(fh, completion_shdr);
completion_sdata =
read_elf_section_data_as_gbytes(fh, completion_shdr, PV_MAX_COMPL_DATA_SIZE);
if (!completion_sdata)
return -EINVAL;
@@ -263,9 +272,9 @@ static int dfi_pv_elf_init(void)
* completion configuration data and store it in `@cpl_conf_decr`. In addition, mmap the
* configuration storage state area and use the `tweak_nonce`.
*/
if (pv_process_section_data(fh->fh, completion_sdata, storage_state_shdr->sh_offset,
storage_state_shdr->sh_size, key, &cpl_conf_decr, &dump_key,
&storage_state_data, &error) < 0) {
if (pv_process_section_data(fh->fh, fh->sb.st_size, completion_sdata,
storage_state_shdr->sh_offset, storage_state_shdr->sh_size, key,
&cpl_conf_decr, &dump_key, &storage_state_data, &error) < 0) {
ERR(_("Unable to read decryption information:" ERR_NEWLINE "%s."), error->message);
return -EINVAL;
}
@@ -313,7 +322,8 @@ static int dfi_pv_elf_init(void)
}
break;
default:
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-PHDR type %#x"), phdr->p_type);
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-PHDR type %#x\n"),
phdr->p_type);
break;
}
}

View File

@@ -271,7 +271,7 @@ int ngdump_get_dump_part(struct zg_fh *zg_fh)
__func__, comp_entry.type,
comp_entry.compdat.load_address);
/* Is this a kernel image ? */
if (comp_entry.type == COMPONENT_LOAD &&
if (comp_entry.type == COMPONENT_TYPE_LOAD &&
comp_entry.compdat.load_address == IMAGE_ENTRY)
break;
}

View File

@@ -20,6 +20,16 @@
#define PV_ELF_SECTION_NAME_COMPL "pv_compl"
#define PV_ELF_SECTION_NAME_TWEAKS "pv_mem_meta"
/* Maximum size (in bytes) of completion section data */
#define PV_MAX_COMPL_DATA_SIZE ROUNDUP(sizeof(pv_dump_completion_data_v1_t), PAGE_SIZE)
/* Maximum size (in bytes) of section header string table */
#define PV_MAX_SHSTRTAB_SIZE \
ROUNDUP(sizeof(PV_ELF_SECTION_NAME_COMPL) + sizeof(PV_ELF_SECTION_NAME_TWEAKS) + \
sizeof(".shstrtab"), \
PAGE_SIZE)
/* Maximum size of NT_S390_PV_CPU_DATA */
#define PV_MAX_NT_S390_PV_CPU_DATA_SIZE ROUNDUP(sizeof(pv_cpu_dump_v1_t), PAGE_SIZE)
#define PV_COMPL_DATA_VERSION_1 ((uint32_t)1)
#define PV_SEC_CPU_DATA_VERSION_1 ((uint32_t)1)

View File

@@ -239,7 +239,7 @@ dfi_cpu_t *pv_decrypt_cpu_note_data(const unsigned int expected_version, GBytes
/* Check dump flags */
if (pv_cpu->has_osii)
util_log_print(UTIL_LOG_WARN,
_("CPU state may contain partial instruction results"));
_("CPU state may contain partial instruction results\n"));
return pv_dfi_cpu_from_pv_cpu(pv_cpu);
}
@@ -608,14 +608,26 @@ ssize_t pv_process_pglist(pv_crypto_ctx_t *ctx, BIO *output,
return -1;
}
}
g_assert(!(page_state & ~PV_ZERO_PAGE));
if (page_state & ~PV_ZERO_PAGE) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR,
ZDUMP_ERR_PGLIST_INVAL_STATE,
_("Invalid page state. page-idx: %#lx, state: %#lx"),
page_idx, page_state);
return -1;
}
continue;
}
if (page_state & PV_SHARED_PAGE) {
/* shared pages are not encrypted */
input = ctx->input;
g_assert(!(page_state & ~PV_SHARED_PAGE));
if (page_state & ~PV_SHARED_PAGE) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR,
ZDUMP_ERR_PGLIST_INVAL_STATE,
_("Invalid page state. page-idx: %#lx, state: %#lx"),
page_idx, page_state);
return -1;
}
} else if (page_state & PV_ENCRYPTED_PAGE) {
input = ctx->filter;
calculate_tweak(tweak_comp, ctx->nonce, &ctx->tweak_scratch);
@@ -624,7 +636,13 @@ ssize_t pv_process_pglist(pv_crypto_ctx_t *ctx, BIO *output,
if (update_tweak(ctx, error) < 0)
return -1;
g_assert(!(page_state & ~PV_ENCRYPTED_PAGE));
if (page_state & ~PV_ENCRYPTED_PAGE) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR,
ZDUMP_ERR_PGLIST_INVAL_STATE,
_("Invalid page state. page-idx: %#lx, state: %#lx"),
page_idx, page_state);
return -1;
}
} else {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_PGLIST_INVAL_STATE,
_("Invalid page state. page-idx: %#lx, state: %#lx"), page_idx,
@@ -659,10 +677,10 @@ struct _storage_state_mmap {
gatomicrefcount ref_count;
};
storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, const u64 size,
GError **error)
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
const u64 size, GError **error)
{
size_t tweak_components_cnt, start_addr, in_page_offset, mmapped_size;
size_t tweak_components_cnt, start_addr, min_size, in_page_offset, mmapped_size;
g_autoptr(storage_state_mmap_t) ret = NULL;
int saved_errno = 0;
u8 *ptr;
@@ -688,6 +706,19 @@ storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, con
start_addr);
return NULL;
}
if (G_UNLIKELY(!g_uint64_checked_add(&min_size, start_addr, mmapped_size))) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_PAGE_END_ADDR_OVERFLOW,
_("UInt overflow detected: %s: start_addr %#lx mmap_size %#lx"),
__func__, start_addr, mmapped_size);
return NULL;
}
if (file_size < min_size) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_MMAP,
_("mmap failed: file too small"));
return NULL;
}
ptr = mmap(NULL, mmapped_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, fd,
(ssize_t)start_addr);
saved_errno = errno;
@@ -722,7 +753,7 @@ void storage_state_mmap_unref(storage_state_mmap_t *storage_state)
if (storage_state->first_page_ptr) {
int rc = munmap(storage_state->first_page_ptr, storage_state->mapped_size);
if (rc != 0)
util_log_print(UTIL_LOG_WARN, _("munmap has failed"));
util_log_print(UTIL_LOG_WARN, _("munmap has failed\n"));
}
g_free(storage_state);
}
@@ -796,9 +827,9 @@ static long completion_data_get_version(GBytes *cpl_data, GError **error)
return *version;
}
int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 storage_state_offset,
const size_t storage_state_size, GBytes *cck,
pv_dump_completion_t **completion_decr, GBytes **dump_key,
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
const u64 storage_state_offset, const size_t storage_state_size,
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
storage_state_mmap_t **storage_state, GError **error)
{
g_autoptr(pv_dump_completion_t) _completion_decr = NULL;
@@ -852,8 +883,8 @@ int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 stor
return -1;
}
_storage_state_data =
storage_state_mmap_new(fd, storage_state_offset, storage_state_size, error);
_storage_state_data = storage_state_mmap_new(fd, file_size, storage_state_offset,
storage_state_size, error);
if (!_storage_state_data)
return -1;

View File

@@ -258,9 +258,9 @@ bool pv_is_pv_elf(const Elf64_Shdr *shdrs, const unsigned int shnum, const char
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 storage_state_offset,
const size_t storage_state_size, GBytes *cck,
pv_dump_completion_t **completion_decr, GBytes **dump_key,
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
const u64 storage_state_offset, const size_t storage_state_size,
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
storage_state_mmap_t **storage_state_data, GError **error);
/**
@@ -283,14 +283,15 @@ int pv_elf_read(const pv_elf_ctx_t *elf_ctx, const u64 start_addr, void *dst, co
/**
* storage_state_mmap_new:
* @fd: file descriptor for which to create the mapping
* @file_size: file size in bytes
* @offset: offset in fd to pv_mem_meta section
* @size: size of mapping (and pv_mem_meta section)
* @error: return value for GError
*
* Returns: new storage_state_mmap context
*/
storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, const u64 size,
GError **error);
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
const u64 size, GError **error);
/**
* storage_state_ref:

View File

@@ -43,17 +43,17 @@ ziorep_utilization: ziorep_utilization.o ziorep_framer.o ziorep_frameset.o \
install: all
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
< ziomon > $(DESTDIR)$(USRSBINDIR)/ziomon;
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon;
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon;
chmod 755 $(DESTDIR)$(USRSBINDIR)/ziomon;
$(SED) -e \
's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
< ziomon_fcpconf > $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
chmod 755 $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
$(SED) -e \
's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
< ziorep_config > $(DESTDIR)$(USRSBINDIR)/ziorep_config;
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziorep_config;
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziorep_config;
chmod 755 $(DESTDIR)$(USRSBINDIR)/ziorep_config;
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 ziomon.8 \
$(DESTDIR)$(MANDIR)/man8

View File

@@ -15,14 +15,16 @@
int extract_length(void *data)
{
struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
struct eckd_blockptr_legacy *blockptr =
(struct eckd_blockptr_legacy *)data;
return blockptr->size * (blockptr->blockct + 1);
}
int is_zero_block(void *data)
{
struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
struct eckd_blockptr_legacy *blockptr =
(struct eckd_blockptr_legacy *)data;
return blockptr->cyl || blockptr->head || blockptr->sec;
}
@@ -30,7 +32,7 @@ int is_zero_block(void *data)
void * load_direct(disk_blockptr_t *data, struct subchannel_id subchannel_id,
void *load_addr)
{
struct eckd_blockptr *blockptr = &data->eckd;
struct eckd_blockptr_legacy *blockptr = &data->eckd;
struct ccw1 *ccws;
unsigned long record_size;
struct seek_arg seek_addr;

View File

@@ -120,9 +120,9 @@ void __noreturn start(void)
/* skip header */
entry = (struct component_entry *)
(load_address + sizeof(struct component_header));
while (entry->type == COMPONENT_LOAD ||
entry->type == COMPONENT_SIGNATURE) {
if (entry->type == COMPONENT_SIGNATURE) {
while (entry->type == COMPONENT_TYPE_LOAD ||
entry->type == COMPONENT_TYPE_SIGNATURE) {
if (entry->type == COMPONENT_TYPE_SIGNATURE) {
/* Skip unhandled signature components */
entry++;
continue;
@@ -132,7 +132,7 @@ void __noreturn start(void)
load_blocklist(entry, subchannel_id, load_address);
entry++;
}
if (entry->type != COMPONENT_EXECUTE)
if (entry->type != COMPONENT_TYPE_EXECUTE)
panic(EWRONGTYPE, "");
load_psw = entry->compdat.load_psw;

View File

@@ -27,7 +27,7 @@
#include "error.h"
typedef union {
struct eckd_blockptr eckd;
struct eckd_blockptr_legacy eckd;
struct linear_blockptr linear;
} disk_blockptr_t;

View File

@@ -158,8 +158,8 @@ struct mvdump_parm_table {
void boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type,
void *param);
void boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
disk_blockptr_t *bm_ptr, struct disk_info *info);
void boot_get_ipl_info_ccw(struct boot_info *boot_info, uint8_t dev_type,
disk_blockptr_t *bm_ptr, struct disk_info *info);
int boot_check_data(void);
int boot_init_fba_stage0(struct boot_fba_stage0* stage0,
@@ -187,6 +187,8 @@ int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
address_t initrd_addr, address_t image_addr);
int boot_get_tape_dump(void** data, size_t* size, uint64_t mem);
int boot_get_eckd_dump_stage2(void** data, size_t* size, uint64_t mem);
int boot_get_eckd_ld_ipl_br(void **br_ptr, size_t *size_ptr,
disk_blockptr_t *table, struct disk_info *info);
int boot_get_eckd_mvdump_stage2(void** data, size_t* size, uint64_t mem,
uint8_t force, struct mvdump_parm_table);
int boot_get_fba_dump_stage2(void** data, size_t* size, uint64_t mem);

View File

@@ -51,11 +51,7 @@ struct file_signature {
int bootmap_header_init(int fd);
int bootmap_header_read(int fd, struct bootmap_header *bh);
int bootmap_header_write(int fd, struct bootmap_header *bh);
int bootmap_create(struct job_data* job, disk_blockptr_t* program_table,
disk_blockptr_t *scsi_dump_sb_blockptr,
disk_blockptr_t** stage2_list, blocknum_t* stage2_count,
char** device, struct disk_info** new_info);
void bootmap_store_blockptr(void* buffer, disk_blockptr_t* ptr,
struct disk_info* info);
void bootmap_store_blockptr(void *buffer, disk_blockptr_t *ptr,
struct disk_info *info, int fid);
#endif /* if not BOOTMAP_H */

View File

@@ -16,6 +16,7 @@
#include <sys/types.h>
#include "zipl.h"
#include "lib/vtoc.h"
/* Type for representing disk block numbers */
@@ -23,7 +24,7 @@ typedef uint64_t blocknum_t;
/* Pointer to block on a disk with cyl/head/sec layout */
struct disk_blockptr_chs {
int cyl;
unsigned int cyl;
int head;
int sec;
int size;
@@ -52,14 +53,6 @@ typedef enum {
disk_type_eckd_cdl,
} disk_type_t;
/* from linux/hdregs.h */
struct hd_geometry {
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
unsigned long start;
};
/* Disk information source */
typedef enum {
source_auto,
@@ -108,6 +101,7 @@ int disk_get_info_from_file(const char* filename,
struct disk_info** info);
void disk_free_info(struct disk_info* info);
char* disk_get_type_name(disk_type_t type);
char *disk_get_ipl_type(disk_type_t type);
int disk_is_large_volume(struct disk_info* info);
int disk_cyl_from_blocknum(blocknum_t blocknum, struct disk_info* info);
int disk_head_from_blocknum(blocknum_t blocknum, struct disk_info* info);

View File

@@ -15,12 +15,90 @@
#include "disk.h"
#include "job.h"
#include "zipl.h"
#include "boot/boot_defs.h"
/*
* For compatibility reasons zIPL can build multiple "similar"
* program tables, which differ only in block pointers format
*/
enum program_table_id {
PROGRAM_TABLE_0,
PROGRAM_TABLE_1,
NR_PROGRAM_TABLES
};
int install_bootloader(const char* device, disk_blockptr_t* program_table,
disk_blockptr_t* scsi_dump_sb_blockptr,
disk_blockptr_t* stage2_data, blocknum_t stage2_count,
struct disk_info* info, struct job_data* job);
enum program_component_id {
COMPONENT_ID_HEAP_AREA,
COMPONENT_ID_STACK_AREA,
COMPONENT_ID_LOADER_SIGNATURE,
COMPONENT_ID_LOADER,
COMPONENT_ID_PARAMETERS,
COMPONENT_ID_IMAGE_SIGNATURE,
COMPONENT_ID_KERNEL_IMAGE,
COMPONENT_ID_PARMLINE,
COMPONENT_ID_RAMDISK_SIGNATURE,
COMPONENT_ID_RAMDISK,
COMPONENT_ID_ENVBLK,
COMPONENT_ID_SEGMENT_FILE,
NR_PROGRAM_COMPONENTS
};
struct component_loc {
address_t addr;
size_t size;
};
struct component_footer {
component_type type;
const char *desc;
};
struct program_component {
struct component_loc loc;
disk_blockptr_t *list;
blocknum_t count;
};
struct program_table {
disk_blockptr_t table;
disk_blockptr_t *stage1b_list;
blocknum_t stage1b_count;
};
/* Bootloader Installation Set */
struct install_set {
struct program_table tables[NR_PROGRAM_TABLES];
struct program_component *components[NR_PROGRAM_COMPONENTS];
int nr_tables; /* number of "similar" program tables to be installed */
int nr_menu_entries;
int fd;
char *device;
char *filename;
struct disk_info *info;
disk_blockptr_t scsi_dump_sb_blockptr;
};
extern struct component_footer component_footers[NR_PROGRAM_COMPONENTS];
static inline component_type component_type_by_id(enum program_component_id id)
{
return component_footers[id].type;
}
static inline const char *component_desc_by_id(enum program_component_id id)
{
return component_footers[id].desc;
}
static inline struct program_component *get_component(struct install_set *bis,
int i, int j)
{
return bis->components[i] + j;
}
int prepare_bootloader(struct job_data *job, struct install_set *bis);
int install_bootloader(struct job_data *job, struct install_set *bis);
void free_bootloader(struct install_set *bis);
int install_tapeloader(const char* device, const char* image,
const char* parmline, const char* ramdisk,
address_t image_addr, address_t parm_addr,

View File

@@ -7,7 +7,8 @@ ALL_CPPFLAGS += -I../include -I../boot \
-D_FILE_OFFSET_BITS=64 $(NO_PIE_CFLAGS)
ALL_LDFLAGS += -Wl,-z,noexecstack $(NO_PIE_LDFLAGS)
libs = $(rootdir)/libutil/libutil.a
libs = $(rootdir)/libutil/libutil.a \
$(rootdir)/libvtoc/libvtoc.a \
objects = misc.o error.o scan.o job.o boot.o bootmap.o fs-map.o disk.o \
bootmap_header.o envblk.o install.o zipl.o $(rootdir)/zipl/boot/data.o

View File

@@ -16,6 +16,7 @@
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "lib/util_libc.h"
#include "stage3.h"
@@ -560,9 +561,12 @@ boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type, void *param)
sizeof(boot_info->bp.dump.param));
}
/*
* Helper function to install a boot record for CCW-type IPL from DASD
*/
void
boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
disk_blockptr_t *bm_ptr, struct disk_info *info)
boot_get_ipl_info_ccw(struct boot_info *boot_info, uint8_t dev_type,
disk_blockptr_t *bm_ptr, struct disk_info *info)
{
memset(boot_info, 0, sizeof(*boot_info));
memcpy(&boot_info->magic, BOOT_INFO_MAGIC, sizeof(boot_info->magic));
@@ -570,6 +574,30 @@ boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
boot_info->dev_type = dev_type;
boot_info->bp_type = BOOT_INFO_BP_TYPE_IPL;
boot_info->version = BOOT_INFO_VERSION;
bootmap_store_blockptr(&boot_info->bp, bm_ptr, info);
bootmap_store_blockptr(&boot_info->bp, bm_ptr, info,
LEGACY_BLKPTR_FORMAT_ID);
}
/**
* Allocate and initialize a boot record for List-Directed IPL from DASD
*
* TABLE: address of an actual program table
*/
int boot_get_eckd_ld_ipl_br(void **br_ptr, size_t *size_ptr,
disk_blockptr_t *table, struct disk_info *info)
{
struct eckd_boot_record *br;
br = util_zalloc(info->phy_block_size);
if (!br)
return -1;
memcpy(&br->magic, ZIPL_MAGIC, ZIPL_MAGIC_SIZE);
br->version_id = DISK_LAYOUT_ID;
bootmap_store_blockptr(&br->program_table_pointer, table, info,
BLKPTR_FORMAT_ID);
br->os_id = 0x55aa; /* LINUX */
*br_ptr = br;
*size_ptr = info->phy_block_size;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@
#include "lib/util_proc.h"
#include "lib/util_sys.h"
#include "lib/util_libc.h"
#include "disk.h"
#include "error.h"
#include "install.h"
@@ -755,7 +756,6 @@ disk_write_block_buffer_align(int fd, int fd_is_basedisk, const void *buffer,
size_t bytecount, disk_blockptr_t **blocklist,
struct disk_info *info, int align, off_t *offset)
{
disk_blockptr_t* list;
blocknum_t count;
blocknum_t i;
size_t written;
@@ -764,13 +764,12 @@ disk_write_block_buffer_align(int fd, int fd_is_basedisk, const void *buffer,
int rc;
count = (bytecount + info->phy_block_size - 1) / info->phy_block_size;
list = (disk_blockptr_t *) misc_malloc(sizeof(disk_blockptr_t) *
count);
if (list == NULL) {
*blocklist = (disk_blockptr_t *)util_zalloc(sizeof(disk_blockptr_t) *
count);
if (*blocklist == NULL) {
close(fd);
return 0;
}
memset((void *) list, 0, sizeof(disk_blockptr_t) * count);
/* Build list */
for (i=0, written=0; i < count; i++, written += chunk_size) {
chunk_size = bytecount - written;
@@ -778,17 +777,15 @@ disk_write_block_buffer_align(int fd, int fd_is_basedisk, const void *buffer,
chunk_size = info->phy_block_size;
rc = disk_write_block_aligned_base(fd, fd_is_basedisk,
VOID_ADD(buffer, written),
chunk_size, &list[i], info,
chunk_size, &(*blocklist)[i],
info,
i == 0 ? align : info->phy_block_size,
&pos);
if (rc) {
free(list);
if (rc)
return 0;
}
if (offset != NULL && i == 0)
*offset = pos;
}
*blocklist = list;
return count;
}
@@ -830,6 +827,21 @@ disk_get_type_name(disk_type_t type)
}
}
/* Return IPL types supported for a given disk TYPE */
char *disk_get_ipl_type(disk_type_t type)
{
switch (type) {
case disk_type_scsi:
return "LD-";
case disk_type_fba:
case disk_type_eckd_ldl:
return "CCW-";
case disk_type_eckd_cdl:
return "CCW- and LD-";
default:
return "";
}
}
/* Return non-zero for ECKD large volumes. */
int
@@ -1050,7 +1062,6 @@ disk_get_blocklist_from_file(const char *filename, struct file_range *reg,
disk_blockptr_t **blocklist,
struct disk_info* info)
{
disk_blockptr_t* list;
struct stat stats;
int fd;
off_t off;
@@ -1094,24 +1105,21 @@ disk_get_blocklist_from_file(const char *filename, struct file_range *reg,
blk_count = ((blocknum_t) count +
info->phy_block_size - 1) / info->phy_block_size;
list = (disk_blockptr_t *) misc_malloc(sizeof(disk_blockptr_t) *
blk_count);
if (list == NULL) {
*blocklist = (disk_blockptr_t *)util_zalloc(sizeof(disk_blockptr_t) *
blk_count);
if (*blocklist == NULL) {
close(fd);
return 0;
}
memset((void *) list, 0, sizeof(disk_blockptr_t) * blk_count);
/* Build list */
for (i = 0; i < blk_count; i++) {
if (disk_get_blocknum(fd, 0, blk_off + i, &blocknum, info)) {
free(list);
close(fd);
return 0;
}
disk_blockptr_from_blocknum(&list[i], blocknum, info);
disk_blockptr_from_blocknum(&(*blocklist)[i], blocknum, info);
}
close(fd);
*blocklist = list;
return blk_count;
}

View File

@@ -25,6 +25,7 @@
#include "lib/zt_common.h"
#include "lib/util_sys.h"
#include "lib/vtoc.h"
#include "boot.h"
#include "bootmap.h"
@@ -109,7 +110,8 @@ update_scsi_mbr(void* bootblock, disk_blockptr_t* table,
memset(buffer, 0, sizeof(struct scsi_mbr));
memcpy(&mbr->magic, ZIPL_MAGIC, ZIPL_MAGIC_SIZE);
mbr->version_id = DISK_LAYOUT_ID;
bootmap_store_blockptr(&mbr->program_table_pointer, table, info);
bootmap_store_blockptr(&mbr->program_table_pointer, table, info,
0 /* this argument is ignored for scsi */);
if (scsi_dump_sb_blockptr->linear.block != 0) {
/* Write dump boot_info */
param.block = scsi_dump_sb_blockptr->linear.block *
@@ -168,11 +170,11 @@ install_scsi(int fd, disk_blockptr_t* program_table, struct disk_info* info,
}
/* Install bootloader for initial program load from an FBA type disk. */
/* Install bootloader for CCW-type IPL from a FBA type disk */
static int
install_fba(int fd, disk_blockptr_t *program_table,
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
struct disk_info *info)
install_fba_ccw(int fd, disk_blockptr_t *program_table,
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
struct disk_info *info)
{
struct boot_fba_stage0 stage0;
@@ -180,8 +182,8 @@ install_fba(int fd, disk_blockptr_t *program_table,
if (boot_init_fba_stage0(&stage0, stage1b_list, stage1b_count))
return -1;
boot_get_ipl_info(&stage0.boot_info, BOOT_INFO_DEV_TYPE_FBA,
program_table, info);
boot_get_ipl_info_ccw(&stage0.boot_info, BOOT_INFO_DEV_TYPE_FBA,
program_table, info);
if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 0)))
return -1;
@@ -218,12 +220,14 @@ out:
return rc;
}
/* Install bootloader for initial program load from an ECKD type disk with
* Linux Disk Layout. */
/*
* Install bootloader for CCW-type IPL from ECKD type disk with
* Linux Disk Layout
*/
static int
install_eckd_ldl(int fd, disk_blockptr_t *program_table,
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
struct disk_info *info)
install_eckd_ldl_ccw(int fd, disk_blockptr_t *program_table,
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
struct disk_info *info)
{
struct boot_eckd_ldl_stage0 stage0;
struct boot_eckd_stage1 stage1;
@@ -236,8 +240,8 @@ install_eckd_ldl(int fd, disk_blockptr_t *program_table,
if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
return -1;
boot_get_ipl_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
program_table, info);
boot_get_ipl_info_ccw(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
program_table, info);
if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
sizeof(stage0))))
@@ -246,12 +250,14 @@ install_eckd_ldl(int fd, disk_blockptr_t *program_table,
return 0;
}
/* Install bootloader for initial program load from an ECKD type disk with
* OS/390 compatible disk layout. */
static int
install_eckd_cdl(int fd, disk_blockptr_t *program_table,
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
struct disk_info *info)
/**
* Install bootloader for CCW-type IPL from ECKD type disk with
* OS/390 compatible disk layout
*/
static int install_eckd_cdl_ccw(int fd, disk_blockptr_t *program_table,
disk_blockptr_t *stage1b_list,
blocknum_t stage1b_count,
struct disk_info *info)
{
struct boot_eckd_cdl_stage0 stage0;
struct boot_eckd_stage1 stage1;
@@ -264,8 +270,8 @@ install_eckd_cdl(int fd, disk_blockptr_t *program_table,
if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
return -1;
boot_get_ipl_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
program_table, info);
boot_get_ipl_info_ccw(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
program_table, info);
if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
4 + info->phy_block_size)))
@@ -273,16 +279,74 @@ install_eckd_cdl(int fd, disk_blockptr_t *program_table,
return 0;
}
int
install_bootloader(const char *device, disk_blockptr_t *program_table,
disk_blockptr_t *scsi_dump_sb_blockptr,
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
struct disk_info *info, struct job_data *job)
/**
* Install a program table for List-Directed IPL on a CDL-formatted DASD.
*
* The installation means storing an actual boot record address in the
* volume label.
*
* BR: represents an actual boot record address.
*/
static int install_eckd_cdl_ld(int fd, disk_blockptr_t *br,
struct disk_info *info)
{
struct vol_label_cdl vl;
int rc;
/* Read a volume label from CDL-formatted DASD */
if (misc_seek(fd, 2 * info->phy_block_size))
return -1;
rc = misc_read(fd, &vl, sizeof(vl));
if (rc) {
error_text("Could not read volume label");
return rc;
}
/* Verify that we have a VOL1 label */
if (!is_vol1(vl.vollbl)) {
error_text("Volume label 'vol1' not initialized");
return -1;
}
/* Pack the actual boot record address */
vtoc_set_cchhb(&vl.br, br->chs.cyl, br->chs.head, br->chs.sec);
/* Write out the updated volume label */
if (misc_seek(fd, 2 * info->phy_block_size))
return -1;
rc = DRY_RUN_FUNC(misc_write(fd, &vl, sizeof(vl)));
if (rc)
error_text("Could not update volume lablel 'vol1'");
return 0;
}
/**
* Install a "compatible" boot record referring one, or two "similar"
* program tables.
*
* The picture below shows which program table is used for IPL
* of specified type from disk of specified type.
* E.g. program table "0" is used for CCW-type IPL from ECKD DASD,
* LD-IPL from DASD FBA is unsupported (respectively, only one program
* table "0" is used), etc.
*
* CCW-IPL LD-IPL
*
* SCSI X 0
* DASD FBA 0 X
* ECKD DASD LDL 0 X
* ECKD DASD CDL 0 1
*/
int install_bootloader(struct job_data *job, struct install_set *bis)
{
disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr;
struct program_table *pt0 = &bis->tables[PROGRAM_TABLE_0];
struct program_table *pt1 = &bis->tables[PROGRAM_TABLE_1];
struct disk_info *info = bis->info;
char *device = bis->device;
int fd, rc;
/* Inform user about what we're up to */
printf("Preparing boot device: ");
printf("Preparing boot device for %sIPL: ",
disk_get_ipl_type(info->type));
if (info->name) {
printf("%s", info->name);
if (info->devno >= 0)
@@ -310,27 +374,40 @@ install_bootloader(const char *device, disk_blockptr_t *program_table,
"caches.\n");
}
}
/* Call disk specific install functions */
/*
* Depending on disk type, install one or two program tables
* for CCW-type IPL and (or) for List-Directed IPL (see the
* picture in comments above)
*/
rc = -1;
switch (info->type) {
case disk_type_scsi:
rc = install_scsi(fd, program_table, info,
rc = install_scsi(fd, &pt0->table, info,
scsi_dump_sb_blockptr);
if (rc == 0 && job->id == job_dump_partition &&
!is_ngdump_enabled(device, &job->target))
rc = overwrite_partition_start(fd, info, 0);
break;
case disk_type_fba:
rc = install_fba(fd, program_table, stage1b_list,
stage1b_count, info);
rc = install_fba_ccw(fd,
&pt0->table,
pt0->stage1b_list,
pt0->stage1b_count, info);
break;
case disk_type_eckd_ldl:
rc = install_eckd_ldl(fd, program_table, stage1b_list,
stage1b_count, info);
rc = install_eckd_ldl_ccw(fd,
&pt0->table,
pt0->stage1b_list,
pt0->stage1b_count, info);
break;
case disk_type_eckd_cdl:
rc = install_eckd_cdl(fd, program_table, stage1b_list,
stage1b_count, info);
rc = install_eckd_cdl_ccw(fd,
&pt0->table,
pt0->stage1b_list,
pt0->stage1b_count, info);
if (rc)
break;
rc = install_eckd_cdl_ld(fd, pt1->stage1b_list, info);
break;
case disk_type_diag:
/* Should not happen */

View File

@@ -126,11 +126,8 @@ check_for_root(void)
int
main(int argc, char* argv[])
{
struct disk_info* info;
disk_blockptr_t program_table, scsi_dump_sb_blockptr, *stage1b_list;
blocknum_t stage1b_count;
struct install_set bis;
struct job_data* job;
char* device;
int rc;
/* Check internals */
@@ -197,21 +194,11 @@ main(int argc, char* argv[])
case job_ipl:
case job_segment:
case job_menu:
/* Create bootmap */
stage1b_list = NULL;
rc = bootmap_create(job, &program_table, &scsi_dump_sb_blockptr,
&stage1b_list, &stage1b_count, &device,
&info);
rc = prepare_bootloader(job, &bis);
if (rc)
break;
/* Install boot loader */
rc = install_bootloader(device, &program_table,
&scsi_dump_sb_blockptr, stage1b_list,
stage1b_count, info, job);
if (stage1b_list != NULL)
free(stage1b_list);
misc_free_temp_dev(device);
disk_free_info(info);
rc = install_bootloader(job, &bis);
free_bootloader(&bis);
break;
case job_ipl_tape:
rc = install_tapeloader(job->data.ipl_tape.device,
@@ -251,3 +238,57 @@ main(int argc, char* argv[])
job_free(job);
return abs(rc);
}
/**
* Program Component Footers
*/
struct component_footer component_footers[NR_PROGRAM_COMPONENTS] = {
[COMPONENT_ID_HEAP_AREA] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "heap area"
},
[COMPONENT_ID_STACK_AREA] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "stack area"
},
[COMPONENT_ID_LOADER_SIGNATURE] = {
.type = COMPONENT_TYPE_SIGNATURE,
.desc = "loader signature"
},
[COMPONENT_ID_LOADER] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "internal loader"
},
[COMPONENT_ID_PARAMETERS] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "parameters"
},
[COMPONENT_ID_IMAGE_SIGNATURE] = {
.type = COMPONENT_TYPE_SIGNATURE,
.desc = "image signature"
},
[COMPONENT_ID_KERNEL_IMAGE] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "kernel image"
},
[COMPONENT_ID_PARMLINE] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "parmline"
},
[COMPONENT_ID_RAMDISK_SIGNATURE] = {
.type = COMPONENT_TYPE_SIGNATURE,
.desc = "ramdisk signature"
},
[COMPONENT_ID_RAMDISK] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "initial ramdisk"
},
[COMPONENT_ID_ENVBLK] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "environment blk"
},
[COMPONENT_ID_SEGMENT_FILE] = {
.type = COMPONENT_TYPE_EXECUTE,
.desc = "segment file"
}
};