Compare commits

...

93 Commits

Author SHA1 Message Date
Jan Höppner
d6925a30da New release s390-tools-2.7.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-31 11:44:17 +01:00
Ingo Franzki
fe4cc7c479 zkey: add generated files to .gitignore
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-31 11:44:17 +01:00
Ingo Franzki
fa3cabc8af zkey: Makefile: Don't rebuild .o.d files on 'make install'
The .o.d make targets in common.mak do not expect that
header files are generated by a make target. When a new header
file is generated, the .o.d targets will be rebuilt on the
next make invocation, because that new header file is then
detected, and is then treated as a new dependency of all .o.d
targets.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-31 11:44:17 +01:00
Jan Höppner
5a9b56f814 lscss: Fix email address
The linux.vnet.ibm.com addresses will be become disfunct by eoy.

Signed-off-by: Stefan Raspl <raspl@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-31 11:44:17 +01:00
Julian Wiedmann
20145b6d06 qethqoat: add OSA-Express7S support
Add the missing identifiers to report the card name and link speed.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-25 13:42:12 +02:00
Ingo Franzki
9561a0b983 zkey: Enhance error message on key store open
Print a meaningful reason when the keystore can not be
accessed, e.g. because the user is not allowed to access
the keystore directory.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-25 11:00:52 +02:00
Philipp Rudo
97fa88299f zfcpdump: Remove unneeded include <zlib.h>
Dump compression was a feature of the file system dumper which was removed
several years ago. This include is a leftover. Remove it.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-25 11:00:52 +02:00
Jan Höppner
aaaebb2030 zpcictl: Change wording of man-page and help output
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-25 11:00:52 +02:00
Karsten Graul
ff2a403bd2 osasnmpd: remove unused code, improve readability
Remove unused code because query_OSA_EXP does actually never return -1.
So make its return value unsigned and remove all checks for negative
return values.

Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-25 11:00:52 +02:00
Karsten Graul
66ed1727f9 osasnmpd: start without real OSA devices
Osasnmpd would start without any devices, but refuses to start when all
devices are no real OSA devices.
Start osasnmpd in this case because it re-scans via update_mib_info
whenever the interface data changes.

Reviewed-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-25 11:00:52 +02:00
Ingo Franzki
c33cc5a619 zkey: Makefile: Avoid relink of modules during 'make install'
Because targets check-dep-zkey and check-dep-zkey-cryptsetup
do not produce any file, any targets that have a pre-req on those
targets are rebuilt during 'make install'.

Also correct .PHONY targets.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/46
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-22 14:02:35 +02:00
Karsten Graul
cd46297d7c s390-tools/utils: handle util_scandir errors correctly
The util_scandir_* functions may return 0 or -1, in which case no vector
is allocated in libutil/util_scandir.c. util_ptr_vec_free, called by
util_scandir_free or directly from lschp.c and lsscm.c, does always
call free for the vector which might be not initialized.

Fix this by always initializing the vector with NULL in __scandir and
add some api hardening by checking the vector and count in
util_ptr_vec_free before iterating over the vector.
And update the comment for util_scandir to indicate that -1 may be
returned in error cases plus that the vector is initialized with NULL.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/43
Reported-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-19 15:32:53 +02:00
Dimitri John Ledkov
07b11982e3 zdev: Trigger generic_ccw devices on any kernel module loads.
Generic CCW device can use any driver, and the value of the driver is
not known ahead of time. To avoid the race between loading and binding
a kernel module, and devices added - retrigger generic-ccw devices on
any kernel module load.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/37
Link: https://bugs.launchpad.net/ubuntu-z-systems/+bug/1794308
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/45

Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-19 15:32:40 +02:00
Dimitri John Ledkov
35348c302b zdev/initramfs: add s390-tools- prefix to hook, due to conflicts.
Unfortunately zdev hook already exists in Ubuntu, from an unrelated
project. ZFS uses zdev/zpool names, and ships a zdev hook to do ZFS
specific initialisation. It is available on s390x and thus results in
file-conflict upon installing both. Thus renaming this zdev hook to
s390-tools-zdev.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/41
Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-19 15:31:54 +02:00
Dimitri John Ledkov
35312d0c47 cpacfstatsd.service: only run on LPARs.
Add ConditionVirtualization=no to the service file such that it is
only started on LPARs. This service cannot run on z/VM nor KVM, and
fails resulting in a degraded boot.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/38
Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
Acked-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-19 15:31:40 +02:00
Jan Höppner
342c6a3707 zpcictl: Make device node for NVMe optional
At the moment, if we specify the slot address of an NVMe device but
can't find the corresponding device node, the execution is terminated.

This is a bit harsh as the device node is rather optional and only
necessary to collect S.M.A.R.T. data. We should still be able to issue
the error reporting, even if we couldn't determine the device node.

Therefore, make sure the device node for NVMe devices is optional by
changing various error messages to warnings.
Change sysfs_get_slot_addr() to have a return value and work with that
accordingly.
Also make sure, that execution is terminated when a valid device node
was specified but no matching slot address was determined. The slot
address is necessary to issue the error reporting commands.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Jan Höppner
e2a8d85916 zpcictl: Read device link to obtain device address
The address sysfs attribute might not be present on some older kernel
levels. Read the device link instead using readlink() to obtain the
address.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Jan Höppner
8f0496b26a zpcictl: Use fopen() instead of open() for writes
Be consistent with the rest of the code and use fopen() rather than
open().

Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Jan Höppner
d03be73536 zpcictl: Rephrase man page entries and tool output
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Michael Holzheu
a87268d62e util_path_example: Fix usage message
Document that for the "sysfs" invocation the mount point is optional.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Michael Holzheu
9cc06a0529 util_proc: Fix typos in description of util_proc_mnt_get_entry()
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Michael Holzheu
3b1ccce515 util_proc: Fix return code handling for util_proc_mnt_get_entry()
Correctly return -1 if the requested file system is not mounted.

Reported-by: Peter Morjan <peter.morjan@de.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Hans Wippel
ffe91d1b30 zdev: fix qeth BridgePort and VNICC conflict checking
This patch fixes false positives when attributes are checked for
conflicts between BridgePort and VNICC.

Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-10-11 14:41:32 +02:00
Hendrik Brueckner
f35c5d01fd zpcictl: include sys/sysmacros.h to avoid minor/major glibc warnings
The minor()/major() function definitions are moved to sys/sysmacros.h
and will be removed from sys/types.h.  To correct below warning, simply
include sys/sysmacros.h.

  zpcictl.c: In function ‘sysfs_get_slot_addr’:
  zpcictl.c:184:13: warning: In the GNU C Library, "major" is defined
   by <sys/sysmacros.h>. For historical compatibility, it is
   currently defined by <sys/types.h> as well, but we plan to
   remove this soon. To use "major", include <sys/sysmacros.h>
   directly. If you did not intend to use a system-defined macro
   "major", you should undefine it after including <sys/types.h>.
    major = major(dev_stat.st_rdev);
               ^~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
2018-10-02 09:55:27 +02:00
Jan Höppner
b23c35c390 zcryptctl: Add binary to .gitignore
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:54 +02:00
Jan Höppner
177cf8cfeb zpcictl: Introduce new tool zpcictl
zpcictl is used to manage PCI devices on z Systems. In this first
version it is mainly used to handle erroneous PCI devices by changing
their state and make those changes known to the SE. Log data, such as
S.M.A.R.T. data for NVMe devices, is sent alongside those state changes.

The state change is issued by sending data via the PCI 'report_error'
sysfs attribute. It's a binary attribute which will cause the host to
send an Adapter Notification Event.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:44 +02:00
Harald Freudenberger
f05f7d656b zcryptctl: new tool zcryptctl for multiple zcrypt node management
With the latest kernel comes an extension for the zcrypt
device driver to support multiple zcrypt device nodes.

Here is the userspace part of this which adds a new
application zcryptctl for user friendly management of
this feature.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:31 +02:00
Dan Horák
0bf4f1b957 zkey: Be explicit about linking the tools
I've met cases when the make's default rule for linking was used instead
omitting the ALL_LDFLAGS variable. The linking rule from common.mak is
defined for linking *.o files only, here we have libutil.a too.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/35
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:28 +02:00
Dan Horák
cd38119888 zkey: Be consistent when referring to libutil.a
Link: https://github.com/ibm-s390-tools/s390-tools/pull/35
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:21 +02:00
Dan Horák
cadef5c0ff zkey: Drop redundant include
Link: https://github.com/ibm-s390-tools/s390-tools/pull/35
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:15 +02:00
Dan Horák
02e1c783f6 Makefile: drop LOADLIBES variable
Remove deprecated LOADLIBES variable from the Makefile rules, LDLIBS
serves the same purpose these days.

Link: https://github.com/ibm-s390-tools/s390-tools/pull/35
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-29 12:41:08 +02:00
Eric Sandeen
07e30951f8 zipl: use FIEMAP mapping ioctl if it exists
zipl currently uses the FIBMAP ioctl to map blocks for the bootloader;
on XFS, if FIBMAP is requested on a reflinked file, it will fail -
and FIBMAP returns 0 in this case, which is indistinguishable from a
hole.  This causes boot to fail because the file is not mapped.

We can use the FIEMAP ioctl instead, which is able to map reflinked
files.  While FIEMAP is able to map entire extents at once, here we
simply use it to obtain the mapping block-by-block so that it fits
in with the current FIBMAP calls.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/34
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/36
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Tested-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:28:18 +02:00
Harald Freudenberger
0a0b4c3826 lszcrypt: support for alternate zcrypt device drivers
With kernel 4.19 there comes an extension to the existing
AP bus which supports alternate zcrypt drivers. For details
about this see kernel patch "s390/zcrypt: AP bus support for
alternate driver(s)". So now lszcrypt displays the driver
name in verbose mode. As some of the information displayed
by lszcrypt was based on sysfs attributes, which are only
available when the default zcrypt driver is bound to the
device, this also needed some rework. If a sysfs attribute
is not available because of an alternate driver binding
(or no driver) a question mark is printed into the field.

Together with this a slight rework of the displayed information
has been done. The two columns for pending requests and pending
replies has been merged to one pending column and the column
sizes have been adjusted.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:26:29 +02:00
Peter Oberparleiter
eade995185 zdsfs: Direct --help and --version output to stdout
zdsfs writes output for --help and --version to stderr. This is
likely because zdsfs calls into a FUSE function for additional
usage output that also writes to stderr (prior to FUSE 3.0.0).

To be consistent with other s390-tools and GNU coding guide lines,
fix this by using stdout for zdsfs generated output, and by
redirecting stderr to stdout before calling the FUSE function.

Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:23:47 +02:00
Peter Oberparleiter
0eba8d11df tape390_display: Direct --help output to stdout
tape390_display writes output for --help to stderr. To be consistent
with other s390-tools and GNU coding guide lines, fix this by using
stdout for tool-generated usage help.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:23:47 +02:00
Peter Oberparleiter
257490366b util_prg_example: Add --help and --version options
Add missing long options for --help and --version in util_prg_example.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:23:47 +02:00
Peter Oberparleiter
5ef1320a7b iucvconn/iucvtty: Direct --help output to stdout
Both iucvconn and iucvtty write output for --help to stderr. To be
consistent with other s390-tools and GNU coding guide lines,
fix this by using stdout for tool-generated usage help.

Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:23:47 +02:00
Peter Oberparleiter
f2f572fa70 hmcdrvfs: Direct --help and --version output to stdout
hmcdrvfs writes output for --help and --version to stderr. This is
likely because hmcdrvfs calls into a FUSE function for additional
usage output that also writes to stderr (prior to FUSE 3.0.0).

To be consistent with other s390-tools and GNU coding guide lines,
fix this by using stdout for hmcdrvfs generated output, and by
redirecting stderr to stdout before calling the FUSE function.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:23:47 +02:00
Peter Oberparleiter
e655f0cd7b cmsfs-fuse: Direct --help and --version output to stdout
cmsfs-fuse writes output for --help and --version to stderr. This is
likely because cmsfs-fuse calls into a FUSE function for additional
usage output that also writes to stderr (prior to FUSE 3.0.0).

To be consistent with other s390-tools and GNU coding guide lines,
fix this by using stdout for cmsfs-fuse generated output, and by
redirecting stderr to stdout before calling the FUSE function.

Also remove an inactive call to add FUSE version output on --version to
be consistent with other FUSE-based s390-tools.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-17 14:23:47 +02:00
Peter Oberparleiter
68b46eea7a zipl: Add missing build dependency
Building zipl from outside the zipl/ sub-directory fails due to a
missing dependency:

  # cd s390-tools
  # make -C zipl/src/ zipl
  boot.c:18:10: fatal error: ../boot/data.h: No such file or directory
   #include "../boot/data.h"

This is because boot/data.h needs to be generated before src/boot.c can
be compiled. Fix this by adding the missing dependency to the zipl
Makefile.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Ingo Franzki
9894e391ef zkey: Man page correction
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
5982fd98bf CHANGELOG: lstape, lsluns: handle non-zfcp; lin_tape multiple paths
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
d5291eed1c lstape: fix SCSI HBA CCW device bus-ID e.g. for virtio-scsi-ccw
Get the SCSI HBA device bus-ID in general for HBAs on the CCW bus.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
34260f1736 lstape: fix SCSI output description in man page
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
b9b3d2d230 lstape: fix description of --type and <devbusid> filter for channel tapes
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
4cf8f5f46c lstape: fix to prevent error messages if there are non-zfcp SCSI devices
Assume "N/A" for non-zfcp SCSI devices, such as iSCSI or virtio-scsi-ccw,
to not erroneously access absent zfcp-specific sysfs attributes.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
eba744a25e lsluns: fix to prevent error messages if there are non-zfcp SCSI devices
Simply skip non-zfcp SCSI devices, such as iSCSI or virtio-scsi-ccw,
to not erroneously access absent zfcp-specific sysfs attributes.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
80e0c41b89 lstape: fix output without SCSI generic (sg)
The default bash setting have nullglob disabled so if
$SCSI_DEV/scsi_generic*
aka
/sys/bus/scsi/devices/*:*:*:*/scsi_generic*
does not match anything, it leaves the glob pattern unmodified and
SG_DEV=$(basename $SG_DEV/*)
results in the literal:
*
If $SG_INQ exists, it invoked sg_inq with more than the one allowed
positional argument for a SCSI generic device node:
sg_inq /dev/*
Causing error messages and the usage of sg_inq to land in $TAPE_SERIAL.

To not have to rely on the nullglob setting, explicitly check for the
existence of $SCSI_DEV/scsi_generic before evaluating
SG_DEV=$(basename $SG_DEV/*).

Also handle availability of sg_inq but absence of scsi_generic
individually to provide the user with a hint if only sg is missing.

Suggested-by: Eric Farman <farman@linux.vnet.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Cc: Eric Farman <farman@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
cdc787db1b lstape: fix to prefer sysfs to find lin_tape device name for SCSI device
This should be more stable than parsing the IBM lin_tape proc-fs output.
If sysfs is not available or provides no match, fall back to proc-fs.

An alternative to "ls -1d ... | head -n1" would have been to use
"shopt -s extglob; ls -d $SCSI_DEV/lin_tape/$DEV_NAME+([0-9])"
but I did not want to have to rely on extglob potentially influencing
other old code of lstape.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Steffen Maier
ef4dc7a45b lstape: fix output with SCSI lin_tape and multiple paths to same tape/changer
https://www.ibm.com/developerworks/linux/linux390/s390-tools-1.8.0.html
before the first upstream commit b627b8d8e1 ("Initial s390-tools-2.0.0
import") introduced SCSI tape/changer output for lstape. It used the SCSI
device serial number as lookup key to find a match in IBM lin_tape device
driver proc-fs output for a given SCSI device name. Since multiple paths
to the same tape/changer have the same serial number, multiple matches can
occur and distort the output:

% lstape
...
SCSI tape devices (found 12):
...
Generic Device        Target       Vendor   Model            Type     State
sg0     IBMtape0      3            0:0:0:0  IBM              ULT3580-TD6 tapedrv
running
sg1     IBMchanger0   1            2        3                0:0:0:1  IBM
3573-TL changer       running
...

There are unexpected additional Device suffix numbers for each additional
path of the same tape/changer (independent of actual path failover
enablement in lin_tape). The multiple matches above cause excess arguments
to printf. Explaining the resulting output, the bash man page says:
"The format is reused as necessary to consume all of the arguments."
This also causes a wrong number of found devices.

Current lin_tape (v3.0.31) uses the printf format string
"%-8d%-12s%-25s%-16s%-16s%-10s" for fixed column proc-fs output.
This causes the following example input to lstape:

==> /proc/scsi/IBMchanger <==
lin_tape version: 3.0.31
lin_tape major number: 251
Attached Changer Devices:
Number  model       SN                       HBA             SCSI            FO Path
0       3573-TL     00L4U78W6497_LL0         Virtio SCSI HBA 0:0:0:1         Primary
1       3573-TL     00L4U78W6497_LL0         Virtio SCSI HBA 0:0:1:1         Alternate
2       3573-TL     00L4U78W6497_LL0         Virtio SCSI HBA 1:0:1:1         Alternate
3       3573-TL     00L4U78W6497_LL0         Virtio SCSI HBA 1:0:0:1         Alternate

==> /proc/scsi/IBMtape <==
lin_tape version: 3.0.31
lin_tape major number: 251
Attached Tape Devices:
Number  model       SN                       HBA             SCSI            FO Path
0       ULT3580-TD6 10WT037733               Virtio SCSI HBA 0:0:0:0         Primary
1       ULT3580-TD6 10WT037701               Virtio SCSI HBA 0:0:1:0         Primary
2       ULT3580-TD6 10WT037701               Virtio SCSI HBA 1:0:1:0         Alternate
3       ULT3580-TD6 10WT037733               Virtio SCSI HBA 1:0:0:0         Alternate

If that was reliable and stable, we could use fixed column parsing:
			IBM_IDX=$(
				awk 'BEGIN {
					FIELDWIDTHS="8 12 25 16 16 10"
				}
				gensub(" ","","g",$5) == "'$SCSI_ID'"{
					print gensub(" ","","g",$1)
				}' /proc/scsi/$DEV_NAME
			)
However, we can hardly guarantee a field value always fits into the left-
adjusted columns (printf won't cap to field width!). Also, the fixed column
format changed between lin_tape v3.0.20 and v3.0.18 from
"%-8d%-12s%-18s%-16s%-16s%-10s" with less width for the 'SN' field.
The column format also changed between v2.2.0 and v1.37.0 from
"%-8d%-12s%-18s%-32s%-10s" where the 'SCSI' field did not even exist.
Likely that was the reason for the original Serial lookup in lstape.

As can be seen in the example, at least the HBA device driver string can
contain whitespace and breaks the field numbers with tokenized parsing.
We want to match column 5 (SCSI) but above we would match against the
string 'SCSI' as part of "Virtio SCSI HBA" instead of e.g. '0:0:0:0'.

The following works currently knowing that the last two columns do not
contain white space. But it can also fail if the value of field
'HBA' does not fit into the left-adjusted columns so there is no white
space between columns 'HBA' and 'SCSI' making them collapse:
awk '$(NF-1) == "'$SCSI_ID'" { print $1 }' /proc/scsi/$DEV_NAME

Grep for the SCSI device name as word (to skip names with same substring,
such as 0:0:1:1 also matching 0:0:1:10) and cut the first field 'Number'.
If there is no SCSI column at all (and no SCSI LLDD or other column with a
name accidentally matching an existing SCSI device name), we get no match
and better bail out with the initialized "N/A" for the lstape column
"Device". If the SCSI column exists, the SCSI device names are unique and
we always get at most one match.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
cb3e949772 zfcpdump: Fix incompatible cast compile warning
When zfcpdump is built you get a compile warning

zfcpdump.c: In function ‘init_sig’:
zfcpdump.c:307:24: warning: cast between incompatible function types from ‘void (* (*)(int,  siginfo_t *, void *))(int)’ {aka ‘void (* (*)(int,  struct <anonymous> *, void *))(int)’} to ‘void (*)(int)’ [-Wcast-function-type]
  g.sigact.sa_handler = (__sighandler_t)dump_sig_handler;

Furthermore the man pages for sigaction says

$man 2 sigaction
[...]
       If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead
       of sa_handler) specifies the signal-handling function for signum.
       This function receives three arguments, as described below.
[...]

Because SA_SIGINFO is set, using sa_handler at all is wrong in this case.

Fix this by giving dump_sig_handler the correct return type and assign it
to sa_sigaction.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
f02de298c1 zfcpdump: Remove module load
The zfcpdump kernel is built without module support. Furthermore the initrd
doesn't contain modprobe. So trying to load modules using modprobe in
zfcpdump userspace doesn't really make sense.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
eb0dc13c88 zfcpdump: Add install script for zfcpdump
Since version 198 (Feb 2013) systemd contains kernel-install, a script
managing kernel installs. This script allows execution of drop-in scripts
for customization. Add such a drop-in script to s390-tools to handle the
installation of zfcpdump kernels.

It's main purpose is to manage a link to the latest installed zfcpudump
kernel at ZFCPDUMP_IMAGE, where zipl expects to find the image to install
for a SCSI dumper.

The script supports two installation modes. One recommended by the
BootLoaderSpecs [1] to /boot/<machine-id>/<kernel-version> directories and
one directly to /boot. In the second case files are renamed during
installation to <original-name>-<kernel-version> to guarantee unique names.

Because the zfcpdump kernel is so special make the script stand-alone and
prevent any other script from being executed (exit 77) when a zfcpdump is
installed. Especially avoid functionality like creating an initrd (already
provided by s390-tools) or creating a boot entry (the zfcpdump kernel
should not be used for any other purpose than dumping).

The script requires systemd >= 203.

[1] https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
d08bd23c1e zipl: Move macro definition to Makefile
In the zipl Makefile macros are defined with the sole purpose to define
other macros in zipl.h. Remove this unnecessary indirection.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
724f1fea2c Makefile: Rename ZFCPDUMP_PART_* macros
The file system dumper no longer exists. So there is no need in keeping
'PART' to distinguish between the file system and the partition dumper.
Adjust the macro name to the usage in zipl by removing 'PART'.

While at it also adjust the file names the macros stand for.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
dcc63e6dfc zipl: Rename FSDUMP_PART_* macros
The macro names are a mixture of the original file system dumper (FSDUMP)
and its extension to cut the file system and write directly to a partition
(PART). The original dumper no longer exists and today the feature is
called zfcpdump. Prevent confusion by renaming the macros to fit todays
usage.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Philipp Rudo
576034e94a zfcpdump: Remove unused macros
There are no more users for these macros. Remove them.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Jan Höppner
3ec49ba7bd Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-09-04 14:09:24 +02:00
Jan Höppner
60c687238d New release s390-tools-2.6.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 12:41:17 +02:00
Sebastian Ott
57b992ffa1 lscss: document behavior of subchannels bound to alternate drivers
Provide information on how subchannels bound to vfio_ccw are displayed.

Reported-by: Cornelia Huck <cohuck@redhat.com>
Link: https://github.com/ibm-s390-tools/s390-tools/issues/32
Fixes: #32
Signed-off-by: Sebastian Ott <sebott@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 12:41:17 +02:00
Ingo Franzki
1f07a41d5a zkey: Add volume-type property to support LUKS2 volumes
Allow to specify a volume-type for a key. This applies to all
associated volumes. The volume type can be either 'plain' or
'luks2'. New keys created will default to 'luks2', but existing
keys that do not have a volume-type property default to 'plain'
for compatibility reasons.

The volume type 'luks2' is only available when the define
HAVE_LUKS2_SUPPORT is set in the makefile. This is set only
when libcryptsetup version 2.0.3 or newer is available
at build time. If the define is not set, the volume-type
option is not available to the user, and the volume-type of
a key defaults to 'plain'.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 12:41:12 +02:00
Ingo Franzki
512b47c004 zkey: Add key verification pattern property
Store a verification pattern in the properties file along
with the secure key. The verification pattern allows to identify
the inner key even when the secure key is no longer valid.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Ingo Franzki
818ffbc4b0 zkey: Add build dependency for libcryptsetup and json-c
The zkey-cryptsetup tool has a build dependency to
libcryptsetup version 2.0.3 or later, and json-c.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Ingo Franzki
5e65df7375 zkey: Add man page for zkey-cryptsetup
Add documentation for the new zkey-cryptsetup tool

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Ingo Franzki
4eb80d14a0 zkey: Add zkey-cryptsetup tool
The zkey-cryptsetup tool is used to validate and re-encipher
secure AES volume keys of volumes encrypted with LUKS2 and
the paes cipher.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Viktor Mihajlovski
7247a61e0b netboot: add BOOTIF support
The IPAPPEND option in the pxelinux config file can be used
to pass information about the boot interface to the booted
Linux kernel.

The support for this option was missing and could lead to
installation failures, e.g. using kickstart.

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Viktor Mihajlovski
c856f28e11 netboot: Send client architecture and handle path prefix
Client architecture aware DHCP configurations may send a
bootfile for the wrong architecture, if the DHCP request
doesn't include the client architecture identifier 0x001f.

Further, the DHCP reply may include the pxepathprefix option,
which points to the base directory to use for TFT requests.
If the value is not honored by the client, the wrong
configuration file, kernel, etc. could be loaded.

Both issues are fixed by this commit.

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Viktor Mihajlovski
ca30cfd341 netboot: Include compressed kernel modules in initramfs
Compressed kernel modules (filename *.ko.xz) would not be included
since the script was looking for files with .ko suffix only.

This can result in a pxelinux.0 image that can't access the
network, which is not good for a network boot loader...

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-08-10 10:42:18 +02:00
Gerald Schaefer
58ecf1f363 mon_procd: fix parsing of /proc/<pid>/stat
The output of /proc/<pid>/stat will show the process name in parentheses.
The parsing code in read_stat() tries to filter out the parentheses, which
will go wrong when the process name itself also contains parentheses, e.g.
in an output like this: "2421 ((sd-pam)) S 2420 2420 2420 ..."

In this case, the first closing parentheses will be taken as end marker,
and the sscanf() on the remaining string will silently fail, leaving its
values in uninitialized state and producing wrong data.

Fix this by using strrchr() instead of strchr() to find the last closing
parentheses. Also add return value checking for sscanf() and initialize the
values to 0.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-07-04 13:10:20 +02:00
Sa Liu
d36ff82999 dbginfo: Add VM command query time. Corrected error messages.
Signed-off-by: Sa Liu <saliu@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-07-04 13:09:58 +02:00
Dimitri John Ledkov
d4398aea89 zdev: Adjust zdev modprobe path to be compatible with split-usr systems.
mk-pxelinux-ramfs, mod_fsstatd|procd.service, zfcpdump all use
/sbin/modprobe path. Adjust zdev to use that path as well. This works
universally on both usr-merge systems (e.g. Debian/Ubuntu with
usrmerge package installed), and split-usr systems alike
(Debian/Ubuntu current stable releases default).

Closes: #31
Link: https://bugs.launchpad.net/ubuntu/+source/s390-tools/+bug/1777600
Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-22 17:25:06 +02:00
Ingo Franzki
672548ce30 zkey: Fix generate and import leaving key in an inconsistent state
When a volume or APQN association is made while generating or
importing a key, and a duplicate association is detected, then
this may leave the key in an inconsistent state.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-22 17:25:06 +02:00
Ingo Franzki
344965bd29 zkey: Fix APQN validation routine
When a zkey generate or change command is used to associate one
or multiple APQNs the command succeeds, but no key is generated
and no APQNs are associated, because the return code returned by
_keystore_apqn_check() is wrong.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-22 17:25:06 +02:00
Ingo Franzki
d6a96f07c1 zkey: Fix memory leak
The APQN check routine as well as the properties helper functions
do not free all memory that they allocated.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-22 17:25:06 +02:00
Jan Höppner
6a99d95d4f Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-22 17:25:06 +02:00
Jan Höppner
3f1bd3bb66 New release s390-tools-2.5.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Dan Horák
0fbc4edd29 zipl: Compute the bootloader stage size to workaround PIE
Closes: #30
Signed-off-by: Dan Horák <dan@danny.cz>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Javier Martinez Canillas
b8a9f0d1d3 scripts: Add script to switch zipl config to a BootLoaderSpec setup
Add a zipl-switch-to-blscfg script that can be used to switch the zipl
configuration in a system to use the BootLoaderSpec (BLS) config files
to define the IPL sections instead of having them defined in zipl.conf.

Closes: #28
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Javier Martinez Canillas
d280e5b1fa zipl: Add BootLoaderSpec support
The BootLoaderSpec (BLS) defines a file format for boot configurations,
so bootloaders can parse these files and create their boot menu entries
by using the information provided by them [0].

This allow to configure the boot items as drop-in files in a directory
instead of having to parse and modify a bootloader configuration file.

If the /boot/loader/entries exists and there are BLS files there, then
these are parsed and configuration sections are added without the need
to have these in a zipl.conf file.

A different BLS directory can be specified from the command line using
the --blsdir option.

[0]: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/

GitHub-ID: #28
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Javier Martinez Canillas
e04acab0ed zipl: Return number of allocated tokens in scan_file()
The function returns 0 on success and a negative number on error but is
useful to know how many tokens were allocated. This will be used by the
BLS parsing code to determine if needs to allocate mor tokens or not to
parse the BLS fragments.

GitHub-ID: #28
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Jens Remus
d868ce5ec7 lsluns: print a message if no adapter or port exists
lsluns lists nothing and returns with return code 0 if no adapter (FCP
device) or target port exists in sysfs. This can be confusing for the user.

Print a message if no adapter exists. Print a message if no port exists on
any adapter.

Reported-by: Thorsten Diehl <thorsten.diehl@de.ibm.com>
Suggested-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Ingo Franzki
dec58c349e zkey: Typo in message
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
d82f5e1f49 zdev: Fix blocking chzdev call/udev rules with cmb_enable
Changing the cmb_enable attribute of a CCW device can cause a blocked
chzdev process or udev rule. This problem occurs when the device is
offline, cmb_enable is 0, and chzdev is used to set cmb_enable=1 and
online=1 at the same time.

The following call will block:

chzdev 190d -a cmb_enable=1 online=1

The following call will generate a udev rule that will block subsequent
calls to 'udevadm settle':

chzdev 190d -p online=1 cmb_enable=1

Fix this by ensuring that cmb_enable is only set when the CCW device
is not online.

Reported-by: André Wild <wild@linux.vnet.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
156450f359 zdev: Implement support for early device configuration
Enable user to specify that a device should be configured early, that is
during the initial RAM-disk boot phase. This may be necessary, e.g. to
override auto-configuration for a device which is also applied during
that boot phase. It may also be used to manually specify devices that
are required to access the root file system, such as networking devices.

Users can mark devices as requiring early configuration by specifying
a value of 1 for the newly added internal attribute zdev:early:

 # chzdev dasd-eckd 0.0.1234 -p zdev:early=1

This can be changed back by removing the attribute setting, or by
setting the attribute value to 0:

 # chzdev dasd-eckd 0.0.1234 -p -r zdev:early

or

 # chzdev dasd-eckd 0.0.1234 -p zdev:early=0

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
c0392efa39 zdev: Implement internal device attributes
This change adds base infrastructure for implementing internal device
attributes. In the context of the zdev tools, an internal device
attribute is a new type of device attribute with the following
characteristics:

  - Can be set and removed like normal device attributes
  - Affects zdev-internal handling only
  - Does not correspond to an actual device attribute, that is
    it has no representation in SysFS
  - Can not be set in the active configuration
  - Name starts with "zdev:" to prevent conflicts with actual
    device attributes

Values for internal device attributes are stored in udev rules alongside
the normal persistent configuration of a device. They are encoded as
udev environment variables. Note that they have no further effect on
udev processing.

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
3c5644ccfd zdev: Integrate firmware auto-configuration with initramfs-tools
Add initramfs-tools scripts that apply firmware-provided I/O
configuration data as auto-configuration during boot. This way, all I/O
devices configured by DPM are automatically brought online without
further user interaction.

This mechanism is active by default. It can be deactivated by specifying
the following parameter on the kernel command line:

  rd.zdev=no-auto

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
3fb356ebd2 zdev: Integrate firmware auto-configuration with dracut
Add a dracut hook that applies firmware-provided I/O configuration data
as auto-configuration during boot. This way, all I/O devices configured
by DPM are automatically brought online without further user
interaction.

This mechanism is active by default. It can be deactivated by specifying
the following parameter on the kernel command line:

  rd.zdev=no-auto

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
fe68ec513d zdev: Add support for handling auto-configuration data
Auto-configuration is the name of a new configuration target that is
supported by chzdev and lszdev besides the existing active and
persistent configuration targets. Directives created in this new
configuration are stored as udev rules in the /run/udev/rules.d
directory.

Auto-configuration directives are only in effect if there are no
directives for the same device in the user-provided persistent
configuration. This allows users to override auto-configuration
directives if necessary.

Due to the volatile nature of the /run directory, auto-configuration
directives are cleared on reboot. Therefore mechanisms that generate
auto-configuration directives must recreate them on every boot.

The lszdev tool displays auto-configuration data both in list view
as well as in detail view. Users can specify the new option --auto-conf
to only show data from this configuration target.

Mechanisms that generate automated configuration directives can use
chzdev together with the --auto-conf option to create the corresponding
udev rules.

Note: This change does not include a mechanism that generates
      auto-configuration directives.

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
a86fb8b091 zdev: Write zfcp-lun udev rules to separate files
Change chzdev's udev rule generation from the previous approach of
combining all zfcp-lun udev rules associated with an FCP device into a
single file to storing zfcp-lun udev rules in one file per zfcp-lun.
This is done to enable per-device udev rule masking.

With udev rule masking, if a udev rule file by the same name exists in
both /etc and /run, the udev daemon will only consider the rules found
in /etc.

The auto-configuration feature will make use of per-device udev rule
masking to introduce a new class of configuration data (stored in /run)
that is only active if no user-provided configuration data (in /etc)
exists.

In addition, change chzdev to allow the regeneration of udev rules by
using the --force command line like in the following example:

 # chzdev zfcp-lun --configured --enable --persistent --force

This can be used to convert all existing zfcp-lun udev rules from the
old format to the new one.

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
f32bff9688 zdev: Implement --no-settle
There are some situations where running "udevadm settle" can result in
a deadlock, such as in the early stages of initial RAM-disk processing.

Introduce a new command-line option --no-settle that can be used to
suppress calling "udevadm settle" to allow chzdev to be run in such
situations.

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
7d355b0fec zdev: Add support for reading firmware configuration files
Add support for reading firmware-provided I/O configuration data files.
Such configuration files are generated by the Dynamic Partition Manager
and made available via a kernel interface for consumption by Linux.

To read a firmware configuration file, use the existing --import option:

 # chzdev --import /sys/firmware/sclp_sd/config/data

This will apply all I/O configuration data found in the specified file
to the persistent configuration.

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Peter Oberparleiter
ab4445c261 zdev: Prepare for firmware configuration file support
Apply some changes to existing functions and data structures to simplify
the firmware configuration file support implementation.

 - Make qeth and dasd subtype objects non-static
 - Change the existing helper functions for reading file contents into
   memory to also support binary functions
 - Move some configuration file import functions to make them available
   for use in other source files

Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
Jan Höppner
e14363373b Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-06-08 15:03:30 +02:00
125 changed files with 8995 additions and 901 deletions

9
.gitignore vendored
View File

@@ -68,6 +68,7 @@ zconf/qeth/lsqeth
zconf/scm/lsscm
zconf/zcrypt/chzcrypt
zconf/zcrypt/lszcrypt
zconf/zcrypt/zcryptctl
zdev/src/chzdev
zdev/src/chzdev_usage.c
zdev/src/lszdev
@@ -76,7 +77,8 @@ zdsfs/zdsfs
zdump/zgetdump
zfcpdump/cpioinit
zfcpdump/zfcpdump_part
zfcpdump/zfcpdump_part.rd
zfcpdump/zfcpdump-initrd
zfcpdump/10-zfcpdump.install
ziomon/ziomon_mgr
ziomon/ziomon_util
ziomon/ziomon_zfcpdd
@@ -89,3 +91,8 @@ zipl/src/chreipl_helper.device-mapper
zipl/src/zipl
zipl/src/zipl_helper.device-mapper
zkey/zkey
zkey/zkey-cryptsetup
zkey/check-dep-zkey
zkey/check-dep-zkey-cryptsetup
zkey/detect-libcryptsetup.dep
zpcictl/zpcictl

View File

@@ -16,8 +16,10 @@ List of all individuals having contributed content to s390-tools
- Clemens von Mann
- Dan Horak
- Despina Papadopoulou
- Dimitri John Ledkov
- Eberhard Pasch
- Einar Lueck
- Eric Sandeen
- Erwin Vicari
- Eugene Crosser
- Eugene Dvurechenski
@@ -45,6 +47,7 @@ List of all individuals having contributed content to s390-tools
- Jan Glauber
- Jan Hoeppner
- Jan Willeke
- Javier Martinez Canillas
- Jean-Baptiste Joret
- Jens Remus
- Jochen Roehrig

View File

@@ -1,5 +1,55 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.7.0 (2018-10-31)__
For Linux kernel version: 4.19
Add new tool:
- zcryptctl: Add zcryptctl for multiple zcrypt node management
- zpcictl: Add zpcictl for reporting defective PCI devices
Changes of existing tools:
- qethqoat: Add OSA-Express7S support
- lszcrypt: Add support for alternative zcrypt device drivers
- zfcpdump: Add install script for zfcpdump
- zipl: Make zipl work with XFS by using the FIEMAP mapping ioctl
Bug Fixes:
- lstape: Fix output with SCSI lin_tape and multiple paths to same unit
- lstape: Fix output without SCSI generic (sg)
- lsluns: Fix to prevent error messages if there are non-zfcp SCSI devices
- lstape: Fix to prevent error messages if there are non-zfcp SCSI devices
- lstape: Fix description of --type and <devbusid> filter for channel tapes
- lstape: Fix SCSI output description in man page
- lstape: Fix SCSI HBA CCW device bus-ID e.g. for virtio-scsi-ccw
- Direct --help and --version output to stdout for several tools
- osasnmpd: Start without real OSA devices
* __v2.6.0 (2018-08-10)__
For Linux kernel version: 4.18
Add new tool:
- zkey: Add zkey-cryptsetup tool
Changes of existing tools:
- netboot: add BOOTIF support
Bug Fixes:
- mon_procd: fix parsing of /proc/<pid>/stat
- netboot: Include compressed kernel modules in initramfs
- netboot: Send client architecture and handle path prefix
* __v2.5.0 (2018-06-08)__
For Linux kernel version: 4.17
Changes of existing tools:
- zdev: Add support for reading firmware configuration files
- zipl: Add BootLoaderSpec support
- scripts: Add script to switch zipl config to a BootLoaderSpec setup
Bug Fixes:
- lsluns: Print a message if no adapter or port exists
* __v2.4.0 (2018-05-07)__

View File

@@ -8,7 +8,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
all: $(TOOL_DIRS)

View File

@@ -265,12 +265,15 @@ build options:
| net-snmp | `HAVE_SNMP` | osasnmpd |
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
| openssl | `HAVE_OPENSSL` | zkey |
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
| json-c | `HAVE_JSONC` | zkey-cryptsetup |
This table lists additional build or install options:
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|----------------|:----------------:|:-------------------------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
The s390-tools build process uses "pkg-config" if available and hard-coded
compiler and linker options otherwise.
@@ -370,9 +373,12 @@ the different tools are provided:
* zkey:
For building the zkey tools you need openssl version 0.9.7 or newer installed
(openssl-devel.rpm). Tip: you may skip the zkey build by adding
`HAVE_OPENSSL=0` to the make invocation.
(openssl-devel.rpm). Also required are cryptsetup version 2.0.3 or newer
(cryptsetup-devel.rpm), and json-c version 0.12 or newer (json-c-devel.rpm).
Tip: you may skip the zkey build by adding `HAVE_OPENSSL=0`, and you may
may skip the zkey-cryptsetup build by adding `HAVE_CRYPTSETUP2=0`, or
`HAVE_JSONC=0` to the make invocation.
A new group 'zkeyadm' needs to be created and all users intending to use the
tool must be added to this group. The owner of the default key repository
tool must be added to this group. The owner of the default key repository
'/etc/zkey/repository' must be set to group 'zkeyadm' with write permission
for this group.
for this group.

View File

@@ -76,7 +76,7 @@ static const struct fuse_opt cmsfs_opts[] = {
static void usage(const char *progname)
{
fprintf(stderr,
fprintf(stdout,
"Usage: %s DEVICE MOUNTPOINT [OPTIONS]\n"
"\n"
"Use the cmsfs-fuse command to read and write files stored on a z/VM CMS disk.\n"
@@ -4498,14 +4498,23 @@ static int cmsfs_process_args(void *data, const char *arg, int key,
return 1;
case KEY_HELP:
usage(outargs->argv[0]);
/*
* Usage output needs to go to stdout to be consistent with
* coding guidelines. FUSE versions before 3.0.0 print help
* output to stderr. Redirect stderr to stdout here to enforce
* consistent behavior.
*/
fflush(stderr);
dup2(STDOUT_FILENO, STDERR_FILENO);
fuse_opt_add_arg(outargs, "-ho");
cmsfs_fuse_main(outargs, &cmsfs_oper);
exit(0);
case KEY_VERSION:
fprintf(stderr, COMP "FUSE file system for CMS disks "
fprintf(stdout, COMP "FUSE file system for CMS disks "
"program version %s\n", RELEASE_STRING);
fprintf(stderr, "Copyright IBM Corp. 2010, 2017\n");
fuse_opt_add_arg(outargs, "--version");
fprintf(stdout, "Copyright IBM Corp. 2010, 2017\n");
exit(0);
default:

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 = 4
RELEASE = 7
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -182,9 +182,10 @@ GROUP = $(shell id -gn)
export INSTALLDIR BINDIR LIBDIR MANDIR OWNER GROUP
# Special defines for zfcpdump
ZFCPDUMP_PART_IMAGE = zfcpdump_part.image
ZFCPDUMP_PART_RD = zfcpdump_part.rd
export ZFCPDUMP_DIR ZFCPDUMP_PART_IMAGE ZFCPDUMP_PART_RD
ZFCPDUMP_IMAGE = zfcpdump-image
ZFCPDUMP_INITRD = zfcpdump-initrd
ZFCPDUMP_FLAVOR = zfcpdump
export ZFCPDUMP_DIR ZFCPDUMP_IMAGE ZFCPDUMP_INITRD ZFCPDUMP_FLAVOR
CFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
HOSTCFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
@@ -239,7 +240,7 @@ endif
$(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@
%: %.o
$(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
%.a:
$(AR) rcs $@ $^

View File

@@ -7,7 +7,7 @@ LDLIBS += -lm
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
cpuplugd: $(OBJECTS)
$(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
clean:
rm -f cpuplugd $(OBJECTS)

View File

@@ -1338,7 +1338,7 @@ static int hmcdrv_fuse_main(struct fuse_args *args)
*/
static void hmcdrv_fuse_usage(const char *progname)
{
fprintf(stderr,
fprintf(stdout,
"Usage: %s MOUNTPOINT [OPTIONS]\n\n"
"Use the %s command to read files from a HMC drive DVD.\n"
"\n"
@@ -1450,7 +1450,7 @@ static int hmcdrv_fuse_optproc(void *data, const char *arg,
return 1;
case HMCDRV_FUSE_OPTKEY_VERSION:
fprintf(stderr, HMCDRV_FUSE_LOGHEAD
fprintf(stdout, HMCDRV_FUSE_LOGHEAD
"HMC drive DVD file system, version %s\n"
"Copyright IBM Corp. 2015, 2017\n",
HMCDRV_FUSE_RELEASE);
@@ -1458,6 +1458,16 @@ static int hmcdrv_fuse_optproc(void *data, const char *arg,
case HMCDRV_FUSE_OPTKEY_HELP:
hmcdrv_fuse_usage(outargs->argv[0]);
/*
* Usage output needs to go to stdout to be consistent with
* coding guidelines. FUSE versions before 3.0.0 print help
* output to stderr. Redirect stderr to stdout here to enforce
* consistent behavior.
*/
fflush(stderr);
dup2(STDOUT_FILENO, STDERR_FILENO);
fuse_opt_add_arg(outargs, "-ho");
hmcdrv_fuse_main(outargs);
exit(EXIT_SUCCESS);

View File

@@ -42,6 +42,9 @@ static inline void util_ptr_vec_free(void **ptr_vec, int count)
{
int i;
if (!ptr_vec || count < 0)
return;
for (i = 0; i < count; i++)
free(ptr_vec[i]);
free(ptr_vec);

View File

@@ -6,7 +6,7 @@ objects = main.o ccw.o fcp.o system.o shutdown.o \
cmd_lsshut.o cmd_chshut.o cmd_lsreipl.o cmd_chreipl.o proc.o
chreipl: $(objects)
$(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
lsreipl:
ln -sf chreipl lsreipl

View File

@@ -75,9 +75,11 @@ static const struct tool_info iucv_tool[2] = {
static void __noreturn usage_exit(const struct tool_info *prg, int is_error,
const char *msg)
{
FILE *file = is_error ? stderr : stdout;
if (msg != NULL)
fprintf(stderr, _("%s: %s\n"), prg->name, msg);
fprintf(stderr, _(prg->usage), prg->name, prg->name);
fprintf(file, _("%s: %s\n"), prg->name, msg);
fprintf(file, _(prg->usage), prg->name, prg->name);
exit(is_error ? 1 : 0); /* rc=1 .. invalid args */
}

View File

@@ -90,7 +90,7 @@ static void test_util_path_is_xxx(void)
}
/*
* Usage: util_path_example [sysfs mount point] | "is_xxx"
* Usage: util_path_example sysfs [MOUNT_POINT] | is_xxx
*/
int main(int argc, char *argv[])
{
@@ -111,6 +111,6 @@ int main(int argc, char *argv[])
}
return EXIT_SUCCESS;
out_fail:
errx(EXIT_FAILURE, "Usage: %s sysfs <path> | is_xxx", argv[0]);
errx(EXIT_FAILURE, "Usage: %s sysfs [MOUNT_POINT] | is_xxx", argv[0]);
}
//! [code]

View File

@@ -34,6 +34,12 @@ const struct util_prg prg = {
}
};
static const struct option opt_list[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ NULL, no_argument, NULL, 0 },
};
/*
* Demonstrate the util_prg_print() functions
*/
@@ -49,7 +55,7 @@ int main(int argc, char *argv[])
util_prg_init(&prg);
while ((opt = getopt(argc, argv, "vhe")) != -1) {
while ((opt = getopt_long(argc, argv, "vhe", opt_list, NULL)) != -1) {
switch (opt) {
case 'v':
util_prg_print_version();

View File

@@ -442,9 +442,9 @@ util_proc_dev_get_entry(dev_t device, int blockdev,
/*
* Provide one record form a /proc/mounts like file
* Provide one record from a /proc/mounts like file
*
* The parameter file_name distinguishes the file form procfs which
* The parameter file_name distinguishes the file from procfs which
* is read, the parameter spec is the selector for the record.
*/
int util_proc_mnt_get_entry(const char *file_name, const char *spec,
@@ -456,7 +456,6 @@ int util_proc_mnt_get_entry(const char *file_name, const char *spec,
rc = get_file_buffer(&file, file_name);
if (rc)
return rc;
rc = -1;
while (!eof(&file)) {
rc = scan_mnt_entry(&file, entry);
if (rc)
@@ -467,6 +466,7 @@ int util_proc_mnt_get_entry(const char *file_name, const char *spec,
}
util_proc_mnt_free_entry(entry);
}
rc = -1;
out_free:
free_file_buffer(&file);
return rc;

View File

@@ -59,6 +59,7 @@ static int __scandir(struct dirent ***de_vec, const char *path,
int count = 0;
DIR *dirp;
*de_vec = NULL;
dirp = opendir(path);
if (!dirp)
return -1;
@@ -134,13 +135,13 @@ int util_scandir_hexsort(const struct dirent **de1, const struct dirent **de2)
* directory entries. The entries as well as the pointer array itself are
* allocated by the function and has to be released by the user via free.
*
* @param[out] de_vec Vector of matched directory entries
* @param[out] de_vec Vector of matched directory entries, or NULL
* @param[in] compar_fn Callback function for sorting the entry list
* @param[in] path Path to the directory to scan
* @param[in] fmt Format string, describes the search pattern as POSIX regex
* @param[in] ... Values for format string
*
* @returns Number of returned directory entries
* @returns Number of returned directory entries, or -1 on error
*/
int util_scandir(struct dirent ***de_vec,
int compar_fn(const struct dirent **first,

View File

@@ -594,17 +594,18 @@ static void cal_task_pcpu(struct task_t *task, const unsigned long long tics)
*/
static int read_stat(struct task_t *task)
{
int ppid, tty, proc;
unsigned long flags, pri, nice;
unsigned long long maj_flt, utime, stime, cutime, cstime;
unsigned long long maj_flt = 0, utime = 0, stime = 0, cutime = 0,
cstime = 0;
unsigned long flags = 0, pri = 0, nice = 0;
char *cmd_start, *cmd_end, *cmdlenp, *cmdp;
int ppid = 0, tty = 0, proc = 0, rc;
snprintf(fname, sizeof(fname), "/proc/%u/stat", task->pid);
if (read_file(fname, buf, sizeof(buf) - 1) == -1)
return 0;
cmd_start = strchr(buf, '(') + 1;
cmd_end = strchr(cmd_start, ')');
cmd_end = strrchr(cmd_start, ')');
name_lens.cmd_len = cmd_end - cmd_start;
cmdlenp = mon_record + sizeof(struct monwrite_hdr);
cmdlenp += sizeof(struct procd_hdr);
@@ -625,7 +626,7 @@ static int read_stat(struct task_t *task)
memcpy(cmdlenp, &name_lens.cmd_len, sizeof(__u16));
cmd_end += 2;
sscanf(cmd_end,
rc = sscanf(cmd_end,
"%c %d %*d %*d %d %*d "
"%lu %*s %*s %Lu %*s "
"%Lu %Lu %Lu %Lu "
@@ -642,6 +643,8 @@ static int read_stat(struct task_t *task)
&utime, &stime, &cutime, &cstime,
&pri, &nice,
&proc);
if (rc != 12)
syslog(LOG_ERR, "bad data in %s \n", fname);
task->ppid = (__u32)ppid;
task->tty = (__u16)tty;
task->flags = (__u32)flags;

View File

@@ -134,8 +134,8 @@ echo "$cmd: Copying virtio modules"
mkdir -p $builddir/$netdir
mkdir -p $builddir/$blkdir
set +e
cp $netdir/virtio_net.ko $builddir/$netdir 2> /dev/null
cp $blkdir/virtio_blk.ko $builddir/$blkdir 2> /dev/null
cp $netdir/virtio_net.ko* $builddir/$netdir 2> /dev/null
cp $blkdir/virtio_blk.ko* $builddir/$blkdir 2> /dev/null
set -e
# Busybox (+ dependencies)
@@ -170,7 +170,7 @@ cat <<'EOF' > $builddir/init
/bin/mount -t tmpfs none /run
/sbin/modprobe virtio_net
/sbin/udhcpc -O pxeconffile -O pxepathprefix &
/sbin/udhcpc -O pxeconffile -O pxepathprefix -x 93:001F &
/sbin/pxeboot.script
EOF
@@ -237,6 +237,7 @@ case "$1" in
echo " router: $router"
echo " domain: $domain $dns"
echo " tftp: $siaddr"
echo " pxepathprefix: $pxepathprefix"
# flush routes
/sbin/ip route flush table all
# setup if link
@@ -272,6 +273,7 @@ case "$1" in
echo "siaddr=$siaddr" > $PXECONF
echo "interface=$interface" >> $PXECONF
echo "ip=$ip" >> $PXECONF
echo "pxepathprefix=$pxepathprefix" >> $PXECONF
fi
;;
@@ -354,7 +356,7 @@ then
for c in $CONFIGS
do
echo "fetching config pxelinux.cfg/$c from $siaddr"
if /usr/bin/tftp -g -l /tmp/config -r pxelinux.cfg/$c $siaddr
if /usr/bin/tftp -g -l /tmp/config -r ${pxepathprefix}pxelinux.cfg/$c $siaddr
then
break
fi
@@ -371,6 +373,7 @@ fi
kernel=$(/bin/grep -i "^[[:space:]]*kernel" /tmp/config | sed "s/^[[:space:]]*kernel[[:space:]]*//I")
initrd=$(/bin/grep -i "^[[:space:]]*initrd" /tmp/config | sed "s/^[[:space:]]*initrd[[:space:]]*//I")
append=$(/bin/grep -i "^[[:space:]]*append" /tmp/config | sed "s/^[[:space:]]*append[[:space:]]*//I")
ipappend=$(/bin/grep -i "^[[:space:]]*ipappend" /tmp/config | sed "s/^[[:space:]]*ipappend[[:space:]]*//I")
if [ -z "$kernel" ]
then
@@ -378,13 +381,13 @@ then
exit
else
echo fetch kernel $kernel from $siaddr
/usr/bin/tftp -g -l /tmp/kernel -r $kernel $siaddr
/usr/bin/tftp -g -l /tmp/kernel -r $pxepathprefix$kernel $siaddr
fi
if [ -n "$initrd" ]
then
echo fetch initrd $initrd from $siaddr
/usr/bin/tftp -g -l /tmp/initrd -r $initrd $siaddr
/usr/bin/tftp -g -l /tmp/initrd -r $pxepathprefix$initrd $siaddr
INITRD="--initrd=/tmp/initrd"
else
INITRD=""
@@ -394,6 +397,9 @@ if [ -z "$append" ]; then
echo "Kexec load: kexec -l /tmp/kernel $INITRD"
kexec -l /tmp/kernel $INITRD
else
if [ "$ipappend" = "2" ]; then
$append="$append BOOTIF=01-$ifaddr"
fi
echo "Kexec load: kexec -l /tmp/kernel $INITRD --append=\"$append\""
kexec -l /tmp/kernel $INITRD --append="$append"
fi

View File

@@ -85,20 +85,12 @@ void init_ibmOSAMib(void) {
/* query OSA-E device driver for OSA-E devices and mark them in IF-MIB interface list */
osaexp_num = query_OSA_EXP ( &if_list, ifNumber );
if ( osaexp_num < 0 )
if ( osaexp_num == 0 )
{
fprintf( stderr, "init_ibmOSAMib(): "
"OSA-E device driver query interface ioctl() failed\n"
"check agent log file for more details\n"
"Cannot start subagent...exiting...\n");
exit(1);
}
else if ( osaexp_num == 0 )
{
fprintf( stderr, "init_ibmOSAMib(): bad or no OSA-E devices reported\n"
"check agent log file for more details\n"
"Cannot start subagent...exiting...\n");
exit(1);
get_time( time_buf );
snmp_log( LOG_ERR, "%s init_ibmOSAMib(): none of the %d interfaces is a real "
"OSA-E device - starting subagent anyway\n", time_buf, ifNumber);
return;
}
/* end if */

View File

@@ -1204,18 +1204,7 @@ void update_mib_info ()
* and mark them in IF-MIB interface list
* */
osaexp_num = query_OSA_EXP( &tmp_list, if_num );
if ( osaexp_num < 0 )
{
get_time( time_buf );
fprintf( stderr, "%s update_mib_info(): "
"OSA-E device driver query interface ioctl() "
"failed\nupdate_mib_info(): going to stop osasnmpd daemon\n"
"update_mib_info(): check subagent logfile for more details\n"
"update_mib_info(): sending termination signal to osasnmpd...\n",
time_buf );
exit(-1);
}
else if ( osaexp_num == 0 )
if ( osaexp_num == 0 )
{
get_time( time_buf );
snmp_log( LOG_ERR, "%s update_mib_info(): "
@@ -1698,9 +1687,8 @@ int query_IF_MIB ( IF_LIST** ifList )
* IN int if_Number: number of network interfaces
* returns: int num - number of OSA Express devices found on this
* system (>=0)
* -1 -an error occurred , no valid info avail
*********************************************************************/
int query_OSA_EXP ( IF_LIST** ifList, int if_Number )
unsigned int query_OSA_EXP ( IF_LIST** ifList, int if_Number )
{
int j, num = 0;
char time_buf[TIME_BUF_SIZE]; /* date/time buffer */

View File

@@ -91,7 +91,7 @@ void update_mib_info ( );
int query_IF_MIB( IF_LIST** );
/* retrieves OSA Express interface information from kernel */
int query_OSA_EXP ( IF_LIST** ,int );
unsigned int query_OSA_EXP ( IF_LIST** ,int );
/* get time of day */
int get_time( char* );

View File

@@ -208,6 +208,9 @@ static void print_physical(struct qeth_qoat_physical *phdr)
case OAT_OSA_GEN_OSAE6S:
osagen = "OSA-Express6S";
break;
case OAT_OSA_GEN_OSAE7S:
osagen = "OSA-Express7S";
break;
default:
sprintf(tmp, "unknown (0x%x)", phdr->osa_gen);
osagen = tmp;
@@ -239,6 +242,9 @@ static void print_physical(struct qeth_qoat_physical *phdr)
case OAT_PORT_SPEED_10gbs_full:
speed = "10 Gb/s / full duplex";
break;
case OAT_PORT_SPEED_25gbs_full:
speed = "25 Gb/s / full duplex";
break;
case OAT_PORT_SPEED_UNKNOWN:
speed = "unknown / unknown";
break;

View File

@@ -58,6 +58,7 @@ struct qeth_qoat_physical {
#define OAT_OSA_GEN_OSAE4S 0x02
#define OAT_OSA_GEN_OSAE5S 0x03
#define OAT_OSA_GEN_OSAE6S 0x04
#define OAT_OSA_GEN_OSAE7S 0x05
__u8 osa_gen;
#define OAT_PORT_SPEED_UNKNOWN 0x00
#define OAT_PORT_SPEED_10mbs_half 0x01
@@ -68,6 +69,7 @@ struct qeth_qoat_physical {
#define OAT_PORT_SPEED_1000mbs_full 0x06
#define OAT_PORT_SPEED_NA 0x07
#define OAT_PORT_SPEED_10gbs_full 0x08
#define OAT_PORT_SPEED_25gbs_full 0x0A
__u8 port_speed;
#define OAT_PORT_MEDIA_COPPER 0x01
#define OAT_PORT_MEDIA_MULTI_MODE 0x02

View File

@@ -1,7 +1,7 @@
include ../common.mak
SCRIPTS = dbginfo.sh zfcpdbf scsi_logging_level
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1 zipl-switch-to-blscfg.1
all:

View File

@@ -2,7 +2,7 @@
#
# dbginfo.sh - Tool to collect runtime, configuration, and trace information
#
# Copyright IBM Corp. 2002, 2017
# Copyright IBM Corp. 2002, 2018
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -21,7 +21,7 @@ readonly SCRIPTNAME="${0##*/}"
print_version() {
cat <<EOF
${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2002, 2017
Copyright IBM Corp. 2002, 2018
EOF
}
@@ -480,6 +480,7 @@ VM_CMDS="q userid\
:q cpus\
:q srm\
:q vtod\
:q time full\
:q timezone\
:q loaddev\
:q v osa\
@@ -1016,25 +1017,31 @@ environment_setup()
# create gzip-ped tar file
create_package()
{
local rc_tar
pr_stdout "Finalizing: Creating archive with collected data"
cd "${WORKDIR_BASE}"
if ! tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"; then
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
pr_stdout " to provide enough free available space."
tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"
rc_tar=$?
if [ $rc_tar -eq 0 ]; then
chmod 0600 "${WORKARCHIVE}"
pr_stdout " "
pr_stdout "Collected data was saved to:"
pr_stdout " >> ${WORKARCHIVE} <<"
pr_stdout " "
pr_stdout "Review the collected data before sending to your service organization. "
pr_stdout " "
elif [ $rc_tar -eq 127 ]; then
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Error: tar command is not available!"
pr_stdout " Please install the corresponding package!"
else
chmod 0600 "${WORKARCHIVE}"
pr_stdout " "
pr_stdout "Collected data was saved to:"
pr_stdout " >> ${WORKARCHIVE} <<"
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
pr_stdout " to provide enough free available space."
fi
pr_stdout " "
pr_stdout "Review the collected data before sending to your service organization. "
pr_stdout " "
}

213
scripts/zipl-switch-to-blscfg Executable file
View File

@@ -0,0 +1,213 @@
#!/bin/bash
#
# zipl-switch-to-blscfg - Switch zipl to use BootLoaderSpec configuration
#
# Copyright 2018 Red Hat, Inc.
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
readonly SCRIPTNAME="${0##*/}"
declare -A zipl_to_bls
zipl_to_bls["image"]="linux"
zipl_to_bls["ramdisk"]="initrd"
zipl_to_bls["parameters"]="options"
print_error() {
echo "$1" >&2
exit 1
}
function on_exit() {
if ! rm -rf $TMP; then
echo "Delete temporary files failed!" >&2
exit 1
fi
}
if ! TMP="$(mktemp -d)"; then
print_error "Creating a temporary dir for config files failed!"
fi
trap 'on_exit' EXIT
print_version() {
cat <<EOF
${SCRIPTNAME}: version %S390_TOOLS_VERSION%
Copyright Red Hat, Inc. 2018
EOF
}
print_usage()
{
print_version
cat <<EOF
Usage: ${SCRIPTNAME} [OPTIONS]
Switches the zipl boot-loader configuration to use BootLoaderSpec files.
Options:
-h, --help print this help and exit
-v, --version print version information and exit
--backup-suffix=SUFFIX suffix used for backup files, defaults to .bak
--bls-directory=DIR path to generate BLS files, defaults to /boot/loader/entries
--config-file=FILE path to zipl configuration file, defaults to /etc/zipl.conf
--ignore-default ignore the default option from the zipl configuration file
--use-version-name use the section kernel version as the BLS file name
EOF
}
OPTS="$(getopt -o hv --long help,version,backup-suffix:,bls-directory:,config-file:,\
ignore-default,use-version-name -n \'$SCRIPTNAME\' -- "$@")"
eval set -- "$OPTS"
BACKUP_SUFFIX=.bak
BLS_DIR="/boot/loader/entries"
CMDLINE_LINUX_DEBUG=" systemd.log_level=debug systemd.log_target=kmsg"
LINUX_DEBUG_VERSION_POSTFIX="_with_debugging"
LINUX_DEBUG_TITLE_POSTFIX=" with debugging"
CONFIG="/etc/zipl.conf"
while [ ${#} -gt 0 ]; do
case "$1" in
--help|-h)
print_usage
exit 0
;;
--version|-v)
print_version
exit 0
;;
--backup-suffix)
BACKUP_SUFFIX=${2}
shift
;;
--bls-directory)
BLS_DIR=${2}
shift
;;
--config-file)
CONFIG=${2}
shift
;;
--ignore-default)
ignore_default=true
;;
--use-version-name)
version_name=true
;;
--)
shift
break
;;
*)
echo >&2
echo "${SCRIPTNAME}: invalid option \"${1}\"" >&2
echo "Try '${SCRIPTNAME} --help' for more information" >&2
echo >&2
exit 1
;;
esac
shift
done
TMP_CONFIG="${TMP}/${CONFIG##*/}"
[[ -d "$BLS_DIR" ]] || mkdir -m 0700 -p "$BLS_DIR"
if [ -f /etc/machine-id ]; then
read MACHINE_ID < /etc/machine-id
MACHINE_ID=${MACHINE_ID}-
fi
count=0
OUTPUT=""
TARGET=""
while IFS='= ' read key val; do
# for BLS the default kernel is always the latest one
if [[ $key == \#* ]] || [[ $key == "default" && $ignore_default == true ]]; then
continue
fi
# remove spaces
key="$(echo $key | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')"
if [[ $key = \[*] ]]; then
if [[ $key == "[defaultboot]" ]]; then
OUTPUT=${TMP_CONFIG}
echo $key >> ${OUTPUT}
else
key="${key%\]}"
key="${key#\[}"
section=$key
OUTPUT=${BLS_DIR}/${MACHINE_ID}${section}.conf
if [ -f "${OUTPUT}" ]; then
print_error "BLS file ${OUTPUT} already exists"
fi
fi
elif [[ $val ]]; then
val="$(echo $val | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')"
if [[ $key == "target" ]]; then
if [ -z ${TARGET} ]; then
echo $key=$val >> ${TMP_CONFIG}
TARGET=$val
else if [ "${TARGET}" != "${val}" ]; then
print_error "BLS is only supported if all sections have the same target"
fi
fi
else
if [ -n "${zipl_to_bls[$key]}" ]; then
if [[ $key = "image" && $version_name == true ]]; then
if [[ $val = *"vmlinuz-"* ]]; then
version="${val##*/vmlinuz-}"
else
version="${val##*/}"
fi
echo "version $version" >> ${OUTPUT}
if [[ $version = *"rescue"* ]]; then
FILENAME=${BLS_DIR}/${MACHINE_ID}0-rescue.conf
else
FILENAME=${BLS_DIR}/${MACHINE_ID}${version}.conf
fi
if [[ ${OUTPUT} != ${FILENAME} ]]; then
if [ -f "${FILENAME}" ]; then
print_error "BLS file ${FILENAME} already exists"
fi
mv ${OUTPUT} ${FILENAME}
if [ ! $? -eq 0 ]; then
print_error "Creating BLS file ${FILENAME} failed"
fi
OUTPUT=${FILENAME}
fi
elif [[ $key = "image" ]]; then
echo "version $section" >> ${OUTPUT}
fi
echo "${zipl_to_bls[$key]} ${val}" >> ${OUTPUT}
else
echo $key=$val >> ${TMP_CONFIG}
fi
fi
fi
done < "${CONFIG}"
if [ -f "${CONFIG}${BACKUP_SUFFIX}" ]; then
print_error "Backup file ${CONFIG}${BACKUP_SUFFIX} already exists"
fi
cp -af "${CONFIG}" "${CONFIG}${BACKUP_SUFFIX}"
mv "${TMP_CONFIG}" "${CONFIG}"
zipl > /dev/null
if [ ! $? -eq 0 ]; then
mv "${CONFIG}${BACKUP_SUFFIX}" "${CONFIG}"
fi
exit 0

View File

@@ -0,0 +1,45 @@
.TH ZIPL-SWITCH-TO-BLSCFG 1 "April 2018" "s390-tools"
.SH NAME
zipl-switch-to-blscfg \- Switch zipl to use BootLoaderSpec configuration
.SH SYNOPSIS
.br
\fBzipl-switch-to-blscfg\fP [OPTIONS]
.br
\fBzipl-switch-to-blscfg\fP {\-h|\-v}
.SH DESCRIPTION
This script switches the zipl boot-loader configuration to use BootLoaderSpec files
to define IPL sections. For each Linux kernel defined in the zipl.conf config file,
a BLS fragment is generated in the BLS directory specified. Also, the zipl.conf is
modified it only contains global configurations, all IPL sections comes from BLS.
.SH OPTIONS
.TP
\fB\-h\fP, \fB\-\-help\fP
Print this help and exit
.TP
\fB\-v\fP, \fB\-\-version\fP
Print version information and exit
.TP
\fB\-\-backup-suffix <SUFFIX>\fP
The suffix used for backup files, defaults to .bak.
.TP
\fB\-\-bls-directory <DIRECTORY>\fP
The DIRECTORY where the BLS fragments will be generated. The directory is created if it doesn't exists, by default /boot/loader/entries is used.
.TP
\fB\-\-config-file <FILE>\fP
The FILE used for zipl configuration file, defaults to /etc/zipl.conf.
.TP
\fB\-\-ignore-default\fP
Ignore the default option from the zipl configuration file
.TP
\fB\-\-use-version-name\fP
Use the section kernel version as the BLS file name

View File

@@ -10,6 +10,7 @@
[Unit]
Description=CPACF statistics collection daemon process for Linux on System z
Documentation=man:cpacfstatsd(8)
ConditionVirtualization=no
[Service]
Type=forking

View File

@@ -174,7 +174,7 @@ int main(int argc, char *argv[]) {
) {
switch(c) {
case 'h':
fprintf(stderr, "%s", help_text);
fprintf(stdout, "%s", help_text);
exit(0);
case 'b':
ds.cntrl.blink = 1;

View File

@@ -9,7 +9,7 @@ libs = $(rootdir)/libvmdump/libvmdump.a
objects = vmconvert.o
vmconvert: $(objects) $(libs)
$(LINKXX) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(LINKXX) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) $(DESTDIR)$(MANDIR)/man1

View File

@@ -11,7 +11,7 @@ libs = $(rootdir)/libvmdump/libvmdump.a \
objects = vmur.o
vmur: $(objects) $(libs)
$(LINKXX) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(LINKXX) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(USRSBINDIR) $(DESTDIR)$(MANDIR)/man8

View File

@@ -111,10 +111,14 @@ In rare situations a device might temporarily not be accessible to
the subchannel. Then "none" is displayed as the device identifier and the
other device attributes are empty.
For subchannels bound to an alternate driver (most notably vfio_ccw) the
device identifier may also be displayed as "none". In this case use the
\fB--vfio\fR option to show VFIO specific subchannel information.
.SH AUTHOR
.nf
This man-page was written by Stefan Bader <shbader@de.ibm.com>.
New options added by Sebastian Ott <sebott@linux.vnet.ibm.com>.
New options added by Sebastian Ott <sebott@linux.ibm.com>.
.SH "SEE ALSO"
.BR chccwdev (8)
.fi

View File

@@ -2,7 +2,7 @@
#
# lsluns - list LUNs discovered in the FC SAN, or show encryption state of attached LUNs
#
# Copyright IBM Corp. 2008, 2017
# Copyright IBM Corp. 2008, 2018
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -152,6 +152,11 @@ sub get_lun_hash
my %lun_hash;
foreach my $device (</$sg_dir/sg*>) {
# skip non-zfcp SCSI devices and avoid file access error messages
next unless -r "$device/device/fcp_lun";
next unless -r "$device/device/wwpn";
next unless -r "$device/device/hba_id";
my $l = `cat $device/device/fcp_lun`;
my $p = `cat $device/device/wwpn`;
my $a = `cat $device/device/hba_id`;
@@ -170,9 +175,8 @@ sub get_lun_hash
sub lsluns_usage {
print <<EOD;
Usage:
This tool is designed for environments where all SCSI devices are attached
through the zfcp device driver. Expect error messages in mixed environments
such as with iSCSI.
This tool is designed for environments with SCSI devices attached
through the zfcp device driver.
$PROGRAM_NAME [-c <busid>] ... [-p <wwpn>] ... [-h] [-v]
@@ -220,7 +224,7 @@ EOD
sub lsluns_version {
print "$PROGRAM_NAME: version %S390_TOOLS_VERSION%\n";
print "Copyright IBM Corp. 2008, 2017\n";
print "Copyright IBM Corp. 2008, 2018\n";
}
sub lsluns_invalid_usage {
@@ -235,8 +239,15 @@ sub get_env_list
my @res ;
my %res_hash;
if (!</sys/bus/ccw/drivers/zfcp/*.*.*/>) {
print "$PROGRAM_NAME: No adapter exists\n";
return;
}
@res = </sys/bus/ccw/drivers/zfcp/*.*.*/0x*>;
return () if (!@res);
if (!@res) {
print "$PROGRAM_NAME: No port on any adapter exists\n";
return;
}
foreach my $entry (@res) {
my $a = ${[split('/', $entry)]}[-2];
my $p = ${[split('/', $entry)]}[-1];

View File

@@ -28,9 +28,8 @@ zfcp-attached LUNs
.SH DESCRIPTION
.PP
This tool is designed for environments where all SCSI devices are attached
through the zfcp device driver. Expect error messages in mixed environments
such as with iSCSI.
This tool is designed for environments with SCSI devices attached
through the zfcp device driver.
.B lsluns
lists all logical unit numbers (LUNs) discovered in the

View File

@@ -2,7 +2,7 @@
#
# lstape - Tool to show information about tape devices
#
# Copyright IBM Corp. 2003, 2017
# Copyright IBM Corp. 2003, 2018
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -48,6 +48,9 @@ function PrintUsage() {
: -v|--version
: Display the version of the tools package and
: the lstape command.
:
:$(basename $0) without the --ccw-only option causes extra SAN traffic
:for each SCSI tape or changer device by invoking the sg_inq command.
EOD
}
@@ -55,7 +58,7 @@ function PrintVersion()
{
cat <<-EOD
$CMD: version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2003, 2017
Copyright IBM Corp. 2003, 2018
EOD
}
@@ -220,6 +223,24 @@ function SysfsCreateListCCW() {
' | sort
}
# handle SCSI device not necessarily zfcp-attached, e.g. virtio-scsi-ccw
function SCSISearchCCWBusid()
{
local SCSI_DEV=$1
local SDEVCAN=$(readlink -e $SCSI_DEV)
while [ -n "$SDEVCAN" ]; do
# ascend to parent: strip last path part
SDEVCAN=${SDEVCAN%/*}
[ -h $SDEVCAN/subsystem ] || continue
local SUBSYSTEM=$(readlink -e $SDEVCAN/subsystem)
if [ "${SUBSYSTEM##*/}" = "ccw" ]; then
echo ${SDEVCAN##*/}
return
fi
done
echo "N/A"
}
function SysfsCreateListSCSI()
{
for SCSI_DEV in $1/bus/scsi/devices/*:*:*:*; do
@@ -249,11 +270,16 @@ function SysfsCreateListSCSI()
if [ -h $SG_DEV ]; then
# deprecated sysfs layout
SG_DEV=$(echo $SG_DEV | awk -F: '{print $NF}')
else
elif [ -d $SCSI_DEV/scsi_generic ]; then
SG_DEV=$(basename $SG_DEV/*)
else
SG_DEV=""
fi
if [ "$SG_INQ" != "" ]; then
if [ -z "$SG_DEV" ]; then
SG_DEV="N/A"
TAPE_SERIAL="NO/SG"
elif [ "$SG_INQ" != "" ]; then
TAPE_SERIAL=$(
sg_inq /dev/$SG_DEV |
awk '/serial/{print $NF}'
@@ -291,17 +317,31 @@ function SysfsCreateListSCSI()
if [ "$CHG_IDX" != "" ]; then
TAPE_DEV=$CHG_IDX
fi
elif [ -r /proc/scsi/$DEV_NAME ]; then
if [ "$TAPE_SERIAL" != "NO/INQ" ]; then
elif [ "$(echo "$SCSI_LIST"|grep lin_tape)" != "" ]; then
# bash glob sorts so IBMtape0 comes before IBMtape0n
local IBM_PATH=$(
ls -1d $SCSI_DEV/lin_tape/$DEV_NAME[0-9]* |
head -n 1)
if [ -d "$IBM_PATH" ]; then
IBM_IDX=${IBM_PATH##*/}
else
# deprecated sysfs layout
IBM_IDX=$(
awk '$3 == "'$TAPE_SERIAL'"{
print $1
}' /proc/scsi/$DEV_NAME
echo "$SCSI_LIST" |
awk -F: '/lin_tape\:'"$DEV_NAME"'[0-9]+$/{print $NF}'
)
fi
if [ "$IBM_IDX" != "" ]; then
TAPE_DEV=$IBM_IDX
fi
elif [ -r /proc/scsi/$DEV_NAME ]; then
IBM_IDX=$(
grep -wF "$SCSI_ID" /proc/scsi/$DEV_NAME |
cut -d ' ' -f 1
)
if [ "$IBM_IDX" != "" ]; then
TAPE_DEV=$DEV_NAME$IBM_IDX
fi
fi
fi
printf "$SCSIFORMAT" \
@@ -313,9 +353,16 @@ function SysfsCreateListSCSI()
$STATE
if $VERBOSE; then
if [ -r $SCSI_DEV/hba_id ]; then
HBA_ID=$(cat $SCSI_DEV/hba_id)
else
HBA_ID=$(SCSISearchCCWBusid $SCSI_DEV)
fi
WWPN="N/A"
[ -r $SCSI_DEV/wwpn ] && WWPN=$(cat $SCSI_DEV/wwpn)
printf "$SCSIVFORMAT" \
$(cat $SCSI_DEV/hba_id) \
$(cat $SCSI_DEV/wwpn) \
"$HBA_ID" \
"$WWPN" \
$TAPE_SERIAL
fi
done

View File

@@ -1,8 +1,8 @@
.\" Copyright 2017 IBM Corp.
.\" Copyright 2017, 2018 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH LSTAPE 8 "Jul 2007" "s390-tools"
.TH LSTAPE 8 "Jun 2018" "s390-tools"
.SH NAME
lstape \- list tape devices.
@@ -20,6 +20,8 @@ lstape \- list tape devices.
.br
.RB [ -t
.IR <device-type> [, <device-type> ] "" ...]
.br
.RI [ <device-bus-ID> ...]
.SH DESCRIPTION
The lstape command lists all available tape devices on the current host. For
@@ -27,19 +29,8 @@ channel attached tape devices this output is the same as the contents of
/proc/tapedevices (which is obsolete) but also includes offline devices. By
default all tape devices are displayed.
Since SCSI tape devices are accessed differently to channel attached tape
devices they are only visible if they are known to the SCSI layer. There
are at least two possible drivers that can claim a SCSI tape device and the
lstape command tries to find out which one this is. For the generic tape
and changer driver the device names start with "st" or "sch", while for the
IBM tape driver this would be "IBMtape" or "IBMchanger". If "N/A" is shown,
the correct driver could not be obtained.
This happens for example if there is no sg_inq command installed which is
required to read the drive's serial number which in turn is used to find out
the device number of the IBM tape driver.
The serial number of a SCSI tape can be displayed with the --verbose option. If
there is no sg_inq command available "NO/INQ" is shown as the tape's serial.
The lstape command without the --ccw-only option causes extra SAN traffic
for each SCSI tape or changer device by invoking the sg_inq command.
.SH OPTIONS
.TP 8
@@ -75,12 +66,64 @@ on the output of SCSI devices.
.TP
.BR -t | --type " \fI<device-type>\fR"
Limit output to given device types (currently only applies to channel attached
Limit output to given device types, for example 3490
(currently only applies to channel-attached
tape devices).
.TP
\fB<device-type>\fR =
Device type of devices that should be displayed (e.g. 3490).
.I <device-bus-ID>
Limits the output to information about the specified tape device or
devices only. For CCW-attached devices only.
.SH OUTPUT FIELDS FOR SCSI TAPE/CHANGER DEVICES
.TP
.B Generic
SCSI generic device file for the tape drive, for example /dev/sg0.
"N/A" if the SCSI generic (sg) kernel functionality is not available.
.TP
.B Device
Main character device node file for accessing the tape drive or medium changer.
SCSI tape devices are only visible if they are known to the SCSI layer. There
are at least two possible drivers that can claim a SCSI tape device. The
lstape command tries to determine the device driver. For the generic tape
and changer driver the device names start with "st" or "sch", while for the
IBM tape driver this would be "IBMtape" or "IBMchanger". If "N/A" is shown,
the device driver could not be determined.
.TP
.B Target
Linux SCSI device name in H:C:T:L format.
.TP
.B Vendor
The vendor field from the SCSI device.
.TP
.B Model
The model field from the SCSI device.
.TP
.B Type
"tapedrv" for a tape drive or "changer" for a medium changer.
.TP
.B State
The state of the SCSI device object in the kernel.
Any state other than "running" can indicate problems.
.PP
For SCSI devices, the --verbose option additionally displays:
.TP
.B HBA
The device bus-ID of the FCP device
or of the virtio-scsi-ccw virtual HBA
through which the tape drive is attached.
"N/A" if the device does not have a sysfs ancestor with subsystem ccw.
.TP
.B WWPN
The WWPN (worldwide port name) of the tape drive in the SAN.
"N/A" if device is not attached through zfcp.
.TP
.B Serial
The serial number.
"NO/INQ" if there is no sg_inq command available.
"NO/SG" if no SCSI generic (sg) kernel support is available.
.SH EXAMPLES
\fBlstape\fR
@@ -92,3 +135,8 @@ List all tape devices that are available
.RS
Show all 3490 CCW devices that are online.
.RE
\fBlstape --scsi-only --verbose\fR
.RS
Show all SCSI tape or changer devices with maximum information.
.RE

View File

@@ -1,21 +1,24 @@
include ../../common.mak
all: chzcrypt lszcrypt
all: chzcrypt lszcrypt zcryptctl
libs = $(rootdir)/libutil/libutil.a
chzcrypt: chzcrypt.o misc.o $(libs)
lszcrypt: lszcrypt.o misc.o $(libs)
zcryptctl: zcryptctl.o misc.o $(libs)
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 chzcrypt $(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 lszcrypt $(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zcryptctl $(DESTDIR)$(BINDIR)
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 -c chzcrypt.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 -c lszcrypt.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 -c zcryptctl.8 $(DESTDIR)$(MANDIR)/man8
clean:
rm -f *.o chzcrypt lszcrypt
rm -f *.o chzcrypt lszcrypt zcryptctl
.PHONY: all install clean

View File

@@ -54,8 +54,8 @@ status.
.B -V, --verbose
The verbose level for cryptographic device information.
With this verbose level additional information like hardware card type,
hardware queue depth, pending request queue count, outstanding
request queue count, and installed function facilities are displayed.
hardware queue depth, pending requests count, installed function
facilities and driver binding is displayed.
.TP 8
.B <device-id>
Specifies a cryptographic device to display. A cryptographic device can be

View File

@@ -1,7 +1,7 @@
/**
* lszcrypt - Display zcrypt devices and configuration settings
*
* Copyright IBM Corp. 2008, 2017
* Copyright IBM Corp. 2008, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -56,6 +56,25 @@ struct lszcrypt_l *lszcrypt_l = &l;
#define MASK_CLASS_STATELESS 0x00400000
#define CLASS_STATELESS "restricted function set"
/*
* facility bits
*/
#define MAX_FAC_BITS 9
static struct fac_bits_s {
int mask;
char c;
} fac_bits[MAX_FAC_BITS] = {
{ 0x80000000, 'S' },
{ 0x40000000, 'M' },
{ 0x20000000, 'C' },
{ 0x10000000, 'D' },
{ 0x08000000, 'A' },
{ 0x04000000, 'X' },
{ 0x02000000, 'N' },
{ 0x00800000, 'F' },
{ 0x00400000, 'R' },
};
/*
* Program configuration
*/
@@ -66,7 +85,7 @@ const struct util_prg prg = {
{
.owner = "IBM Corp.",
.pub_first = 2008,
.pub_last = 2017,
.pub_last = 2018,
},
UTIL_PRG_COPYRIGHT_END
}
@@ -255,7 +274,8 @@ static void show_capability(const char *id_str)
/* Skip devices, which are not supported by zcrypt layer */
if (!util_path_is_readable("%s/type", dev) ||
!util_path_is_readable("%s/online", dev)) {
printf("Detailed capability information for %s (hardware type %ld) is not available.\n", card, hwtype);
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
card, hwtype);
return;
}
cbuf[0] = '\0';
@@ -299,11 +319,13 @@ static void show_capability(const char *id_str)
} else if (func_val & MASK_EP11) {
printf("%s", CAP_EP11);
} else {
printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype);
printf("Detailed capability information for %s (hardware type %ld) is not available.",
card, hwtype);
}
break;
default:
printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype);
printf("Detailed capability information for %s (hardware type %ld) is not available.",
card, hwtype);
break;
}
printf("\n");
@@ -315,17 +337,22 @@ static void show_capability(const char *id_str)
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
const char *sub_dev)
{
unsigned long facility;
char buf[256];
unsigned long facility;
util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev);
util_rec_set(rec, "type", buf);
util_file_read_line(buf, sizeof(buf), "%s/%s/online", grp_dev, sub_dev);
if (strcmp(buf, "0") == 0)
util_rec_set(rec, "online", "offline");
if (util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev))
util_rec_set(rec, "type", "-");
else
util_rec_set(rec, "online", "online");
util_rec_set(rec, "type", buf);
if (util_file_read_line(buf, sizeof(buf), "%s/%s/online",
grp_dev, sub_dev))
util_rec_set(rec, "online", "-");
else
if (strcmp(buf, "0") == 0)
util_rec_set(rec, "online", "offline");
else
util_rec_set(rec, "online", "online");
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
if (facility & MASK_COPRO)
@@ -339,7 +366,7 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
util_file_read_line(buf, sizeof(buf), "%s/%s/request_count",
grp_dev, sub_dev);
util_rec_set(rec, "request_count", buf);
util_rec_set(rec, "requests", buf);
}
/*
@@ -348,20 +375,19 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
const char *sub_dev)
{
int i;
unsigned long facility;
char buf[256];
long depth;
char buf[256], afile[PATH_MAX];
long depth, pending1, pending2;
if (l.verbose == 0)
return;
util_file_read_line(buf, sizeof(buf), "%s/%s/pendingq_count",
grp_dev, sub_dev);
util_rec_set(rec, "pendingq_count", buf);
util_file_read_line(buf, sizeof(buf), "%s/%s/requestq_count",
grp_dev, sub_dev);
util_rec_set(rec, "requestq_count", buf);
util_file_read_l(&pending1, 10, "%s/%s/pendingq_count",
grp_dev, sub_dev);
util_file_read_l(&pending2, 10, "%s/%s/requestq_count",
grp_dev, sub_dev);
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
util_rec_set(rec, "hwtype", buf);
@@ -370,7 +396,18 @@ static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
util_rec_set(rec, "depth", "%02d", depth + 1);
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
util_rec_set(rec, "facility", "0x%08x", facility);
for (i = 0; i < MAX_FAC_BITS; i++)
buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-';
buf[i] = '\0';
util_rec_set(rec, "facility", buf);
snprintf(afile, sizeof(afile), "%s/%s/driver", grp_dev, sub_dev);
afile[sizeof(afile) - 1] = '\0';
memset(buf, 0, sizeof(buf));
if (readlink(afile, buf, sizeof(buf)) > 0)
util_rec_set(rec, "driver", strrchr(buf, '/') + 1);
else
util_rec_set(rec, "driver", "-no-driver-");
}
/*
@@ -382,9 +419,13 @@ static void show_subdevice(struct util_rec *rec, const char *grp_dev,
if (!util_path_is_dir("%s/%s", grp_dev, sub_dev))
errx(EXIT_FAILURE, "Error - cryptographic device %s/%s does not exist.", grp_dev, sub_dev);
/* Skip devices, which are not supported by zcrypt layer */
if (!util_path_is_readable("%s/type", grp_dev) ||
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
/*
* If not verbose mode, skip devices which are not supported
* by the zcrypt layer.
*/
if (l.verbose == 0 &&
(!util_path_is_readable("%s/type", grp_dev) ||
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev)))
return;
util_rec_set(rec, "card", sub_dev);
@@ -414,11 +455,13 @@ static void show_subdevices(struct util_rec *rec, const char *grp_dev)
*/
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
{
unsigned long facility;
char buf[256];
unsigned long facility;
util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev);
util_rec_set(rec, "type", buf);
if (util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev))
util_rec_set(rec, "type", "-");
else
util_rec_set(rec, "type", buf);
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
if (facility & MASK_COPRO)
@@ -430,14 +473,16 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
else
util_rec_set(rec, "mode", "Unknown");
util_file_read_line(buf, sizeof(buf), "%s/online", grp_dev);
if (strcmp(buf, "0") == 0)
util_rec_set(rec, "online", "offline");
if (util_file_read_line(buf, sizeof(buf), "%s/online", grp_dev))
util_rec_set(rec, "online", "-");
else
util_rec_set(rec, "online", "online");
if (strcmp(buf, "0") == 0)
util_rec_set(rec, "online", "offline");
else
util_rec_set(rec, "online", "online");
util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev);
util_rec_set(rec, "request_count", buf);
util_rec_set(rec, "requests", buf);
}
/*
@@ -445,18 +490,17 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
*/
static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
{
int i;
unsigned long facility;
char buf[256];
long depth;
char buf[256], afile[PATH_MAX];
long depth, pending1, pending2;
if (l.verbose == 0)
return;
util_file_read_line(buf, sizeof(buf), "%s/pendingq_count", grp_dev);
util_rec_set(rec, "pendingq_count", buf);
util_file_read_line(buf, sizeof(buf), "%s/requestq_count", grp_dev);
util_rec_set(rec, "requestq_count", buf);
util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev);
util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev);
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
util_rec_set(rec, "hwtype", buf);
@@ -465,7 +509,18 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
util_rec_set(rec, "depth", "%02d", depth + 1);
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
util_rec_set(rec, "facility", "0x%08x", facility);
for (i = 0; i < MAX_FAC_BITS; i++)
buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-';
buf[i] = '\0';
util_rec_set(rec, "facility", buf);
snprintf(afile, sizeof(afile), "%s/driver", grp_dev);
afile[sizeof(afile) - 1] = '\0';
memset(buf, 0, sizeof(buf));
if (readlink(afile, buf, sizeof(buf)) > 0)
util_rec_set(rec, "driver", strrchr(buf, '/') + 1);
else
util_rec_set(rec, "driver", "-no-driver-");
}
/*
@@ -481,9 +536,14 @@ static void show_device(struct util_rec *rec, const char *device)
grp_dev = util_path_sysfs("devices/ap/%s", device);
if (!util_path_is_dir(grp_dev))
errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device);
/* Skip devices, which are not supported by zcrypt layer */
if (!util_path_is_readable("%s/type", grp_dev) ||
!util_path_is_readable("%s/online", grp_dev)) {
/*
* If not verbose mode, skip devices which are not supported
* by the zcrypt layer.
*/
if (l.verbose == 0 &&
(!util_path_is_readable("%s/type", grp_dev) ||
!util_path_is_readable("%s/online", grp_dev))) {
goto out_free;
}
util_rec_set(rec, "card", card);
@@ -506,8 +566,7 @@ static void define_rec_default(struct util_rec *rec)
util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE");
util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE");
util_rec_def(rec, "online", UTIL_REC_ALIGN_LEFT, 7, "STATUS");
util_rec_def(rec, "request_count", UTIL_REC_ALIGN_RIGHT, 11,
"REQUEST_CNT");
util_rec_def(rec, "requests", UTIL_REC_ALIGN_RIGHT, 8, "REQUESTS");
}
/*
@@ -517,13 +576,11 @@ static void define_rec_verbose(struct util_rec *rec)
{
if (l.verbose == 0)
return;
util_rec_def(rec, "pendingq_count", UTIL_REC_ALIGN_RIGHT, 12,
"PENDINGQ_CNT");
util_rec_def(rec, "requestq_count", UTIL_REC_ALIGN_RIGHT, 12,
"REQUESTQ_CNT");
util_rec_def(rec, "hwtype", UTIL_REC_ALIGN_RIGHT, 7, "HW_TYPE");
util_rec_def(rec, "depth", UTIL_REC_ALIGN_RIGHT, 7, "Q_DEPTH");
util_rec_def(rec, "pending", UTIL_REC_ALIGN_RIGHT, 8, "PENDING");
util_rec_def(rec, "hwtype", UTIL_REC_ALIGN_RIGHT, 6, "HWTYPE");
util_rec_def(rec, "depth", UTIL_REC_ALIGN_RIGHT, 6, "QDEPTH");
util_rec_def(rec, "facility", UTIL_REC_ALIGN_LEFT, 10, "FUNCTIONS");
util_rec_def(rec, "driver", UTIL_REC_ALIGN_LEFT, 11, "DRIVER");
}
/*

147
zconf/zcrypt/zcryptctl.8 Normal file
View File

@@ -0,0 +1,147 @@
.\" zcryptctl.8
.\"
.\" Copyright 2018 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.
.\"
.\" use
.\" groff -man -Tutf8 zcryptctl.8
.\" or
.\" nroff -man zcryptctl.8
.\" to process this source
.\"
.TH ZCRYPTCTL 8 "AUG 2018" "s390-tools"
.SH NAME
zcryptctl \- display information and administrate zcrypt multiple device nodes
.SH SYNOPSIS
.TP 8
.B zcryptctl list
.TP
.B zcryptctl create
.R [
.I node-name
.R ]
.TP
.B zcryptctl destroy
.I node-name
.TP
.B zcryptctl addap
.R |
.B delap
.I node-name adapter-nr
.TP
.B zcryptctl adddom
.R |
.B deldom
.I node-name domain-nr
.TP
.B zcryptctl addioctl
.R |
.B delioctl
.I node-name ioctl-term
.TP
.B zcryptctl config
.I config-file
.TP
.B zcryptctl listconfig
.SH DESCRIPTION
The
.B zcryptctl
command displays information and maintains the multi device node
extension for the zcrypt device driver.
.P
With the multi device node extension you can create and configure
additional zcrypt device nodes which can be used as alternate device
nodes to access the crypto hardware provided by the zcrypt device
driver. Each zcrypt device node can be restricted in terms of crypto
cards, domains, and available ioctls. Such a device node can be used
as a base for container solutions like Docker to control and restrict
the access to crypto resources.
.SH COMMANDS
.TP 8
.B zcryptctl list
Show all the additional device nodes that are currently active.
.TP
.B zcryptctl create
.R [
.I node-name
.R ]
Create a new zcrypt device node. The \fInode-name\fP might be given
and needs to be unique and not in use. If there is no node name
provided, the zcrypt device driver will create a new one with pattern
zcrypt_\fIx\fP, with \fIx\fP being the next free number. Up to 256
additional device nodes can be created. The newly created additional
device node appears in /dev and has read and write permissions enabled
only for root. By default all adapters, domains and ioctls are
initially disabled on this new device node.
.TP
.B zcryptctl destroy
.I node-name
Destroy an additional zcrypt device node. The device node is only
marked for disposal and destroyed when it is no longer used.
.TP
.B zcryptctl addap
.R |
.B delap
.I node-name adapter-nr
Update the filter for the specified zcrypt device node and add or
delete a crypto adapter to be accessible via this node. The symbol
\fBALL\fP can be used to enable or disable all adapters.
.TP
.B zcryptctl adddom
.R |
.B deldom
.I node-name domain-nr
Update the filter for the specified zcrypt device node and add or
delete a domain to be accessible through this node. The symbol
\fBALL\fP can be used to enable or disable all domains.
.TP
.B zcryptctl addioctl
.R |
.B delioctl
.I node-name ioctl-term
Update the filter for the specified zcrypt device node and add or
delete an ioctl. The ioctl might be specified as symbolic string (one
of \fBICARSAMODEXPO\fP, \fBICARSACRT\fP, \fBZSECSENDCPRB\fP,
\fBZSENDEP11CPRB\fP, \fBZCRYPT_DEVICE_STATUS\fP,
\fBZCRYPT_STATUS_MASK\fP, \fBZCRYPT_QDEPTH_MASK\fP,
\fBZCRYPT_PERDEV_REQCNT\fP) or numeric value in the range 0-255 and
the symbol \fBALL\fP can be used to include all ioctls.
.TP
.B zcryptctl config
.I config-file
Process a config file. The given configuration file is read line by
line and the settings are applied. Syntax is simple:
.RS
.IP "node=<node-name>"
.IP "aps=<list of ap numbers separated by space, tab or ','>"
.IP "doms=<list of domain numbers separated by space, tab or ','>"
.IP "ioctls=<list of ioctl as numeric or symbolic number separated by space, tab or ','>"
.LP
Empty lines are ignored and the '#' marks the rest of the
line as comment.
.LP
The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP,
\fBdoms=\fP and \fBioctls=\fP lines customize the previously created
node. The symbol \fBALL\fP is also recognized for aps, doms, and
ioctls.
.LP
Each action must fit into one line, spreading over multiple lines is
not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP
and \fBioctls=\fP lines to customize the very same node.
.LP
Processing stops when a line cannot be parsed or the current action
fails. In this case the exit status is non zero but the successful
actions until the failure occurs are not rolled back.
.RE
.TP
.B zcryptctl listconfig
List the current configuration in a form suitable for input to the
\fBzcryptctl config\fP command.
.LP
.SH EXIT STATUS
On successful completion of the command the exit status is 0. A non
zero return code (and some kind of failure message) is emitted if the
processing could not complete successful.
.SH SEE ALSO
\fBlszcrypt\fR(8)

1030
zconf/zcrypt/zcryptctl.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ install: all
$(MAKE) -C src install
$(MAKE) -C man install
$(MAKE) -C dracut install
$(MAKE) -C initramfs install
clean:
$(MAKE) -C src clean

View File

@@ -9,7 +9,8 @@
# 95zdev/module_setup.sh
# This module installs configuration files (udev rules and modprobe.conf
# files) required to enable the root device on s390. It will only work when
# the root device was configured using the chzdev tool.
# the root device was configured using the chzdev tool. In addition,
# a hook is installed to parse rd.zdev= kernel parameters.
#
check() {
@@ -29,30 +30,27 @@ depends() {
}
installkernel() {
local _modules=$(lszdev --by-path / --columns MODULES --no-headings 2>/dev/null)
[ -z "$_modules" ] && return 0
[ ! -z "$_modules" ] && instmods $_modules
# Add modules for all device types supported by chzdev (required for
# auto-configuration)
instmods lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
dasd_diag_mod zfcp
}
install() {
local _tempfile
# Exit early if root device type is unknown
if ! lszdev --by-path / >/dev/null 2>&1 ; then
return 0
fi
# Ensure that required tools are available
inst_multiple chzdev lszdev vmcp
# Hook to parse zdev kernel parameter
inst_hook cmdline 95 "$moddir/parse-zdev.sh"
# Obtain early + root device configuration
_tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
if chzdev --export - --persistent --by-path / >/dev/null 2>&1 ; then
# Use persistent configuration
chzdev --export "$_tempfile" --persistent --by-path / --quiet --type
else
# Use active configuration
chzdev --export "$_tempfile" --active --by-path / --quiet --type
sed -i -e 's/active/persistent/g' "$_tempfile"
fi
chzdev --export "$_tempfile" --persistent --by-path / --quiet \
--type 2>/dev/null
chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \
--type 2>/dev/null >> "$_tempfile"
# Apply via --import to prevent other devices from being configured
chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \

View File

@@ -0,0 +1,38 @@
#!/bin/sh
#
# Copyright IBM Corp. 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
# 95zdev/parse-zdev.sh
# Parse the kernel command line for rd.zdev kernel parameters. These
# parameters are evaluated and used to configure z Systems specific devices.
#
# Format:
# rd.zdev=no-auto
#
# where
#
# no-auto: Indicates that firmware-provided I/O configuration data
# should not be applied.
#
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
if [ -e "$zdev_fw_file" ] ; then
zdev_auto=1
else
zdev_auto=0
fi
for zdev_arg in $(getargs rd.zdev); do
if [ "$zdev_arg" = "no-auto" ] ; then
zdev_auto=0
fi
done
if [ $zdev_auto -eq 1 ] ; then
chzdev --import "$zdev_fw_file" $zdev_base_args
fi

View File

@@ -11,11 +11,14 @@ ZDEVDIR := 95zdev
# performs the following functions when dracut is run:
#
# - copy the persistent root device configuration to the initial ram disk
# - install a boot-time hook to apply firmware-provided configuration data
# to the system
#
ifeq ($(HAVE_DRACUT),1)
install:
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)/$(ZDEVDIR)
$(INSTALL) -m 755 $(ZDEVDIR)/module-setup.sh \
$(ZDEVDIR)/parse-zdev.sh \
$(DESTDIR)$(MODDIR)/$(ZDEVDIR)/
endif

View File

@@ -189,6 +189,7 @@ struct value_map {
* in the persistent configuration
* @nounload: (Device type attributes only) This attribute can be set while
* the corresponding kernel module remains loaded.
* @internal: This attribute only affects internal handling
* @order: A number indicating the order in which to apply attribute
* @order_cmp: A function determining if a setting for this attribute should
* be applied before (-1) or after (1) another setting, or
@@ -216,6 +217,7 @@ struct attrib {
unsigned int activerem :1;
unsigned int defunset :1;
unsigned int nounload :1;
unsigned int internal :1;
/* Optional */
int order;

View File

@@ -62,10 +62,12 @@ struct ccw_devinfo {
* ccw_subtype_data - CCW subtype specific information
* @ccwdrv: The name of the CCW device driver for this subtype
* @mod: The name of the main kernel module for this subtype
* @any_driver: If set, the exact driver for this subtype are not known
*/
struct ccw_subtype_data {
const char *ccwdrv;
const char *mod;
bool any_driver;
};
extern struct attrib ccw_attr_online;

View File

@@ -11,7 +11,10 @@
#define DASD_H
struct devtype;
struct subtype;
extern struct devtype dasd_devtype;
extern struct subtype dasd_subtype_eckd;
extern struct subtype dasd_subtype_fba;
#endif /* DASD_H */

View File

@@ -45,6 +45,7 @@ struct device_state {
* @node: Node for adding this device to a list
* @active: Device state in the active configuration
* @persistent: Device state in the persistent configuration
* @autoconf: Auto-configured device state
* @errors: A strlist of error and warning messages issued for the device
* @processed: Device has been processed
*/
@@ -59,6 +60,7 @@ struct device {
struct device_state active;
struct device_state persistent;
struct device_state autoconf;
unsigned int processed:1;
};
@@ -94,5 +96,9 @@ void device_list_add(struct device_list *, struct device *);
struct device *device_list_find(struct device_list *, const char *,
struct device *);
void device_list_print(struct device_list *, int);
struct setting_list *device_get_setting_list(struct device *dev,
config_t config);
config_t device_get_config(struct device *dev);
#endif /* DEVICE_H */

View File

@@ -31,6 +31,7 @@ struct export_object {
} ptr;
};
struct export_object *object_new(export_t type, void *ptr);
exit_code_t export_write_device(FILE *, struct device *, config_t, int *);
exit_code_t export_write_devtype(FILE *, struct devtype *, config_t, int *);
exit_code_t export_read(FILE *, const char *, struct util_list *);

25
zdev/include/firmware.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* zdev - Modify and display the persistent configuration of devices
*
* Copyright IBM Corp. 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef FIRMWARE_H
#define FIRMWARE_H
#include <stdio.h>
#include <stdbool.h>
#include "exit_code.h"
#include "misc.h"
struct util_list;
bool firmware_detect(FILE *fd);
exit_code_t firmware_read(FILE *fd, const char *filename, long skip,
config_t config, struct util_list *objects);
#endif /* FIRMWARE_H */

25
zdev/include/internal.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* zdev - Modify and display the persistent configuration of devices
*
* Copyright IBM Corp. 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef INTERNAL_H
#define INTERNAL_H
#include <stdbool.h>
#include "attrib.h"
#define INTERNAL_ATTR_PREFIX "zdev:"
#define INTERNAL_ATTR_EARLY INTERNAL_ATTR_PREFIX "early"
extern struct attrib internal_attr_early;
const char *internal_get_name(const char *name);
bool internal_by_name(const char *name);
#endif /* INTERNAL_H */

View File

@@ -19,9 +19,14 @@
#include "exit_code.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define SCOPE_ACTIVE(x) (((x) == config_active) || ((x) == config_all))
#define SCOPE_PERSISTENT(x) (((x) == config_persistent) || \
((x) == config_all))
#define SCOPE_ACTIVE(x) ((x) & config_active ? 1 : 0)
#define SCOPE_PERSISTENT(x) ((x) & config_persistent ? 1 : 0)
#define SCOPE_AUTOCONF(x) ((x) & config_autoconf ? 1 : 0)
#define SCOPE_ALL(x) ((x) == (config_active | config_persistent |\
config_autoconf))
#define SCOPE_SINGLE(x) ((x) == config_active || \
(x) == config_persistent || \
(x) == config_autoconf)
#define DELAY_INDENT 4
@@ -34,12 +39,15 @@
#define EVEN(x) (((x) & 1) == 0)
/* Enumeration of configuration sets. */
typedef enum {
config_active,
config_persistent,
config_all,
} config_t;
/* Enumeration of configuration sets. Multiple configuration sets can be
* combined using bit-wise or. */
enum {
config_active = 1,
config_persistent = 2,
config_autoconf = 4,
config_all = 7,
};
typedef int config_t;
typedef enum {
err_ignore,
@@ -159,6 +167,7 @@ bool misc_read_dir(const char *, struct util_list *,
bool (*)(const char *, void *), void *);
bool file_is_devnode(const char *);
exit_code_t remove_file(const char *);
exit_code_t misc_read_fd(FILE *fd, void **buffer, size_t *size_ptr);
char *misc_read_text_file(const char *, int, err_t);
char *misc_read_cmd_output(const char *, int, err_t);
char *config_read_cmd_output(const char *, int, err_t);
@@ -166,7 +175,7 @@ exit_code_t misc_write_text_file(const char *, const char *, err_t);
exit_code_t misc_write_text_file_retry(const char *, const char *, err_t);
exit_code_t misc_mktemp(char **, int *);
char *misc_readlink(const char *path);
config_t get_config(int, int);
config_t get_config(int act, int pers, int ac);
bool is_zvm(void);
bool is_terminal(void);
const char *config_to_str(config_t);
@@ -174,6 +183,7 @@ bool str_to_config(const char *, config_t *);
char *quote_str(const char *, int);
char *unquote_str(const char *);
char *shrink_str(const char *);
char *misc_strrstr(const char *haystack, const char *needle);
struct util_list *strlist_new(void);
void strlist_free(struct util_list *);

View File

@@ -20,10 +20,11 @@
#define UDEV_SUFFIX ".rules"
#define PATH_MODPROBE_CONF "/etc/modprobe.d"
#define PATH_MODPROBE "/usr/sbin/modprobe"
#define PATH_MODPROBE "/sbin/modprobe"
#define PATH_CCW_BUS "/sys/bus/ccw"
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
#define PATH_UDEV_RULES "/etc/udev/rules.d"
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
#define PATH_PROC "/proc"
#define PATH_UDEVADM "udevadm"
@@ -55,8 +56,8 @@ char *path_get_ccw_device(const char *, const char *);
char *path_get_ccw_devices(const char *);
char *path_get_ccwgroup_device(const char *, const char *);
char *path_get_ccwgroup_devices(const char *);
char *path_get_udev_rule(const char *, const char *);
char *path_get_udev_rules(void);
char *path_get_udev_rule(const char *type, const char *id, bool vol);
char *path_get_udev_rules(bool vol);
char *path_get_proc(const char *);
char *path_get_sys_bus_dev(const char *, const char *);
char *path_get_sys_bus_drv(const char *, const char *);

View File

@@ -17,9 +17,11 @@
#define QETH_NUM_DEVS 3
struct devtype;
struct subtype;
struct namespace;
extern struct devtype qeth_devtype;
extern struct subtype qeth_subtype_qeth;
extern struct namespace qeth_namespace;
#endif /* QETH_H */

View File

@@ -94,7 +94,8 @@ void setting_list_map_values(struct setting_list *);
void setting_list_mark_default_derived(struct setting_list *);
int setting_list_count_set(struct setting_list *);
void setting_list_remove_derived(struct setting_list *);
char *setting_get_changes(struct setting_list *, struct setting_list *);
char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
struct setting_list *ac);
bool setting_match_value(struct setting *, const char *);
#endif /* SETTING_H */

View File

@@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id,
*
* @exists_active: Check if device exists in active configuration
* @exists_persistent: Check if device exists in persistent configuration
* @exists_autoconf: Check if device exists in autoconf configuration
*
* @add_active_ids: Add IDs of all devices existing in active configuration to
* specified strlist
* @add_persistent_ids: Add IDs of all devices existing in persistent
* configuration to specified strlist
* @add_autoconf_ids: Add IDs of all devices existing in autoconf
* configuration to specified strlist
*
* @read_active: Read device configuration from active configuration
* @read_persistent: Read device configuration from persistent configuration
* @read_autoconf: Read device configuration from autoconf configuration
*
* @configure_active: Apply configuration to active configuration
* @configure_persistent: Apply configuration to persistent configuration
* @configure_autoconf: Apply configuration to autoconf configuration
*
* @check_pre_write: Optional: Determine if the given configuration is valid
* for the specified device. If not, emit warning messages
@@ -150,24 +155,33 @@ struct subtype {
bool (*exists_active)(struct subtype *, const char *);
bool (*exists_persistent)(struct subtype *, const char *);
bool (*exists_autoconf)(struct subtype *, const char *);
void (*add_active_ids)(struct subtype *, struct util_list *);
void (*add_persistent_ids)(struct subtype *,
struct util_list *);
void (*add_autoconf_ids)(struct subtype *,
struct util_list *);
exit_code_t (*read_active)(struct subtype *, struct device *,
read_scope_t);
exit_code_t (*read_persistent)(struct subtype *, struct device *,
read_scope_t);
exit_code_t (*read_autoconf)(struct subtype *, struct device *,
read_scope_t);
exit_code_t (*configure_active)(struct subtype *, struct device *);
exit_code_t (*configure_persistent)(struct subtype *,
struct device *);
exit_code_t (*configure_autoconf)(struct subtype *,
struct device *);
exit_code_t (*deconfigure_active)(struct subtype *,
struct device *);
exit_code_t (*deconfigure_persistent)(struct subtype *,
struct device *);
exit_code_t (*deconfigure_autoconf)(struct subtype *,
struct device *);
exit_code_t (*check_pre_configure)(struct subtype *,
struct device *, int, config_t);
@@ -217,23 +231,31 @@ void subtype_exit(struct subtype *);
bool subtype_device_exists_active(struct subtype *, const char *);
bool subtype_device_exists_persistent(struct subtype *, const char *);
bool subtype_device_exists_autoconf(struct subtype *st, const char *id);
void subtype_add_active_ids(struct subtype *, struct util_list *);
void subtype_add_persistent_ids(struct subtype *, struct util_list *);
void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids);
exit_code_t subtype_device_read_active(struct subtype *, struct device *,
read_scope_t);
exit_code_t subtype_device_read_persistent(struct subtype *, struct device *,
read_scope_t);
exit_code_t subtype_device_read_autoconf(struct subtype *st, struct device *dev,
read_scope_t scope);
exit_code_t subtype_device_configure_active(struct subtype *, struct device *);
exit_code_t subtype_device_configure_persistent(struct subtype *,
struct device *);
exit_code_t subtype_device_configure_autoconf(struct subtype *st,
struct device *dev);
exit_code_t subtype_device_deconfigure_active(struct subtype *,
struct device *);
exit_code_t subtype_device_deconfigure_persistent(struct subtype *st,
struct device *);
exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
struct device *dev);
exit_code_t subtype_check_pre_configure(struct subtype *, struct device *, int,
config_t);

View File

@@ -13,7 +13,11 @@
#include "lib/util_list.h"
#include "exit_code.h"
struct attrib;
struct setting_list;
extern int udev_need_settle;
extern int udev_no_settle;
/* Single key-operator-value entry in a udev rule line.*/
struct udev_entry_node {
@@ -39,9 +43,14 @@ exit_code_t udev_read_file(const char *, struct udev_file **);
void udev_free_file(struct udev_file *);
void udev_file_print(struct udev_file *);
void udev_get_device_ids(const char *, struct util_list *);
exit_code_t udev_remove_rule(const char *, const char *);
void udev_get_device_ids(const char *type, struct util_list *list,
bool autoconf);
exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf);
void udev_settle(void);
void udev_add_internal_from_entry(struct setting_list *list,
struct udev_entry_node *entry,
struct attrib **attribs);
#endif /* UDEV_H */

View File

@@ -15,9 +15,9 @@
struct device;
bool udev_ccw_exists(const char *, const char *);
exit_code_t udev_ccw_read_device(struct device *);
exit_code_t udev_ccw_write_device(struct device *);
exit_code_t udev_ccw_write_cio_ignore(const char *);
bool udev_ccw_exists(const char *type, const char *id, bool autoconf);
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf);
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf);
exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf);
#endif /* UDEV_CCW_H */

View File

@@ -16,10 +16,12 @@
struct device;
struct util_list;
bool udev_ccwgroup_exists(const char *, const char *);
exit_code_t udev_ccwgroup_read_device(struct device *);
exit_code_t udev_ccwgroup_write_device(struct device *);
void udev_ccwgroup_add_device_ids(const char *, struct util_list *);
exit_code_t udev_ccwgroup_remove_rule(const char *, const char *);
bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf);
exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf);
exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf);
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
bool autoconf);
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
bool autoconf);
#endif /* UDEV_CCWGROUP_H */

View File

@@ -15,10 +15,10 @@
struct device;
void udev_zfcp_lun_add_device_ids(struct util_list *);
bool udev_zfcp_lun_exists(const char *);
exit_code_t udev_zfcp_lun_read_device(struct device *);
exit_code_t udev_zfcp_lun_write_device(struct device *);
exit_code_t udev_zfcp_lun_remove_rule(const char *);
void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf);
bool udev_zfcp_lun_exists(const char *id, bool autoconf);
exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf);
exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf);
exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf);
#endif /* UDEV_ZFCP_LUN_H */

22
zdev/initramfs/Makefile Normal file
View File

@@ -0,0 +1,22 @@
# Common definitions
include ../../common.mak
INITRAMFSDIR := /usr/share/initramfs-tools
HOOKDIR := $(INITRAMFSDIR)/hooks
INITTOP := $(INITRAMFSDIR)/scripts/init-top
# HAVE_INITRAMFS
#
# This install time parameter determines whether the zdev initramfs support is
# installed (HAVE_INITRAMFS=1) or not (default). When installed, the module
# performs the following functions when mkinitramfs is run:
#
# - install a boot-time hook to apply firmware-provided configuration data
# to the system
#
ifeq ($(HAVE_INITRAMFS),1)
install:
$(INSTALL) -m 755 -d $(DESTDIR)/$(HOOKDIR) $(DESTDIR)/$(INITTOP)
$(INSTALL) -m 755 hooks/s390-tools-zdev $(DESTDIR)/$(HOOKDIR)
$(INSTALL) -m 755 scripts/init-top/s390-tools-zdev $(DESTDIR)/$(INITTOP)
endif

View File

@@ -0,0 +1,56 @@
#!/bin/sh
#
# Copyright IBM Corp. 2016, 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
# hooks/s390-tools-zdev
# This hook script adds files required to apply firmware-provided I/O
# configuration data during boot.
#
# Needs to run after udev or resulting udev rules could be overwritten
PREREQ="udev"
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
# Add modules for all device types supported by chzdev (required for
# auto-configuration)
zdev_modules="lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod dasd_diag_mod zfcp"
for x in $zdev_modules ; do
manual_add_modules ${x}
done
copy_exec /sbin/chzdev
copy_exec /sbin/lszdev
copy_exec /sbin/vmcp
_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX)
# Obtain early + root device configuration
chzdev --export "$_tempfile" --persistent --by-path / \
--by-attrib "zdev:early=1" --quiet --type 2>/dev/null
# Apply via --import to prevent other devices from being configured.
# Rename the resulting cio-ignore rule to ensure that it does not override
# the one copied by the initramfs udev hook to /lib/udev.
chzdev --import "$_tempfile" --persistent \
--base "/etc/udev/rules.d/41-cio-ignore.rules=$DESTDIR/etc/udev/rules.d/41-cio-ignore-root.rules" \
--base "/etc=$DESTDIR/etc" --yes --quiet --no-root-update --force \
>/dev/null
rm -f "$_tempfile"

View File

@@ -0,0 +1,67 @@
#!/bin/sh
#
# Copyright IBM Corp. 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
# scripts/init-top/s390-tools-zdev
# Parse the kernel command line for rd.zdev kernel parameters. These
# parameters are evaluated and used to configure z Systems specific devices.
#
# Format:
# rd.zdev=no-auto
#
# where
#
# no-auto: Indicates that firmware-provided I/O configuration data
# should not be applied.
#
PREREQ="udev"
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
if [ -e "$zdev_fw_file" ] ; then
zdev_auto=1
else
zdev_auto=0
fi
for x in $(cat /proc/cmdline); do
case ${x} in
rd.zdev=*)
zdev_arg=${x#*=}
if [ "$zdev_arg" = "no-auto" ] ; then
zdev_auto=0
fi
;;
esac
done
if [ $zdev_auto -eq 1 ] ; then
log_begin_msg "Starting firmware auto-configuration"
chzdev --import "$zdev_fw_file" $zdev_base_args
log_end_msg
# Repeat cold-plug after creating udev rules
udevadm control --reload
udevadm trigger --type=subsystems --action=add
udevadm trigger --action=add
udevadm settle || true
fi

View File

@@ -334,6 +334,35 @@ a specific attribute.
.PP
.
.
.SS "Special settings"
The following special settings affect how devices are handled by chzdev:
.PP
.
.BR zdev:early =0|1
.RS 4
Control in which stage of the boot process a device is activated:
.TP 4
.B 0
Device is activated normally during boot (default).
.PP
.TP 4
.B 1
Device is activated early in the boot process, by the initial RAM-disk.
.PP
Specify a value of 1 for this attribute in any of the following situations:
.TP 4
\(bu
To ensure that your settings override auto-configuration settings.
.PP
.TP 4
\(bu
To ensure that a device required to access the root file system is correctly
enabled during boot. An example would be a networking device, or a device that
is intended to extend a logical volume that provides the root file system.
.PP
.RE
.
.
.SH ACTIONS
You can use one of the action options listed below to specify the
.B main tool action
@@ -409,17 +438,27 @@ default value.
.PP
.
.OD import "" "FILENAME" "|-"
Import configuration data from a text file.
Import configuration data from a text or machine-provided file.
Reads configuration data from FILENAME and applies it. If a single hyphen ("-")
is specified as FILENAME data is read from the standard input stream. The
input format of the data read must be the same format as produced by the
chzdev \-\-export action.
input format must be either in the format as produced by the chzdev \-\-export
action, or in the format of a machine-provided I/O configuration data file.
.B Machine-provided data:
Some machine models provide I/O configuration data which is made available
by the Linux kernel via a sysfs interface. While this data is intended for
automatic consumption during the boot phase, you can also apply it manually
using the \-\-import action like in the following example
.B Example:
.CL chzdev --import /sys/firmware/sclp_sd/config/data
.B Note:
By default all configuration data that is read is also applied. To reduce the
scope of imported configuration data, you can select specific devices, a device
type, or define whether only data for the active or persistent configuration
should be imported.
type, or define whether only data for the active, persistent or
auto-configuration should be imported.
.PP
.
.OD list-attributes "l" ""
@@ -462,6 +501,18 @@ on reboot, or when a device becomes unavailable, or when a device driver is
unloaded.
.PP
.
.OD auto-conf "" ""
Apply changes to the auto-configuration only.
This option is used internally to apply machine-provided I/O configuration data
to a Linux system.
.B Note:
There is typically no need for users to specify this option directly.
In particular, user-initiated changes to this configuration will be lost
the next time that machine-provided data is obtained (i.e. during boot).
.PP
.
.OD base "" "PATH" | "KEY" = "VALUE"
Change file system paths used to access files.
@@ -518,6 +569,15 @@ device configuration persistent. Typically such steps include rebuilding the
initial RAM disk, or modifying the kernel command line.
.PP
.
.OD no-settle "" ""
Do not wait for udev processing to complete.
Skips all calls to the udevadm tool that are intended to wait for udev to
finish processing before continuing. There is typically no need to use this
option unless chzdev is run in an environment where udev is not fully
functional (such as in the early phase of an initial RAM disk).
.PP
.
.OD persistent "p" ""
Apply changes to persistent configuration only.

View File

@@ -69,12 +69,13 @@ With no further options specified, the output format defaults to list format.
.
.
.SS "Configurations"
There are two sources for configuration information: the active configuration
of the currently running system, and the persistent configuration stored in
configuration files.
There are three sources for configuration information: the active configuration
of the currently running system, the persistent configuration stored in
configuration files, and the auto-configuration that is provided by some
machine types to automatically enable I/O devices.
.PP
By default lszdev displays information from both the active and the persistent
configuration.
configuration, and, if available, from the auto-configuration.
.PP
.
.
@@ -319,6 +320,19 @@ Restricts output to information obtained from the active configuration, that
is information from the running system.
.PP
.
.OD auto-conf "" ""
List information from the auto-configuration only.
Restricts output to information obtained from the auto-configuration.
The auto-configuration is the collection of configuration data obtained
automatically on some machine models during boot.
.B Note:
This data is refreshed during each boot. Also configuration directives in
the auto-configuration only take effect if there is no directive for the
same device in the persistent configuration.
.PP
.
.OD base "" "PATH" | "KEY" = "VALUE"
Change file system paths used to access files.

View File

@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
root.o select.o setting.o subtype.o table.o table_attribs.o \
table_types.o net.o
table_types.o net.o firmware.o internal.o
# Devtype Helpers
chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
@@ -38,7 +38,7 @@ chzdev_objects += generic_ccw.o
lszdev_objects += attrib.o lszdev.o device.o devnode.o devtype.o exit_code.o \
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
root.o select.o setting.o subtype.o table.o table_types.o \
net.o
net.o internal.o
# Devtype Helpers
lszdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \

View File

@@ -73,6 +73,7 @@ struct attrib ccw_attr_cmb_enable = {
" 1: Data collection is enabled (rewrite 1 to reset data)\n",
.rewrite = 1,
.defval = "0",
.order_cmp = ccw_offline_only_order_cmp,
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
};
@@ -892,12 +893,13 @@ static exit_code_t collect_group_cb(struct subtype *st, const char *id,
}
/* Set bits for all persistently configured CCW devices. */
static char ***id_bitmap_collect(void)
static char ***id_bitmap_collect(bool autoconf)
{
char ***id_bitmap;
int i, j;
struct devtype *dt;
struct subtype *st;
config_t config = autoconf ? config_autoconf : config_persistent;
id_bitmap = id_bitmap_new();
@@ -906,14 +908,14 @@ static char ***id_bitmap_collect(void)
for (j = 0; (st = dt->subtypes[j]); j++) {
/* Collect CCW device IDs. */
if (st->namespace == &ccw_namespace) {
subtype_for_each_id(st, config_persistent,
subtype_for_each_id(st, config,
collect_cb, id_bitmap);
}
/* Collect CCWGROUP device IDs. Since there may be
* multiple namespaces, we need to make use of this
* hack. */
if (ccwgroup_compatible_namespace(st->namespace)) {
subtype_for_each_id(st, config_persistent,
subtype_for_each_id(st, config,
collect_group_cb,
id_bitmap);
}
@@ -952,7 +954,7 @@ static void range_add(struct util_list *list, struct ccw_devid *from,
free(f_str);
}
static struct util_list *cio_ignore_get_ranges(void)
static struct util_list *cio_ignore_get_ranges(bool autoconf)
{
char ***id_bitmap;
unsigned int cssid, ssid, devno;
@@ -962,7 +964,7 @@ static struct util_list *cio_ignore_get_ranges(void)
ranges = strlist_new();
id_bitmap = id_bitmap_collect();
id_bitmap = id_bitmap_collect(autoconf);
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
if (!id_bitmap[cssid])
continue;
@@ -1003,24 +1005,34 @@ static struct util_list *cio_ignore_get_ranges(void)
}
/* Persistently configure cio_ignore. */
exit_code_t ccw_blacklist_persist(void)
static exit_code_t _ccw_blacklist_persist(bool autoconf)
{
struct util_list *ranges;
char *id_list;
exit_code_t rc;
/* Get string to write to /proc/cio_ignore. */
ranges = cio_ignore_get_ranges();
ranges = cio_ignore_get_ranges(autoconf);
id_list = strlist_flatten(ranges, ",");
strlist_free(ranges);
/* Write udev rule to automatically write cio_ignore. */
rc = udev_ccw_write_cio_ignore(id_list);
rc = udev_ccw_write_cio_ignore(id_list, autoconf);
free(id_list);
return rc;
}
exit_code_t ccw_blacklist_persist(void)
{
exit_code_t rc1, rc2;
rc1 = _ccw_blacklist_persist(false);
rc2 = _ccw_blacklist_persist(true);
return rc1 ? rc1 : rc2;
}
/*
* CCW device ID namespace.
*/
@@ -1368,7 +1380,13 @@ static bool ccw_st_exists_active(struct subtype *st, const char *id)
/* Check if a configuration exists for a CCW device with the specified @id. */
static bool ccw_st_exists_persistent(struct subtype *st, const char *id)
{
return udev_ccw_exists(st->name, id);
return udev_ccw_exists(st->name, id, false);
}
/* Check if a configuration exists for a CCW device with the specified @id. */
static bool ccw_st_exists_autoconf(struct subtype *st, const char *id)
{
return udev_ccw_exists(st->name, id, true);
}
static bool get_ids_cb(const char *file, void *data)
@@ -1404,7 +1422,14 @@ static void ccw_st_add_active_ids(struct subtype *st, struct util_list *ids)
* to strlist @ids. */
static void ccw_st_add_persistent_ids(struct subtype *st, struct util_list *ids)
{
udev_get_device_ids(st->name, ids);
udev_get_device_ids(st->name, ids, false);
}
/* Add the IDs of all CCW devices for which a autoconf configuration exists
* to strlist @ids. */
static void ccw_st_add_autoconf_ids(struct subtype *st, struct util_list *ids)
{
udev_get_device_ids(st->name, ids, true);
}
/* Read the configuration of the CCW device with the specified @id from the
@@ -1440,7 +1465,16 @@ static exit_code_t ccw_st_read_persistent(struct subtype *st,
struct device *dev,
read_scope_t scope)
{
return udev_ccw_read_device(dev);
return udev_ccw_read_device(dev, false);
}
/* Read the configuration of the CCW device with the specified @id from the
* autoconf configuration and add the resulting data to @dev. */
static exit_code_t ccw_st_read_autoconf(struct subtype *st,
struct device *dev,
read_scope_t scope)
{
return udev_ccw_read_device(dev, true);
}
static int get_online(struct setting_list *list)
@@ -1505,7 +1539,14 @@ static exit_code_t ccw_st_configure_active(struct subtype *st,
static exit_code_t ccw_st_configure_persistent(struct subtype *st,
struct device *dev)
{
return udev_ccw_write_device(dev);
return udev_ccw_write_device(dev, false);
}
/* Create a autoconf configuration for the specified device @dev. */
static exit_code_t ccw_st_configure_autoconf(struct subtype *st,
struct device *dev)
{
return udev_ccw_write_device(dev, true);
}
@@ -1552,7 +1593,22 @@ static exit_code_t ccw_st_deconfigure_active(struct subtype *st,
static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st,
struct device *dev)
{
return udev_remove_rule(st->name, dev->id);
return udev_remove_rule(st->name, dev->id, false);
}
/**
* ccw_st_deconfigure_autoconf - Deconfigure device in autoconf
* configuration set
* @st: Subtype of target device
* @dev: Target device
*
* Deconfigure device @dev in the autoconf configuration set. Return %EXIT_OK
* on success, an error code otherwise.
*/
static exit_code_t ccw_st_deconfigure_autoconf(struct subtype *st,
struct device *dev)
{
return udev_remove_rule(st->name, dev->id, true);
}
/* Perform basic sanity checks. */
@@ -1589,6 +1645,8 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev,
setting_list_apply(dev->active.settings, a, name, value);
if (SCOPE_PERSISTENT(config))
setting_list_apply(dev->persistent.settings, a, name, value);
if (SCOPE_AUTOCONF(config))
setting_list_apply(dev->autoconf.settings, a, name, value);
}
/* Determine the online state of the specified CCW device (0=offline, 1=online,
@@ -1596,14 +1654,16 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev,
static int ccw_st_online_get(struct subtype *st, struct device *dev,
config_t config)
{
int act_online = 1, pers_online = 1;
int act_online = 1, pers_online = 1, auto_online = 1;
if (SCOPE_ACTIVE(config))
act_online = get_online(dev->active.settings);
if (SCOPE_PERSISTENT(config))
pers_online = get_online(dev->persistent.settings);
if (SCOPE_AUTOCONF(config))
auto_online = get_online(dev->autoconf.settings);
return MIN(act_online, pers_online);
return MIN(MIN(act_online, pers_online), auto_online);
}
/* Determine if the online state of the specified CCW device was specified */
@@ -1622,6 +1682,11 @@ static bool ccw_st_online_specified(struct subtype *st, struct device *dev,
if (s && s->specified)
return true;
}
if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
s = setting_list_find(dev->autoconf.settings, "online");
if (s && s->specified)
return true;
}
return false;
}
@@ -1769,18 +1834,23 @@ struct subtype ccw_subtype = {
.exists_active = &ccw_st_exists_active,
.exists_persistent = &ccw_st_exists_persistent,
.exists_autoconf = &ccw_st_exists_autoconf,
.add_active_ids = &ccw_st_add_active_ids,
.add_persistent_ids = &ccw_st_add_persistent_ids,
.add_autoconf_ids = &ccw_st_add_autoconf_ids,
.read_active = &ccw_st_read_active,
.read_persistent = &ccw_st_read_persistent,
.read_autoconf = &ccw_st_read_autoconf,
.configure_active = &ccw_st_configure_active,
.configure_persistent = &ccw_st_configure_persistent,
.configure_autoconf = &ccw_st_configure_autoconf,
.deconfigure_active = &ccw_st_deconfigure_active,
.deconfigure_persistent = &ccw_st_deconfigure_persistent,
.deconfigure_autoconf = &ccw_st_deconfigure_autoconf,
.check_pre_configure = &ccw_st_check_pre_configure,

View File

@@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struct subtype *st, struct device *dev,
}
if (SCOPE_PERSISTENT(config))
setting_list_apply(dev->persistent.settings, a, name, value);
if (SCOPE_AUTOCONF(config))
setting_list_apply(dev->autoconf.settings, a, name, value);
}
static int get_online(struct setting_list *list)
@@ -446,18 +448,20 @@ static int get_online(struct setting_list *list)
}
/* Return -1 if online state is not configured, 0 for offline and 1 for online.
* If multiple configurations are specified, return the minimum of both. */
* If multiple configurations are specified, return the minimum of all. */
static int ccwgroup_st_online_get(struct subtype *st, struct device *dev,
config_t config)
{
int act_online = 1, pers_online = 1;
int act_online = 1, pers_online = 1, auto_online = 1;
if (SCOPE_ACTIVE(config))
act_online = get_online(dev->active.settings);
if (SCOPE_PERSISTENT(config))
pers_online = get_online(dev->persistent.settings);
if (SCOPE_AUTOCONF(config))
auto_online = get_online(dev->autoconf.settings);
return MIN(act_online, pers_online);
return MIN(MIN(act_online, pers_online), auto_online);
}
/* Determine if the online state of the specified device was modified. */
@@ -476,6 +480,11 @@ static bool ccwgroup_st_online_specified(struct subtype *st,
if (s && s->specified)
return true;
}
if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
s = setting_list_find(dev->autoconf.settings, "online");
if (s && s->specified)
return true;
}
return false;
}
@@ -682,7 +691,18 @@ static exit_code_t ccwgroup_st_read_persistent(struct subtype *st,
expand_id(data->ccwgroupdrv, dev);
return udev_ccwgroup_read_device(dev);
return udev_ccwgroup_read_device(dev, false);
}
static exit_code_t ccwgroup_st_read_autoconf(struct subtype *st,
struct device *dev,
read_scope_t scope)
{
struct ccwgroup_subtype_data *data = st->data;
expand_id(data->ccwgroupdrv, dev);
return udev_ccwgroup_read_device(dev, true);
}
static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
@@ -693,8 +713,9 @@ static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
return device_write_active_settings(dev);
}
static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
struct device *dev)
static exit_code_t _ccwgroup_st_configure_persistent(struct subtype *st,
struct device *dev,
bool autoconf)
{
struct ccwgroup_subtype_data *data = st->data;
struct ccwgroup_devid *devid = dev->devid;
@@ -703,9 +724,22 @@ static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
delayed_err("Incomplete device ID specified\n");
return EXIT_INCOMPLETE_ID;
}
return udev_ccwgroup_write_device(dev);
return udev_ccwgroup_write_device(dev, autoconf);
}
static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
struct device *dev)
{
return _ccwgroup_st_configure_persistent(st, dev, false);
}
static exit_code_t ccwgroup_st_configure_autoconf(struct subtype *st,
struct device *dev)
{
return _ccwgroup_st_configure_persistent(st, dev, true);
}
static char *ccwgroup_st_get_active_attrib_path(struct subtype *,
struct device *, const char *);
@@ -733,7 +767,13 @@ static exit_code_t ccwgroup_st_deconfigure_active(struct subtype *st,
static exit_code_t ccwgroup_st_deconfigure_persistent(struct subtype *st,
struct device *dev)
{
return udev_ccwgroup_remove_rule(st->name, dev->id);
return udev_ccwgroup_remove_rule(st->name, dev->id, false);
}
static exit_code_t ccwgroup_st_deconfigure_autoconf(struct subtype *st,
struct device *dev)
{
return udev_ccwgroup_remove_rule(st->name, dev->id, true);
}
/* Check if a CCWGROUP device with the specified ID exists. */
@@ -774,7 +814,12 @@ static bool ccwgroup_st_exists_active(struct subtype *st, const char *id)
static bool ccwgroup_st_exists_persistent(struct subtype *st, const char *id)
{
return udev_ccwgroup_exists(st->name, id);
return udev_ccwgroup_exists(st->name, id, false);
}
static bool ccwgroup_st_exists_autoconf(struct subtype *st, const char *id)
{
return udev_ccwgroup_exists(st->name, id, true);
}
int ccwgroup_qsort_cmp(const void *a_ptr, const void *b_ptr)
@@ -796,7 +841,13 @@ static void ccwgroup_st_add_active_ids(struct subtype *st,
static void ccwgroup_st_add_persistent_ids(struct subtype *st,
struct util_list *ids)
{
udev_ccwgroup_add_device_ids(st->name, ids);
udev_ccwgroup_add_device_ids(st->name, ids, false);
}
static void ccwgroup_st_add_autoconf_ids(struct subtype *st,
struct util_list *ids)
{
udev_ccwgroup_add_device_ids(st->name, ids, true);
}
/* Check if CCW device ID @b is part of CCW group device ID @a. */
@@ -1185,18 +1236,23 @@ struct subtype ccwgroup_subtype = {
.exists_active = &ccwgroup_st_exists_active,
.exists_persistent = &ccwgroup_st_exists_persistent,
.exists_autoconf = &ccwgroup_st_exists_autoconf,
.add_active_ids = &ccwgroup_st_add_active_ids,
.add_persistent_ids = &ccwgroup_st_add_persistent_ids,
.add_autoconf_ids = &ccwgroup_st_add_autoconf_ids,
.read_active = &ccwgroup_st_read_active,
.read_persistent = &ccwgroup_st_read_persistent,
.read_autoconf = &ccwgroup_st_read_autoconf,
.configure_active = &ccwgroup_st_configure_active,
.configure_persistent = &ccwgroup_st_configure_persistent,
.configure_autoconf = &ccwgroup_st_configure_autoconf,
.deconfigure_active = &ccwgroup_st_deconfigure_active,
.deconfigure_persistent = &ccwgroup_st_deconfigure_persistent,
.deconfigure_autoconf = &ccwgroup_st_deconfigure_autoconf,
.online_set = &ccwgroup_st_online_set,
.online_get = &ccwgroup_st_online_get,

View File

@@ -27,6 +27,7 @@
#include "devnode.h"
#include "devtype.h"
#include "export.h"
#include "firmware.h"
#include "inuse.h"
#include "misc.h"
#include "module.h"
@@ -85,6 +86,7 @@ struct options {
config_t config;
unsigned int active:1;
unsigned int persistent:1;
unsigned int auto_conf:1;
struct util_list *remove; /* List of struct strlist_node */
unsigned int remove_all:1;
unsigned int force:1;
@@ -94,6 +96,7 @@ struct options {
struct util_list *base; /* List of struct strlist_node */
unsigned int verbose:1;
unsigned int quiet:1;
unsigned int no_settle:1;
};
/* Makefile converts chzdev_usage.txt into C file which we include here. */
@@ -135,6 +138,8 @@ enum {
OPT_VERSION = 'v',
OPT_VERBOSE = 'V',
OPT_QUIET = 'q',
OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
};
static struct opts_conflict conflict_list[] = {
@@ -169,11 +174,13 @@ static struct opts_conflict conflict_list[] = {
OPTS_CONFLICT(OPT_APPLY,
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
OPT_REMOVE_ALL, OPT_ACTIVE, OPT_PERSISTENT, 0),
OPT_REMOVE_ALL, OPT_ACTIVE, 0),
OPTS_CONFLICT(OPT_ONLINE,
OPT_OFFLINE),
OPTS_CONFLICT(OPT_QUIET,
OPT_VERBOSE),
OPTS_CONFLICT(OPT_AUTO_CONF,
OPT_TYPE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES),
OPTS_CONFLICT(0, 0),
};
@@ -207,6 +214,7 @@ static const struct option opt_list[] = {
/* Options. */
{ "active", no_argument, NULL, OPT_ACTIVE },
{ "persistent", no_argument, NULL, OPT_PERSISTENT },
{ "auto-conf", no_argument, NULL, OPT_AUTO_CONF },
{ "remove", required_argument, NULL, OPT_REMOVE },
{ "remove-all", no_argument, NULL, OPT_REMOVE_ALL },
{ "force", no_argument, NULL, OPT_FORCE },
@@ -216,6 +224,7 @@ static const struct option opt_list[] = {
{ "base", required_argument, NULL, OPT_BASE },
{ "verbose", no_argument, NULL, OPT_VERBOSE },
{ "quiet", no_argument, NULL, OPT_QUIET },
{ "no-settle", no_argument, NULL, OPT_NO_SETTLE },
{ NULL, no_argument, NULL, 0 },
};
@@ -879,6 +888,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
opts->persistent = 1;
break;
case OPT_AUTO_CONF:
/* --auto-conf */
opts->auto_conf = 1;
break;
case OPT_REMOVE:
/* --remove ATTRIB */
strlist_add(opts->remove, "%s", optarg);
@@ -936,6 +950,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
opts->quiet = 1;
break;
case OPT_NO_SETTLE:
/* --no-settle */
opts->no_settle = 1;
break;
case ':':
/* Missing option argument. */
syntax("Option '%s' requires an argument\n",
@@ -968,7 +987,13 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
goto out;
/* Determine configuration set. */
opts->config = get_config(opts->active, opts->persistent);
if (!opts->active && !opts->persistent && !opts->auto_conf) {
/* Default configuration targets are active + persistent */
opts->config = config_active | config_persistent;
} else {
opts->config = get_config(opts->active, opts->persistent,
opts->auto_conf);
}
/* Handle positional parameters. */
rc = parse_positional(opts, argc, argv, optind);
@@ -1040,13 +1065,15 @@ static void remove_all_settings(struct setting_list *settings, int active)
/* Perform --remove-all operation for specified config on device. */
static exit_code_t device_remove_all(struct device *dev, config_t config)
{
int active, persistent;
int active, persistent, autoconf;
active = SCOPE_ACTIVE(config) ?
count_removable(dev->active.settings, 1) : 0;
persistent = SCOPE_PERSISTENT(config) ?
count_removable(dev->persistent.settings, 0) : 0;
if (active == 0 && persistent == 0) {
autoconf = SCOPE_AUTOCONF(config) ?
count_removable(dev->autoconf.settings, 0) : 0;
if (active == 0 && persistent == 0 && autoconf == 0) {
delayed_err("No removable settings found\n");
return EXIT_SETTING_NOT_FOUND;
}
@@ -1054,6 +1081,8 @@ static exit_code_t device_remove_all(struct device *dev, config_t config)
remove_all_settings(dev->active.settings, 1);
if (persistent)
remove_all_settings(dev->persistent.settings, 0);
if (autoconf)
remove_all_settings(dev->autoconf.settings, 0);
return EXIT_OK;
}
@@ -1123,6 +1152,13 @@ static exit_code_t device_remove_settings(struct device *dev,
goto out;
}
if (SCOPE_AUTOCONF(config)) {
rc = remove_settings(dev->autoconf.settings, names, found,
notfound, 0);
if (rc)
goto out;
}
if (!util_list_is_empty(notfound)) {
flat = strlist_flatten(notfound, " ");
delayed_err("Setting not found: %s\n", flat);
@@ -1190,7 +1226,8 @@ static void print_dev_config_info(struct device *dev, config_t config)
changes = setting_get_changes(
SCOPE_ACTIVE(config) ? dev->active.settings : NULL,
SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL);
SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL,
SCOPE_AUTOCONF(config) ? dev->autoconf.settings : NULL);
if (changes)
info(" Changes: %s\n", changes);
free(changes);
@@ -1248,6 +1285,12 @@ static exit_code_t cfg_mod_existence(struct device *dev, config_t config)
dev->persistent.modified = 1;
}
/* Create autoconf config if necessary. */
if (SCOPE_AUTOCONF(config) && !dev->autoconf.exists) {
dev->autoconf.exists = 1;
dev->autoconf.modified = 1;
}
return EXIT_OK;
}
@@ -1287,11 +1330,14 @@ online:
/* Make sure there's an online attribute. */
ensure_online(dev, config_active);
ensure_online(dev, config_persistent);
ensure_online(dev, config_autoconf);
mand:
/* Ensure default values for mandatory attributes. */
setting_list_apply_defaults(dev->persistent.settings,
dev->subtype->dev_attribs, true);
setting_list_apply_defaults(dev->autoconf.settings,
dev->subtype->dev_attribs, true);
return EXIT_OK;
}
@@ -1324,10 +1370,11 @@ static exit_code_t cfg_write(struct device *dev, int prereq, config_t config,
struct subtype *st = dev->subtype;
exit_code_t rc = EXIT_OK;
if (!device_needs_writing(dev, config))
if (!device_needs_writing(dev, config) && !force)
goto out;
if (check_active && config == config_persistent &&
if (check_active && !SCOPE_ACTIVE(config) &&
(SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) &&
(!dev->active.exists && !dev->active.definable)) {
rc = handle_nonexistent(dev);
if (rc)
@@ -1368,7 +1415,7 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
if (proc_ptr)
*proc_ptr = 0;
/* Read current device data. Note that we read data from both
/* Read current device data. Note that we read data from all
* configurations to enable QETH autodetection and subtype
* detection (e.g. dasd -> dasd_fba).*/
dev = NULL;
@@ -1389,23 +1436,17 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
/* Exit here if we're only trying and device cannot be configured. */
if (try && !(dev->active.exists || dev->active.definable ||
dev->persistent.exists)) {
dev->persistent.exists || dev->autoconf.exists)) {
return EXIT_DEVICE_NOT_FOUND;
}
if (config == config_persistent) {
/* Abort if a modification action is triggered for a
* non-existing persistent device. */
if (!dev->persistent.exists &&
(!util_list_is_empty(opts->remove) || opts->remove_all))
return EXIT_DEVICE_NOT_FOUND;
/* Create device if needed by action. */
if (opts->enable || !util_list_is_empty(opts->settings)) {
rc = cfg_mod_existence(dev, config);
if (rc)
return rc;
}
/* Apply changes to device existence. */
rc = cfg_mod_existence(dev, config);
if (rc)
return rc;
/* Apply changes to device settings. */
rc = cfg_mod_settings(dev, opts, prereq);
if (rc)
@@ -1417,10 +1458,12 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
/* Apply persistent configuration to active configuration. */
static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
struct device **dev_ptr, int *proc_ptr)
struct device **dev_ptr, int *proc_ptr,
bool autoconf)
{
exit_code_t rc;
struct device *dev;
struct device_state *state;
/* Reset processed flag. */
if (proc_ptr)
@@ -1443,8 +1486,9 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
*proc_ptr = 1;
dev->processed = 1;
state = autoconf ? &dev->autoconf : &dev->persistent;
/* Exit here if there is no persistent configuration. */
if (!dev->persistent.exists)
if (!state->exists)
return EXIT_NO_DATA;
/* Apply changes to device existence. */
@@ -1453,8 +1497,7 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
return rc;
/* Copy persistent settings to active configuration. */
rc = device_apply_settings(dev, config_active,
&dev->persistent.settings->list);
rc = device_apply_settings(dev, config_active, &state->settings->list);
if (rc)
return rc;
@@ -1468,7 +1511,8 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
struct device **dev_ptr, int *proc_ptr)
{
exit_code_t rc;
struct setting_list *active = NULL, *persistent = NULL;
struct setting_list *active = NULL, *persistent = NULL,
*autoconf = NULL;
struct device *dev;
/* Reset processed flag. */
@@ -1486,6 +1530,7 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
return EXIT_OK;
active = setting_list_copy(dev->active.settings);
persistent = setting_list_copy(dev->persistent.settings);
autoconf = setting_list_copy(dev->autoconf.settings);
} else if (!prereq) {
/* Should not happen. */
return EXIT_OK;
@@ -1515,14 +1560,20 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
&persistent->list);
if (rc)
goto out;
rc = device_apply_settings(dev, config_autoconf,
&autoconf->list);
if (rc)
goto out;
}
ensure_online(dev, config_active);
ensure_online(dev, config_persistent);
ensure_online(dev, config_autoconf);
/* Write resulting device data. */
rc = cfg_write(dev, prereq, config, 0);
out:
setting_list_free(autoconf);
setting_list_free(persistent);
setting_list_free(active);
@@ -1600,11 +1651,13 @@ static exit_code_t print_config_result(struct selected_dev_node *sel,
if (opts->deconfigure) {
op = "deconfigure";
verb = "deconfigured";
if (dev)
if (dev) {
already = !dev->active.modified &&
!dev->persistent.modified;
else if (rc == EXIT_DEVICE_NOT_FOUND &&
config == config_persistent) {
!dev->persistent.modified &&
!dev->autoconf.modified;
} else if (rc == EXIT_DEVICE_NOT_FOUND &&
(!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
SCOPE_AUTOCONF(config)))) {
rc = EXIT_OK;
already = 1;
}
@@ -1615,6 +1668,10 @@ static exit_code_t print_config_result(struct selected_dev_node *sel,
already = device_needs_writing(dev, config) ? 0 : 1;
}
/* Re-do actions if run with --force */
if (force)
already = 0;
if (dev) {
devname = dev->subtype->devname;
devid = dev->id;
@@ -1672,9 +1729,10 @@ static exit_code_t cfg_prereqs(struct subtype *st, const char *id,
prereqs = selected_dev_list_new();
subtype_add_prereqs(st, id, prereqs);
util_list_iterate(prereqs, sel) {
if (opts->apply)
rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc);
else if (opts->import) {
if (opts->apply) {
rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc,
opts->auto_conf);
} else if (opts->import) {
rc = cfg_import(sel->st, sel->id, config, 1, &dev,
&proc);
} else {
@@ -1747,9 +1805,11 @@ static exit_code_t configure_devices(struct options *opts, int specified,
struct namespace *ns;
const char *param;
struct device *dev;
config_t config = opts->config;
/* Determine list of selected devices. */
if (opts->config == config_persistent ||
if ((!SCOPE_ACTIVE(config) &&
(SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config))) ||
(opts->select->subtype && opts->select->subtype->support_definable))
existing = 0;
else
@@ -1795,9 +1855,10 @@ static exit_code_t configure_devices(struct options *opts, int specified,
goto next;
/* Configure actual target device. */
if (opts->apply)
rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc);
else {
if (opts->apply) {
rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc,
opts->auto_conf);
} else {
rc = cfg_configure(sel->st, sel->id, opts, 0,
0, &dev, &proc);
}
@@ -1893,7 +1954,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
dev->processed = 1;
if (try && !(dev->active.exists || dev->active.definable ||
dev->persistent.exists)) {
dev->persistent.exists || dev->autoconf.exists)) {
/* Attempt to deconfigure this device will fail. */
return EXIT_DEVICE_NOT_FOUND;
}
@@ -1903,7 +1964,8 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
* dev. */
if (SCOPE_ACTIVE(config) &&
!(dev->active.exists || dev->active.definable)) {
if (!SCOPE_PERSISTENT(config) || !dev->persistent.exists)
if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) ||
(SCOPE_AUTOCONF(config) && dev->autoconf.exists)))
return EXIT_DEVICE_NOT_FOUND;
}
@@ -1927,7 +1989,12 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
dev->persistent.deconfigured = 1;
dev->persistent.modified = 1;
}
if (!dev->active.modified && !dev->persistent.modified)
if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) {
dev->autoconf.deconfigured = 1;
dev->autoconf.modified = 1;
}
if (!dev->active.modified && !dev->persistent.modified &&
!dev->autoconf.modified)
return EXIT_OK;
/* Pre-write check. */
@@ -2071,7 +2138,8 @@ static void print_type_config_info(struct devtype *dt, const char *title,
changes = setting_get_changes(
SCOPE_ACTIVE(config) ? dt->active_settings : NULL,
SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL);
SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL,
NULL);
if (changes)
info(" %s: %s\n", title, changes);
free(changes);
@@ -2485,6 +2553,8 @@ static void action_note(const char *msg, config_t config)
info("%s the active configuration only\n", msg);
else if (config == config_persistent)
info("%s the persistent configuration only\n", msg);
else if (config == config_autoconf)
info("%s the auto-configuration only\n", msg);
}
/* Export configuration of selected devices and/or device type to file. */
@@ -2500,9 +2570,9 @@ static exit_code_t do_export(struct options *opts)
/* Open output stream. */
if (strcmp(opts->export, "-") == 0) {
fd = stdout;
info("Exporting configuration data to standard output\n");
info("Exporting data to standard output\n");
} else {
info("Exporting configuration data to %s\n", opts->export);
info("Exporting data to %s\n", opts->export);
if (!util_path_exists(opts->export)) {
rc = path_create(opts->export);
if (rc)
@@ -2606,7 +2676,7 @@ static exit_code_t import_device(struct device *dev, struct options *opts)
struct subtype *st = dev->subtype;
exit_code_t rc;
config_t config;
int proc = 0, active, persistent;
int proc = 0, active, persistent, autoconf;
if (SCOPE_ACTIVE(opts->config))
active = (dev->active.exists || dev->active.definable);
@@ -2616,7 +2686,16 @@ static exit_code_t import_device(struct device *dev, struct options *opts)
persistent = dev->persistent.exists;
else
persistent = 0;
config = get_config(active, persistent);
if (SCOPE_AUTOCONF(opts->config))
autoconf = dev->autoconf.exists;
else
autoconf = 0;
if (!active && !persistent && !autoconf) {
/* Nothing to import */
return EXIT_OK;
}
config = get_config(active, persistent, autoconf);
/* First check for prerequisite devices that need to be configured. */
rc = cfg_prereqs(st, dev->id, opts, config, 0);
@@ -2643,17 +2722,9 @@ static bool import_device_selected(struct device *dev, struct options *opts)
if (!select_opts_dev_specified(select))
return false;
/* --active */
if (opts->config == config_active) {
if (!dev->active.exists && !dev->active.definable)
return false;
}
/* --persistent */
if (opts->config == config_persistent) {
if (!dev->persistent.exists)
return false;
}
/* Target configuration */
if ((device_get_config(dev) & opts->config) == 0)
return false;
/* Devtype */
if (select->devtype && dt != select->devtype)
@@ -2735,6 +2806,7 @@ static exit_code_t do_import(struct options *opts)
exit_code_t drc = EXIT_OK;
const char *filename;
int found;
bool is_firmware;
/* Open input stream. */
if (strcmp(opts->import, "-") == 0) {
@@ -2744,16 +2816,23 @@ static exit_code_t do_import(struct options *opts)
fd = fopen(opts->import, "r");
filename = opts->import;
}
info("Importing configuration data from %s\n", filename);
if (!fd) {
error("Could not open file %s: %s\n", opts->import,
strerror(errno));
return EXIT_RUNTIME_ERROR;
}
is_firmware = firmware_detect(fd);
info("Importing data from %s%s\n", filename,
is_firmware ? " (firmware format)" : "");
/* Read data. */
objects = ptrlist_new();
rc = export_read(fd, filename, objects);
if (is_firmware)
rc = firmware_read(fd, filename, -1, opts->config, objects);
else
rc = export_read(fd, filename, objects);
if (rc)
goto out;
@@ -2766,8 +2845,8 @@ static exit_code_t do_import(struct options *opts)
"selection\n", filename);
rc = EXIT_EMPTY_SELECTION;
} else {
error("%s: No settings found to import\n", filename);
rc = EXIT_NO_DATA;
info("%s: No settings found to import\n", filename);
rc = EXIT_OK;
}
goto out;
}
@@ -2895,6 +2974,7 @@ int main(int argc, char *argv[])
force = opts.force;
yes = opts.yes;
dryrun = opts.dryrun;
udev_no_settle = opts.no_settle;
path_set_base(opts.base);
if (dryrun)
@@ -2945,8 +3025,8 @@ int main(int argc, char *argv[])
if ((pers_mod_devs || pers_mod_devtypes) && !opts.no_root_check &&
!dryrun) {
/* If the root device/device type has been modified, additional
* work might be necessary. */
/* If the root device/device type or early devices have been
* modified, additional work might be necessary. */
rc = root_check();
if (rc && !drc)
drc = rc;

View File

@@ -54,5 +54,7 @@ OPTIONS
--no-root-update Skip root device update
--dry-run Display changes without applying
--base PATH Use PATH as base for accessing files
--no-settle Do not wait for udev to settle
--auto-conf Apply changes to auto-configuration only
-V, --verbose Print additional run-time information
-q, --quiet Print only minimal run-time information

View File

@@ -17,6 +17,7 @@
#include "ctc_auto.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "misc.h"
#include "namespace.h"
#include "path.h"
@@ -425,6 +426,7 @@ static struct subtype ctc_subtype = {
&ccw_attr_online,
&ctc_attr_buffer,
&ctc_attr_protocol,
&internal_attr_early,
),
.unknown_dev_attribs = 1,
.support_definable = 1,

View File

@@ -16,6 +16,7 @@
#include "dasd.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "misc.h"
#include "modprobe.h"
#include "module.h"
@@ -316,34 +317,34 @@ static struct attrib dasd_attr_safe_offline = {
* DASD subtype methods.
*/
static bool _check_use_diag(struct setting_list *list)
{
struct setting *u;
u = setting_list_find(list, dasd_attr_use_diag.name);
if (u && u->modified) {
if (u->value && atoi(u->value) == 1) {
delayed_warn("Cannot set 'use_diag=1' on non-z/VM system\n");
return false;
}
}
return true;
}
/* Check if use_diag setting can be correctly applied. */
static exit_code_t check_use_diag(struct device *dev, config_t config)
{
struct setting *u;
int zvm = is_zvm();
if (is_zvm())
return EXIT_OK;
if (SCOPE_ACTIVE(config)) {
u = setting_list_find(dev->active.settings,
dasd_attr_use_diag.name);
if (u && u->modified) {
if (u->value && atoi(u->value) == 1 && !zvm) {
delayed_warn("Cannot set 'use_diag=1' on "
"non-z/VM system\n");
return EXIT_INVALID_CONFIG;
}
}
}
if (SCOPE_PERSISTENT(config)) {
u = setting_list_find(dev->persistent.settings,
dasd_attr_use_diag.name);
if (u && u->modified) {
if (u->value && atoi(u->value) == 1 && !zvm) {
delayed_warn("Cannot set 'use_diag=1' on "
"non-z/VM system\n");
return EXIT_INVALID_CONFIG;
}
}
}
if (SCOPE_ACTIVE(config) && !_check_use_diag(dev->active.settings))
return EXIT_INVALID_CONFIG;
if (SCOPE_PERSISTENT(config) &&
!_check_use_diag(dev->persistent.settings))
return EXIT_INVALID_CONFIG;
if (SCOPE_AUTOCONF(config) &&
!_check_use_diag(dev->autoconf.settings))
return EXIT_INVALID_CONFIG;
return EXIT_OK;
}
@@ -376,6 +377,8 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev,
dasd_attr_use_diag.name, &changed, &aset);
setting_list_get_bool_state(dev->persistent.settings,
dasd_attr_use_diag.name, &changed, &pset);
setting_list_get_bool_state(dev->autoconf.settings,
dasd_attr_use_diag.name, &changed, &pset);
if (aset || pset)
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
@@ -589,7 +592,7 @@ static struct ccw_subtype_data dasd_eckd_data = {
.mod = "dasd_eckd_mod",
};
static struct subtype dasd_subtype_eckd = {
struct subtype dasd_subtype_eckd = {
.super = &ccw_subtype,
.devtype = &dasd_devtype,
.name = "dasd-eckd",
@@ -614,6 +617,7 @@ static struct subtype dasd_subtype_eckd = {
&dasd_attr_reservation_policy,
&dasd_attr_last_known_reservation_state,
&dasd_attr_safe_offline,
&internal_attr_early,
),
.unknown_dev_attribs = 1,
@@ -626,7 +630,7 @@ static struct ccw_subtype_data dasd_fba_data = {
.mod = "dasd_fba_mod",
};
static struct subtype dasd_subtype_fba = {
struct subtype dasd_subtype_fba = {
.super = &ccw_subtype,
.devtype = &dasd_devtype,
.name = "dasd-fba",
@@ -649,6 +653,7 @@ static struct subtype dasd_subtype_fba = {
&dasd_attr_reservation_policy,
&dasd_attr_last_known_reservation_state,
&dasd_attr_safe_offline,
&internal_attr_early,
),
.unknown_dev_attribs = 1,

View File

@@ -16,6 +16,7 @@
#include "attrib.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "misc.h"
#include "namespace.h"
#include "setting.h"
@@ -40,6 +41,7 @@ struct device *device_new(struct subtype *st, const char *id)
dev->active.settings = setting_list_new();
dev->persistent.settings = setting_list_new();
dev->autoconf.settings = setting_list_new();
return dev;
}
@@ -53,6 +55,7 @@ void device_free(struct device *dev)
free(dev->devid);
setting_list_free(dev->active.settings);
setting_list_free(dev->persistent.settings);
setting_list_free(dev->autoconf.settings);
free(dev);
}
@@ -83,6 +86,15 @@ void device_print(struct device *dev, int level)
setting_list_print(dev->persistent.settings, level + 8);
else
printf("%*s<none>\n", level + 8, "");
printf("%*sautoconf:\n", level + 4, "");
printf("%*sexists=%d mod=%d deconf=%d\n",
level + 8, "", dev->autoconf.exists, dev->autoconf.modified,
dev->autoconf.deconfigured);
if (dev->autoconf.settings)
setting_list_print(dev->autoconf.settings, level + 8);
else
printf("%*s<none>\n", level + 8, "");
}
static const void *device_hash_get_id(void *dev_ptr)
@@ -182,6 +194,10 @@ bool device_needs_writing(struct device *dev, config_t config)
(dev->persistent.modified || dev->persistent.deconfigured ||
setting_list_modified(dev->persistent.settings)))
return true;
if (SCOPE_AUTOCONF(config) &&
(dev->autoconf.modified || dev->autoconf.deconfigured ||
setting_list_modified(dev->autoconf.settings)))
return true;
return false;
}
@@ -204,6 +220,11 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
/* Check for activeonly. */
if (!force && SCOPE_PERSISTENT(config) && a->activeonly)
goto err_activeonly_forceable;
if (!force && SCOPE_AUTOCONF(config) && a->activeonly)
goto err_activeonly_forceable;
/* Check for internal. */
if (config == config_active && a->internal)
goto err_int_noactive;
/* Check for multiple values. */
if (!force && !a->multi && strlist_find(processed, key))
goto err_multi_forceable;
@@ -213,6 +234,9 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
goto err_unknown;
if (!force)
goto err_unknown_forceable;
/* Check for internal. */
if (config == config_active && internal_by_name(key))
goto err_int_noactive;
}
strlist_add(processed, "%s", key);
@@ -231,8 +255,15 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
a, key, value);
}
/* Apply to autoconf config. */
if (SCOPE_AUTOCONF(config)) {
setting_list_apply_specified(dev->autoconf.settings,
a, key, value);
}
/* Additional warning when trying to persist read-only setting. */
if (config == config_persistent) {
if (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
SCOPE_AUTOCONF(config))) {
s = setting_list_find(dev->active.settings, key);
if (s && s->readonly)
warn_readonly = true;
@@ -270,6 +301,11 @@ err_activeonly_forceable:
delayed_forceable("Attribute '%s' should only be changed in the active "
"config\n", a->name);
return EXIT_INVALID_SETTING;
err_int_noactive:
delayed_err("Internal attribute '%s' cannot be set in the active config\n",
key);
return EXIT_INVALID_SETTING;
}
/* Apply device settings from strlist to device. */
@@ -341,6 +377,8 @@ void device_reset(struct device *dev, config_t config)
reset_device_state(&dev->active);
if (SCOPE_PERSISTENT(config))
reset_device_state(&dev->persistent);
if (SCOPE_AUTOCONF(config))
reset_device_state(&dev->autoconf);
dev->processed = 0;
}
@@ -516,6 +554,9 @@ exit_code_t device_write_active_settings(struct device *dev)
s = p->ptr;
if (!s->modified || s->removed)
continue;
if ((s->attrib && s->attrib->internal) ||
internal_by_name(s->name))
continue;
path = subtype_get_active_attrib_path(st, dev, s->name);
if (!path) {
@@ -567,6 +608,44 @@ exit_code_t device_check_settings(struct device *dev, config_t config,
err))
return EXIT_INVALID_CONFIG;
}
if (SCOPE_AUTOCONF(config)) {
if (!setting_list_check_conflict(dev->autoconf.settings,
config_autoconf,
err))
return EXIT_INVALID_CONFIG;
}
return EXIT_OK;
}
struct setting_list *device_get_setting_list(struct device *dev,
config_t config)
{
struct setting_list *settings = NULL;
if (config == config_active)
settings = dev->active.settings;
else if (config == config_persistent)
settings = dev->persistent.settings;
else if (config == config_autoconf)
settings = dev->autoconf.settings;
return settings;
}
/* Return configuration set in which device exists. */
config_t device_get_config(struct device *dev)
{
config_t config = 0;
if (dev->active.exists || dev->active.definable)
config |= config_active;
if (dev->persistent.exists)
config |= config_persistent;
if (dev->autoconf.exists)
config |= config_autoconf;
return config;
}

View File

@@ -83,7 +83,7 @@ static bool is_exportable(struct setting *s, config_t config)
return true;
}
}
if (SCOPE_PERSISTENT(config)) {
if (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) {
if (setting_is_set(s))
return true;
}
@@ -148,10 +148,9 @@ static int count_exportable(struct device *dev, config_t config)
struct setting *s;
int count;
if (config == config_active)
list = dev->active.settings;
else
list = dev->persistent.settings;
list = device_get_setting_list(dev, config);
if (!list)
return 0;
count = 0;
util_list_iterate(&list->list, s) {
@@ -169,12 +168,26 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config,
exit_code_t rc;
struct setting_list *settings;
if (config == config_all) {
rc = export_write_device(fd, dev, config_active, first_ptr);
if (rc)
return rc;
return export_write_device(fd, dev, config_persistent,
first_ptr);
if (!SCOPE_SINGLE(config)) {
if (SCOPE_ACTIVE(config)) {
rc = export_write_device(fd, dev, config_active,
first_ptr);
if (rc)
return rc;
}
if (SCOPE_PERSISTENT(config)) {
rc = export_write_device(fd, dev, config_persistent,
first_ptr);
if (rc)
return rc;
}
if (SCOPE_AUTOCONF(config)) {
rc = export_write_device(fd, dev, config_autoconf,
first_ptr);
if (rc)
return rc;
}
return EXIT_OK;
}
if (config == config_active) {
@@ -185,10 +198,14 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config,
!dev->subtype->support_definable)
return EXIT_OK;
settings = dev->active.settings;
} else {
} else if (config == config_persistent) {
if (!dev->persistent.exists)
return EXIT_OK;
settings = dev->persistent.settings;
} else {
if (!dev->autoconf.exists)
return EXIT_OK;
settings = dev->autoconf.settings;
}
write_header(fd, config, dev->subtype->name, dev->id, first_ptr);
@@ -204,12 +221,21 @@ exit_code_t export_write_devtype(FILE *fd, struct devtype *dt, config_t config,
exit_code_t rc;
struct setting_list *settings;
if (config == config_all) {
rc = export_write_devtype(fd, dt, config_active, first_ptr);
if (rc)
return rc;
return export_write_devtype(fd, dt, config_persistent,
first_ptr);
if (!SCOPE_SINGLE(config)) {
if (SCOPE_ACTIVE(config)) {
rc = export_write_devtype(fd, dt, config_active,
first_ptr);
if (rc)
return rc;
}
if (SCOPE_PERSISTENT(config)) {
rc = export_write_devtype(fd, dt, config_persistent,
first_ptr);
if (rc)
return rc;
}
/* Scope autoconf not supported for devtype */
return EXIT_OK;
}
if (config == config_active)
@@ -282,19 +308,6 @@ static bool parse_setting(const char *line, char **key_ptr, char **val_ptr)
return true;
}
static struct setting_list *dev_get_setting_list(struct device *dev,
config_t config)
{
struct setting_list *settings = NULL;
if (config == config_active)
settings = dev->active.settings;
else
settings = dev->persistent.settings;
return settings;
}
static struct setting_list *dt_get_setting_list(struct devtype *dt,
config_t config)
{
@@ -392,6 +405,10 @@ static exit_code_t handle_header(const char *filename, int lineno,
setting_list_clear(dev->persistent.settings);
dev->persistent.exists = 1;
}
if (SCOPE_AUTOCONF(hdr->config)) {
setting_list_clear(dev->autoconf.settings);
dev->autoconf.exists = 1;
}
}
out:
@@ -410,13 +427,26 @@ static exit_code_t handle_setting(const char *filename, int lineno,
struct attrib **attribs, *a;
struct setting_list *list;
if (config == config_all) {
rc = handle_setting(filename, lineno, key, value, dt, dev,
config_active);
if (rc)
return rc;
return handle_setting(filename, lineno, key, value, dt, dev,
config_persistent);
if (!SCOPE_SINGLE(config)) {
if (SCOPE_ACTIVE(config)) {
rc = handle_setting(filename, lineno, key, value, dt,
dev, config_active);
if (rc)
return rc;
}
if (SCOPE_PERSISTENT(config)) {
rc = handle_setting(filename, lineno, key, value, dt,
dev, config_persistent);
if (rc)
return rc;
}
if (SCOPE_AUTOCONF(config)) {
rc = handle_setting(filename, lineno, key, value, dt,
dev, config_autoconf);
if (rc)
return rc;
}
return EXIT_OK;
}
if (dt) {
@@ -426,7 +456,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
} else if (dev) {
/* We're inside a device section. */
attribs = dev->subtype->dev_attribs;
list = dev_get_setting_list(dev, config);
list = device_get_setting_list(dev, config);
} else
return EXIT_OK;
@@ -444,7 +474,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
return EXIT_OK;
}
static struct export_object *object_new(export_t type, void *ptr)
struct export_object *object_new(export_t type, void *ptr)
{
struct export_object *obj;
@@ -465,7 +495,8 @@ static bool empty_device(struct device *dev)
if (dev->subtype->support_definable)
return false;
if (util_list_is_empty(&dev->active.settings->list) &&
util_list_is_empty(&dev->persistent.settings->list))
util_list_is_empty(&dev->persistent.settings->list) &&
util_list_is_empty(&dev->autoconf.settings->list))
return true;
return false;
}

682
zdev/src/firmware.c Normal file
View File

@@ -0,0 +1,682 @@
/*
* zdev - Modify and display the persistent configuration of devices
*
* Copyright IBM Corp. 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <err.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "attrib.h"
#include "ccw.h"
#include "ccwgroup.h"
#include "dasd.h"
#include "device.h"
#include "export.h"
#include "firmware.h"
#include "misc.h"
#include "qeth.h"
#include "subtype.h"
#include "zfcp_host.h"
#include "zfcp_lun.h"
/* In-memory firmware file representation. */
struct fw_file {
const char *name;
char *buffer;
size_t size;
char *last_access;
size_t last_size;
};
/* Record access to fields of the buffered file for use in warning messages. */
#define fwacc(f, x) ((f)->last_access = (char *) &(x), \
(f)->last_size = sizeof(x), x)
/*
* Firmware file format definitions.
*/
/* Firmware file header. */
struct fw_filehdr {
uint32_t magic;
uint16_t ver;
uint16_t hdr_len;
uint32_t file_len;
uint32_t seq;
uint32_t zeroes;
uint16_t de_count;
char unused[10];
} __packed;
#define FW_HDR_MAGIC 0x7a646576 /* ASCII "zdev" */
#define FW_HDR_VER_Z14 0x0000
/* I/O device ID. */
struct fw_iodevid {
uint8_t cssid;
uint8_t ssid;
uint16_t devno;
} __packed;
#define FW_IODEVID_FLAG_MCSS 0x01
/* Device setting. */
struct fw_setting {
uint16_t len;
uint8_t key_type;
uint8_t key_len;
uint8_t val_type;
uint8_t val_len;
char data[];
} __packed;
#define FW_SETTING_KEYTYPE_ASCII 0x00
#define FW_SETTING_VALTYPE_ASCII 0x00
#define FW_SETTING_VALTYPE_UINT 0x01
/* Device settings list. */
struct fw_setlist {
uint16_t len;
char data[];
} __packed;
/* Device entry header. */
struct fw_dehdr {
uint16_t type;
uint16_t len;
uint32_t seq;
} __packed;
#define FW_DE_HDR_TYPE_DASD 0x0001
#define FW_DE_HDR_TYPE_ZFCP_HOST 0x0002
#define FW_DE_HDR_TYPE_ZFCP_LUN 0x0003
#define FW_DE_HDR_TYPE_QETH 0x0004
/* DASD device entry. */
struct fw_dasd {
struct fw_dehdr hdr;
uint8_t id_flags;
struct fw_iodevid id;
char settings[];
} __packed;
/* zFCP host device entry. */
struct fw_zfcp_host {
struct fw_dehdr hdr;
uint8_t id_flags;
struct fw_iodevid id;
char settings[];
} __packed;
/* zFCP LUN device entry. */
struct fw_zfcp_lun {
struct fw_dehdr hdr;
uint8_t id_flags;
struct fw_iodevid id;
uint64_t wwpn;
uint64_t fcp_lun;
char settings[];
} __packed;
/* QETH device entry. */
struct fw_qeth {
struct fw_dehdr hdr;
uint8_t id_flags;
struct fw_iodevid read_id;
struct fw_iodevid write_id;
struct fw_iodevid data_id;
char settings[];
} __packed;
/* Emit a warning that refers to a position in a firmware file. */
static void fwwarn(struct fw_file *f, const char *fmt, ...)
{
va_list args;
off_t start = (off_t) (f->last_access - f->buffer),
end = start + f->last_size - 1;
fprintf(stderr, "%s: ", f->name);
if (start == end)
fprintf(stderr, "Byte 0x%zx: ", start);
else
fprintf(stderr, "Bytes 0x%zx-0x%zx: ", start, end);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
}
/* Basic file format header sanity check. */
static bool check_header(struct fw_file *f, struct fw_filehdr *hdr)
{
if (fwacc(f, hdr->magic) != FW_HDR_MAGIC)
fwwarn(f, "Invalid file magic (0x%08x)", hdr->magic);
else if (fwacc(f, hdr->ver) != FW_HDR_VER_Z14)
fwwarn(f, "Unsupported file version (0x%04x)", hdr->ver);
else
return true;
return false;
}
#define READ_RETRY 3
/* Read a firmware configuration file. */
static exit_code_t read_fw(struct fw_file *file, FILE *fd, const char *filename)
{
struct fw_file f = { NULL };
struct fw_filehdr *hdr;
char *buffer, *buffer2;
size_t size, size2;
int retry;
exit_code_t rc = EXIT_OK;
for (retry = 0; retry < READ_RETRY; retry++) {
/* Read complete file once */
rc = misc_read_fd(fd, (void **) &buffer, &size);
if (rc) {
warn("%s: Could not read file", filename);
return rc;
}
if (!buffer) {
/* Empty file - skip silently as this is the default
* on machines without firmware support. */
return rc;
}
/* Re-read complete file to detect in-flight modifications. */
if (fseek(fd, 0, SEEK_SET) == -1) {
/* Could be a pipe, socket, or FIFO - accept v1. */
break;
}
rc = misc_read_fd(fd, (void **) &buffer2, &size2);
if (rc || !buffer2) {
/* Could not get second version - accept v1. */
break;
}
if (size == size2 && memcmp(buffer, buffer2, size) == 0) {
/* No change */
free(buffer2);
break;
}
free(buffer);
free(buffer2);
}
if (retry >= READ_RETRY) {
warnx("%s: File changed %d times while reading - aborting",
filename, retry);
return EXIT_RUNTIME_ERROR;
}
/* Perform basic checks */
f.name = filename;
f.buffer = buffer;
f.size = size;
hdr = (void *) buffer;
if (!check_header(&f, hdr)) {
free(buffer);
return EXIT_FORMAT_ERROR;
}
if (fwacc(&f, hdr->file_len) > size) {
fwwarn(&f, "File length mismatch (expect %zu) - adjusting",
size);
hdr->file_len = size;
}
*file = f;
return EXIT_OK;
}
/* Return textual representation of a device entry type. */
static const char *type_to_str(uint16_t type)
{
switch (type) {
case FW_DE_HDR_TYPE_DASD:
return "dasd";
case FW_DE_HDR_TYPE_ZFCP_HOST:
return "zfcp-host";
case FW_DE_HDR_TYPE_ZFCP_LUN:
return "zfcp-lun";
case FW_DE_HDR_TYPE_QETH:
return "qeth";
default:
return "<unknown>";
}
}
/* Convert a binary format device setting of the specified length to integer. */
static unsigned long parse_value(char *data, uint8_t len)
{
switch (len) {
case 1:
return (unsigned long) *((uint8_t *) data);
case 2:
return (unsigned long) *((uint16_t *) data);
case 4:
return (unsigned long) *((uint32_t *) data);
case 8:
return (unsigned long) *((uint64_t *) data);
default:
return 0;
}
}
/* Perform sanity checks on device setting. */
static bool check_setting(struct fw_file *f, struct fw_setting *set)
{
/* Key sanity checks */
if (fwacc(f, set->key_type) != FW_SETTING_KEYTYPE_ASCII) {
fwwarn(f, "Unsupported key type: %d", set->key_type);
return false;
}
if (fwacc(f, set->key_len) < 1) {
fwwarn(f, "Unsupported key length: %d", set->key_len);
return false;
}
if (sizeof(struct fw_setting) + fwacc(f, set->key_len) > set->len) {
fwwarn(f, "Key length exceeds setting");
return false;
}
if (fwacc(f, set->data[set->key_len - 1])) {
fwwarn(f, "Key not null-terminated");
return false;
}
/* Value sanity checks */
if (fwacc(f, set->val_type) != FW_SETTING_VALTYPE_UINT &&
fwacc(f, set->val_type) != FW_SETTING_VALTYPE_ASCII) {
fwwarn(f, "Unsupported value type: %d", set->val_type);
return false;
}
if (fwacc(f, set->val_len) < 1) {
fwwarn(f, "Unsupported value length: %d", set->val_len);
return false;
}
if (sizeof(struct fw_setting) + set->key_len +
fwacc(f, set->val_len) > set->len) {
fwwarn(f, "Value length exceeds setting");
return false;
}
if ((set->val_type == FW_SETTING_VALTYPE_ASCII) &&
fwacc(f, set->data[set->key_len + set->val_len - 1])) {
fwwarn(f, "Value not null-terminated");
return false;
}
if (set->val_type == FW_SETTING_VALTYPE_UINT) {
switch (fwacc(f, set->val_len)) {
case 1:
case 2:
case 4:
case 8:
break;
default:
fwwarn(f, "Unsupported integer value length: %d",
set->val_len);
return false;
}
}
return true;
}
/* Add a setting to the device. Emit a warning if the setting is not known. */
static void _add_setting(const char *filename, struct device *dev,
config_t config, const char *key, const char *value)
{
struct attrib *a;
struct setting_list *list;
list = device_get_setting_list(dev, config);
a = attrib_find(dev->subtype->dev_attribs, key);
if (!a) {
warnx("%s: Applying unknown device setting %s=%s", filename,
key, value);
}
setting_list_apply(list, a, key, value);
}
static void add_setting(const char *filename, struct device *dev,
config_t config, const char *key, const char *value)
{
if (SCOPE_ACTIVE(config))
_add_setting(filename, dev, config_active, key, value);
if (SCOPE_PERSISTENT(config))
_add_setting(filename, dev, config_persistent, key, value);
if (SCOPE_AUTOCONF(config))
_add_setting(filename, dev, config_autoconf, key, value);
}
/* Parse a single device setting in firmware format and apply it to the
* specified device. */
static void parse_setting(struct fw_file *f, struct fw_setting *set,
struct device *dev, config_t config)
{
char *ascii_key, *ascii_val;
unsigned long ulong_val;
if (!check_setting(f, set))
return;
ascii_key = &set->data[0];
if (set->val_type == FW_SETTING_VALTYPE_UINT) {
ulong_val = parse_value(&set->data[set->key_len], set->val_len);
ascii_val = misc_asprintf("%lu", ulong_val);
add_setting(f->name, dev, config, ascii_key, ascii_val);
free(ascii_val);
} else {
ascii_val = &set->data[set->key_len];
add_setting(f->name, dev, config, ascii_key, ascii_val);
}
}
/* Parse a device settings list in firmware format and apply the resulting
* settings to the specified device. */
static void parse_settings(struct fw_file *f, char *data, struct device *dev,
config_t config)
{
struct fw_setlist *list = (struct fw_setlist *) data;
struct fw_setting *set;
uint16_t off;
for (off = sizeof(struct fw_setlist); off < list->len;
off += set->len) {
set = (struct fw_setting *) &data[off];
if (fwacc(f, set->len) < sizeof(struct fw_setting)) {
fwwarn(f, "Setting too short");
break;
}
if (off + fwacc(f, set->len) > list->len) {
fwwarn(f, "Setting too long");
break;
}
parse_setting(f, set, dev, config);
}
}
/* Perform sanity checks on an I/O device ID. */
static bool check_iodevid(struct fw_file *f, uint8_t *flags,
struct fw_iodevid *id)
{
if (fwacc(f, *flags) & FW_IODEVID_FLAG_MCSS) {
fwwarn(f, "Unsupported entry in non-default CSS");
return false;
}
if (fwacc(f, id->cssid) != 0) {
fwwarn(f, "Non-zero CSS-ID");
return false;
}
return true;
}
/* Perform sanity checks on a device entry. */
static bool check_de_size(struct fw_file *f, struct fw_dehdr *de, size_t size)
{
if (fwacc(f, de->len) < size) {
fwwarn(f, "Device entry too short (expect %zu)", size);
return false;
}
return true;
}
/* Convert an I/O device ID to CCW device ID format. */
static void io_to_ccw(struct ccw_devid *c, struct fw_iodevid *i)
{
c->cssid = i->cssid;
c->ssid = i->ssid;
c->devno = i->devno;
}
/* Register a new device configuration. */
static struct device *add_device(struct fw_file *f, struct subtype *st,
const char *id, config_t config,
struct util_list *objects)
{
struct device *dev;
if (!st->devices)
st->devices = device_list_new(st);
dev = device_list_find(st->devices, id, NULL);
if (!dev) {
dev = device_new(st, id);
if (!dev) {
warnx("%s: Skipping invalid %s device ID %s", f->name,
st->name, id);
return NULL;
}
device_list_add(st->devices, dev);
}
ptrlist_add(objects, object_new(export_device, dev));
/* Prepare device for new settings. */
if (SCOPE_ACTIVE(config)) {
setting_list_clear(dev->active.settings);
if (dev->subtype->support_definable)
dev->active.definable = 1;
else
dev->active.exists = 1;
}
if (SCOPE_PERSISTENT(config)) {
setting_list_clear(dev->persistent.settings);
dev->persistent.exists = 1;
}
if (SCOPE_AUTOCONF(config)) {
setting_list_clear(dev->autoconf.settings);
dev->autoconf.exists = 1;
}
return dev;
}
/* Parse a DASD device entry. */
static void parse_dasd(struct fw_file *f, struct fw_dehdr *de, config_t config,
struct util_list *objects)
{
struct fw_dasd *dasd = (struct fw_dasd *) de;
struct ccw_devid devid;
struct device *dev_eckd, *dev_fba;
char *id;
if (!check_de_size(f, de, sizeof(struct fw_dasd)))
return;
if (!check_iodevid(f, &dasd->id_flags, &dasd->id))
return;
/* Could be either dasd_eckd or dasd_fba - add both entries */
io_to_ccw(&devid, &dasd->id);
id = ccw_devid_to_str(&devid);
dev_eckd = add_device(f, &dasd_subtype_eckd, id, config, objects);
dev_fba = add_device(f, &dasd_subtype_fba, id, config, objects);
free(id);
if (dasd->hdr.len > sizeof(struct fw_dasd)) {
if (dev_eckd)
parse_settings(f, dasd->settings, dev_eckd, config);
if (dev_fba)
parse_settings(f, dasd->settings, dev_fba, config);
}
}
/* Parse a zFCP host device entry. */
static void parse_zfcp_host(struct fw_file *f, struct fw_dehdr *de,
config_t config, struct util_list *objects)
{
struct fw_zfcp_host *zfcp_host = (struct fw_zfcp_host *) de;
struct ccw_devid devid;
struct device *dev;
char *id;
if (!check_de_size(f, de, sizeof(struct fw_zfcp_host)))
return;
if (!check_iodevid(f, &zfcp_host->id_flags, &zfcp_host->id))
return;
/* Add zfcp_host entry */
io_to_ccw(&devid, &zfcp_host->id);
id = ccw_devid_to_str(&devid);
dev = add_device(f, &zfcp_host_subtype, id, config, objects);
free(id);
if (dev && zfcp_host->hdr.len > sizeof(struct fw_zfcp_host))
parse_settings(f, zfcp_host->settings, dev, config);
}
/* Parse a zFCP LUN device entry. */
static void parse_zfcp_lun(struct fw_file *f, struct fw_dehdr *de,
config_t config, struct util_list *objects)
{
struct fw_zfcp_lun *zfcp_lun = (struct fw_zfcp_lun *) de;
struct zfcp_lun_devid devid;
struct device *dev;
char *id;
if (!check_de_size(f, de, sizeof(struct fw_zfcp_lun)))
return;
if (!check_iodevid(f, &zfcp_lun->id_flags, &zfcp_lun->id))
return;
/* Add zfcp_lun entry */
io_to_ccw(&devid.fcp_dev, &zfcp_lun->id);
devid.wwpn = zfcp_lun->wwpn;
devid.lun = zfcp_lun->fcp_lun;
id = zfcp_lun_devid_to_str(&devid);
dev = add_device(f, &zfcp_lun_subtype, id, config, objects);
free(id);
if (dev && zfcp_lun->hdr.len > sizeof(struct fw_zfcp_lun))
parse_settings(f, zfcp_lun->settings, dev, config);
}
/* Parse a QETH device entry. */
static void parse_qeth(struct fw_file *f, struct fw_dehdr *de, config_t config,
struct util_list *objects)
{
struct fw_qeth *qeth = (struct fw_qeth *) de;
struct ccwgroup_devid devid;
struct device *dev;
char *id;
if (!check_de_size(f, de, sizeof(struct fw_qeth)))
return;
if (!check_iodevid(f, &qeth->id_flags, &qeth->read_id) ||
!check_iodevid(f, &qeth->id_flags, &qeth->write_id) ||
!check_iodevid(f, &qeth->id_flags, &qeth->data_id))
return;
/* Add qeth entry */
devid.num = 3;
io_to_ccw(&devid.devid[0], &qeth->read_id);
io_to_ccw(&devid.devid[1], &qeth->write_id);
io_to_ccw(&devid.devid[2], &qeth->data_id);
id = ccwgroup_devid_to_str(&devid);
dev = add_device(f, &qeth_subtype_qeth, id, config, objects);
free(id);
if (dev && qeth->hdr.len > sizeof(struct fw_qeth))
parse_settings(f, qeth->settings, dev, config);
}
/* Parse a firmware file. */
static void parse_fw(struct fw_file *f, long skip, config_t config,
struct util_list *objects)
{
char *data = f->buffer;
struct fw_filehdr *hdr = (struct fw_filehdr *) data;
struct fw_dehdr *de;
uint16_t count = 0;
uint32_t off;
for (off = hdr->hdr_len; off < hdr->file_len; off += de->len) {
count++;
de = (struct fw_dehdr *) &data[off];
if (fwacc(f, de->len) == 0) {
fwwarn(f, "Empty device entry");
break;
}
if (off + fwacc(f, de->len) > hdr->file_len) {
fwwarn(f, "Device entry too long");
break;
}
if (skip >= 0 && de->seq <= skip) {
debug("Skipping %s entry due to sequence (%08x)\n",
type_to_str(de->type), de->seq);
continue;
}
switch (fwacc(f, de->type)) {
case FW_DE_HDR_TYPE_DASD:
parse_dasd(f, de, config, objects);
break;
case FW_DE_HDR_TYPE_ZFCP_HOST:
parse_zfcp_host(f, de, config, objects);
break;
case FW_DE_HDR_TYPE_ZFCP_LUN:
parse_zfcp_lun(f, de, config, objects);
break;
case FW_DE_HDR_TYPE_QETH:
parse_qeth(f, de, config, objects);
break;
default:
fwwarn(f, "Unknown entry (type=%04x)", de->type);
break;
}
}
if (count != fwacc(f, hdr->de_count))
fwwarn(f, "Device entry count mismatch");
}
/* Read configuration objects from @fd in firmware file format. Add pointers to
* newly allocated struct export_objects to ptrlist @objects. If @skip is a
* positive number, skip over entries with a sequence number equal to or
* greater than @skip. */
exit_code_t firmware_read(FILE *fd, const char *filename, long skip,
config_t config, struct util_list *objects)
{
struct fw_file file;
exit_code_t rc;
rc = read_fw(&file, fd, filename);
if (rc)
return rc;
parse_fw(&file, skip, config, objects);
free(file.buffer);
return rc;
}
/* Check if @fd refers to a file in binary firmware format. */
bool firmware_detect(FILE *fd)
{
int c;
c = fgetc(fd);
ungetc(c, fd);
/* Note: A full check would require looking at least at the first 4
* bytes, but fd might be non-seekable (e.g. pipe). Since there is no
* way that a textual import file can start with a 'z', looking at
* the first char should be enough. */
return c == 'z';
}

View File

@@ -17,6 +17,7 @@
#include "devnode.h"
#include "devtype.h"
#include "generic_ccw.h"
#include "internal.h"
#include "namespace.h"
#include "path.h"
#include "subtype.h"
@@ -28,6 +29,7 @@
static struct ccw_subtype_data generic_ccw_data = {
.ccwdrv = NULL,
.mod = NULL,
.any_driver = true,
};
/* Check if there is a non-generic subtype in the CCW namespace that uses the
@@ -182,6 +184,7 @@ static struct subtype generic_ccw_subtype = {
.dev_attribs = ATTRIB_ARRAY(
&ccw_attr_online,
&ccw_attr_cmb_enable,
&internal_attr_early,
),
.unknown_dev_attribs = 1,
.generic = 1,

38
zdev/src/internal.c Normal file
View File

@@ -0,0 +1,38 @@
/*
* zdev - Modify and display the persistent configuration of devices
*
* Copyright IBM Corp. 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdbool.h>
#include "attrib.h"
#include "internal.h"
#include "misc.h"
struct attrib internal_attr_early = {
.name = INTERNAL_ATTR_EARLY,
.title = "Activate device early during boot",
.desc = "Control the time of activation of a device:\n"
" 0: Device is activated normally during boot\n"
" 1: Device is activated early in the boot process, by the\n"
" initial RAM-disk\n",
.defval = "0",
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
.internal = 1,
};
/* Return identifier of internal attribute with specified @name. */
const char *internal_get_name(const char *name)
{
return name + sizeof(INTERNAL_ATTR_PREFIX) - 1;
}
/* Check if attribute is internal by name. */
bool internal_by_name(const char *name)
{
return starts_with(name, INTERNAL_ATTR_PREFIX);
}

View File

@@ -15,6 +15,7 @@
#include "ccwgroup.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "lcs.h"
#include "lcs_auto.h"
#include "misc.h"
@@ -362,6 +363,7 @@ static struct subtype lcs_subtype = {
&ccw_attr_online,
&lcs_attr_lancmd_timeout,
&lcs_attr_recover,
&internal_attr_early,
),
.unknown_dev_attribs = 1,
.support_definable = 1,

View File

@@ -59,6 +59,7 @@ struct options {
config_t config;
unsigned int active:1;
unsigned int persistent:1;
unsigned int auto_conf:1;
struct util_list *columns; /* List of struct strlist_node */
unsigned int no_headings:1;
struct util_list *base; /* List of struct strlist_node */
@@ -98,6 +99,7 @@ enum {
OPT_VERBOSE = 'V',
OPT_QUIET = 'q',
OPT_PAIRS = 'P',
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
};
static struct opts_conflict conflict_list[] = {
@@ -150,6 +152,7 @@ static const struct option opt_list[] = {
/* Options. */
{ "active", no_argument, NULL, OPT_ACTIVE },
{ "persistent", no_argument, NULL, OPT_PERSISTENT },
{ "auto-conf", no_argument, NULL, OPT_AUTO_CONF },
{ "columns", required_argument, NULL, OPT_COLUMNS },
{ "no-headings", no_argument, NULL, OPT_NO_HEADINGS },
{ "base", required_argument, NULL, OPT_BASE },
@@ -623,6 +626,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
opts->persistent = 1;
break;
case OPT_AUTO_CONF:
/* --auto-conf */
opts->auto_conf = 1;
break;
case OPT_COLUMNS:
/* --columns COLUMN */
strlist_add_multi(opts->columns, optarg, ",", 0);
@@ -685,7 +693,15 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
goto out;
/* Determine configuration set. */
opts->config = get_config(opts->active, opts->persistent);
if (!opts->active && !opts->persistent && !opts->auto_conf) {
/* Default display targets are active + persistent - note that
* autoconf data is still shown when available to make users
* aware of this type of data. */
opts->config = config_active | config_persistent;
} else {
opts->config = get_config(opts->active, opts->persistent,
opts->auto_conf);
}
/* Handle positional parameters. */
rc = parse_positional(opts, argc, argv, optind);
@@ -725,6 +741,7 @@ enum dev_table_id {
dev_netdevs,
dev_exists,
dev_pers,
dev_auto,
dev_online,
dev_failed,
dev_modules,
@@ -744,6 +761,8 @@ static struct column *dev_table = COLUMN_ARRAY(
"Device exists in the active configuration"),
COLUMN("PERS", align_left, dev_pers, 1,
"Device is configured persistently"),
COLUMN("AUTO", align_left, dev_auto, 0,
"Auto-configuration exists for device"),
COLUMN("FAILED", align_left, dev_failed, 0,
"Device is in error"),
COLUMN("NAMES", align_left, dev_names, 1,
@@ -762,21 +781,34 @@ static struct column *dev_table = COLUMN_ARRAY(
"Path to specific attribute in active configuration")
);
static char *merge_str(const char *act, const char *pers)
static char *merge_str(const char *act, const char *pers, const char *ac,
config_t config)
{
char *str;
size_t len;
if (act && pers) {
if (strcmp(act, pers) == 0)
str = misc_strdup(act);
else
str = misc_asprintf("%s/%s", act, pers);
} else if (act)
str = misc_strdup(act);
else if (pers)
str = misc_strdup(pers);
else
str = misc_strdup("-");
act = act ? act : "-";
pers = pers ? pers : "-";
ac = ac ? ac : "-";
if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0)
return misc_strdup(act);
len = strlen(act) + strlen(pers) + strlen(ac) + /* 3 * / + NUL */ 4;
str = misc_malloc(len);
if (SCOPE_ACTIVE(config))
strcat(str, act);
if (SCOPE_PERSISTENT(config)) {
if (*str)
strcat(str, "/");
strcat(str, pers);
}
if (SCOPE_AUTOCONF(config)) {
if (*str)
strcat(str, "/");
strcat(str, ac);
}
return str;
}
@@ -821,10 +853,9 @@ static char *get_attr(struct device *dev, const char *name, config_t config)
struct setting_list *list;
struct setting *s;
if (config == config_active)
list = dev->active.settings;
else
list = dev->persistent.settings;
list = device_get_setting_list(dev, config);
if (!list)
return NULL;
s = setting_list_find(list, name);
if (!s) {
if (config == config_active) {
@@ -841,7 +872,7 @@ static char *get_attr(struct device *dev, const char *name, config_t config)
static char *dev_table_get_attr(struct device *dev, const char *attr,
config_t config)
{
char *act = NULL, *pers = NULL, *str;
char *act = NULL, *pers = NULL, *ac = NULL, *str;
const char *name;
name = strchr(attr, ':');
@@ -853,10 +884,13 @@ static char *dev_table_get_attr(struct device *dev, const char *attr,
act = get_attr(dev, name, config_active);
if (SCOPE_PERSISTENT(config))
pers = get_attr(dev, name, config_persistent);
if (SCOPE_AUTOCONF(config))
ac = get_attr(dev, name, config_autoconf);
str = merge_str(act, pers);
str = merge_str(act, pers, ac, config);
free(act);
free(pers);
free(ac);
return str;
}
@@ -904,7 +938,11 @@ static char *dev_table_get_value(void *item, int id, const char *heading,
return misc_strdup(YESNO(dev->active.exists ||
dev->active.definable));
case dev_pers:
if (!dev->persistent.exists && dev->autoconf.exists)
return misc_strdup("auto");
return misc_strdup(YESNO(dev->persistent.exists));
case dev_auto:
return misc_strdup(YESNO(dev->autoconf.exists));
case dev_online:
return dev_table_get_online(dev, config_active);
case dev_failed:
@@ -942,6 +980,7 @@ static read_scope_t get_scope(struct options *opts)
case dev_netdevs:
case dev_exists:
case dev_pers:
case dev_auto:
case dev_online:
case dev_modules:
continue;
@@ -960,14 +999,21 @@ static struct util_list *dev_table_build(struct options *opts,
struct util_list *selected, *devices = NULL;
struct selected_dev_node *sel;
struct device *dev;
int active, persistent;
int active, persistent, autoconf;
read_scope_t scope;
exit_code_t rc;
config_t config = opts->config;
scope = get_scope(opts);
selected = selected_dev_list_new();
/* Read auto-config data when no configuration set was specified to
* make user aware of auto-config data. */
if (!opts->active && !opts->persistent && !opts->auto_conf)
config |= config_autoconf;
rc = select_devices(opts->select, selected, 1, 0, opts->pairs,
opts->config, scope, err_print);
config, scope, err_print);
if (rc)
goto out;
devices = ptrlist_new();
@@ -987,7 +1033,8 @@ static struct util_list *dev_table_build(struct options *opts,
/* Only process existing devices. */
active = dev->active.exists || dev->active.definable;
persistent = dev->persistent.exists;
if (!active && !persistent)
autoconf = dev->autoconf.exists;
if (!active && !persistent && !autoconf)
continue;
ptrlist_add(devices, dev);
@@ -1025,9 +1072,11 @@ static exit_code_t do_list_devices(struct options *opts)
if (!items)
return EXIT_EMPTY_SELECTION;
/* Adjust columns visible depending on --active and --persistent. */
/* Adjust columns visible depending on selected config set. */
table_set_default(dev_table, dev_online, SCOPE_ACTIVE(opts->config));
table_set_default(dev_table, dev_pers, SCOPE_PERSISTENT(opts->config));
table_set_default(dev_table, dev_auto, SCOPE_AUTOCONF(opts->config) &&
!SCOPE_PERSISTENT(opts->config));
table_set_default(dev_table, dev_names, SCOPE_ACTIVE(opts->config));
/* Display table. */
@@ -1057,17 +1106,20 @@ enum settings_table_id {
settings_readonly,
settings_active,
settings_persistent,
settings_autoconf,
};
static struct column *settings_table = COLUMN_ARRAY(
COLUMN("ATTRIBUTE", align_left, settings_attribute, 1, ""),
COLUMN("READONLY", align_left, settings_readonly, 1, ""),
COLUMN("ACTIVE", align_left, settings_active, 1, ""),
COLUMN("PERSISTENT", align_left, settings_persistent, 1, "")
COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""),
COLUMN("AUTOCONF", align_left, settings_autoconf, 0, "")
);
static struct util_list *settings_table_build(struct setting_list *active,
struct setting_list *persistent,
struct setting_list *autoconf,
bool readonly)
{
struct util_list *names, *items;
@@ -1088,6 +1140,10 @@ static struct util_list *settings_table_build(struct setting_list *active,
util_list_iterate(&persistent->list, s)
strlist_add(names, s->name);
}
if (autoconf && !readonly) {
util_list_iterate(&autoconf->list, s)
strlist_add(names, s->name);
}
strlist_sort_unique(names, str_cmp);
/* Convert strlist to ptrlist. */
@@ -1102,6 +1158,7 @@ static struct util_list *settings_table_build(struct setting_list *active,
struct settings_table_data {
struct setting_list *active;
struct setting_list *persistent;
struct setting_list *autoconf;
int pairs;
bool readonly;
};
@@ -1124,12 +1181,17 @@ static char *settings_table_get_value(void *item, int id, const char *heading,
case settings_persistent:
list = stdata->persistent;
break;
case settings_autoconf:
list = stdata->autoconf;
break;
default:
break;
}
if (list) {
s = setting_list_find(list, name);
if (s && !(id == settings_persistent && s->derived)) {
if (s &&
!((id == settings_persistent || id == settings_autoconf) &&
s->derived)) {
if (stdata->pairs)
return misc_strdup(s->value);
else
@@ -1145,6 +1207,7 @@ static char *settings_table_get_value(void *item, int id, const char *heading,
static void settings_table_print(struct setting_list *active,
struct setting_list *persistent,
struct setting_list *autoconf,
struct options *opts, int ind, bool readonly,
bool neednl)
{
@@ -1154,7 +1217,7 @@ static void settings_table_print(struct setting_list *active,
items = settings_table_build(
SCOPE_ACTIVE(opts->config) ? active : NULL,
SCOPE_PERSISTENT(opts->config) ? persistent : NULL,
readonly);
autoconf, readonly);
if (util_list_is_empty(items)) {
if (!opts->pairs && !readonly)
indent(ind, "%sNo settings found\n",
@@ -1170,8 +1233,12 @@ static void settings_table_print(struct setting_list *active,
SCOPE_ACTIVE(opts->config));
table_set_default(settings_table, settings_persistent,
SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0);
table_set_default(settings_table, settings_autoconf,
(SCOPE_AUTOCONF(opts->config) || autoconf) &&
!readonly ? 1 : 0);
data.active = active;
data.persistent = persistent;
data.autoconf = autoconf;
data.pairs = opts->pairs;
table_print(settings_table, settings_table_get_value, &data, items,
NULL, 1, opts->pairs, ind, 0);
@@ -1253,7 +1320,7 @@ static exit_code_t do_info_type(struct options *opts)
}
} else {
settings_table_print(dt->active_settings,
dt->persistent_settings, opts,
dt->persistent_settings, NULL, opts,
INFO_INDENT, false, false);
}
@@ -1280,7 +1347,7 @@ static void do_info_one_device(struct device *dev, struct options *opts)
{
struct subtype *st = dev->subtype;
char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key;
const char *id, *type, *exists, *persist, *prefix;
const char *id, *type, *exists, *persist, *ac, *prefix;
struct util_list *resources, *errors;
struct strlist_node *s;
bool first;
@@ -1299,6 +1366,7 @@ static void do_info_one_device(struct device *dev, struct options *opts)
errors = subtype_get_errors(dev->subtype, dev->id);
exists = YESNO(dev->active.exists || dev->active.definable);
persist = YESNO(dev->persistent.exists);
ac = YESNO(dev->autoconf.exists);
/* Print information. */
if (opts->pairs) {
@@ -1316,6 +1384,8 @@ static void do_info_one_device(struct device *dev, struct options *opts)
print_pair("ONLINE", online);
print_pair("EXISTS", exists);
print_pair("PERSISTENT", persist);
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
print_pair("AUTOCONF", ac);
if (errors) {
util_list_iterate(errors, s)
print_pair("ERROR", s->str);
@@ -1341,6 +1411,8 @@ static void do_info_one_device(struct device *dev, struct options *opts)
print_info("Online", online);
print_info("Exists", exists);
print_info("Persistent", persist);
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
print_info("Auto-configured", ac);
if (errors) {
first = true;
util_list_iterate(errors, s) {
@@ -1382,11 +1454,17 @@ static void do_info_one_device(struct device *dev, struct options *opts)
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
dev->persistent.exists ? dev->persistent.settings :
NULL, opts, INFO_INDENT, false, !opts->pairs);
NULL,
dev->autoconf.exists ? dev->autoconf.settings :
NULL,
opts, INFO_INDENT, false, !opts->pairs);
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
dev->persistent.exists ? dev->persistent.settings :
NULL, opts, INFO_INDENT, true, !opts->pairs);
NULL,
dev->autoconf.exists ? dev->autoconf.settings :
NULL,
opts, INFO_INDENT, true, !opts->pairs);
strlist_free(errors);
free(online);
@@ -1404,9 +1482,10 @@ static exit_code_t do_info_devices(struct options *opts)
struct util_list *selected;
struct selected_dev_node *sel;
struct device *dev;
int found, active, persistent;
int found, active, persistent, autoconf;
exit_code_t rc, drc = EXIT_OK;
read_scope_t scope;
config_t config = opts->config;
if (opts->info > 1)
scope = scope_all;
@@ -1415,7 +1494,13 @@ static exit_code_t do_info_devices(struct options *opts)
/* Get list of selected devices. */
selected = selected_dev_list_new();
select_devices(opts->select, selected, 1, 0, opts->pairs, opts->config,
/* Read auto-config data when no configuration set was specified to
* make user aware of auto-config data. */
if (!opts->active && !opts->persistent && !opts->auto_conf)
config |= config_autoconf;
select_devices(opts->select, selected, 1, 0, opts->pairs, config,
scope, err_print);
/* Process selected devices. */
@@ -1434,9 +1519,8 @@ static exit_code_t do_info_devices(struct options *opts)
/* Only process existing devices. */
active = dev->active.exists || dev->active.definable;
persistent = dev->persistent.exists;
if ((opts->config == config_active && !active) ||
(opts->config == config_persistent && !persistent) ||
(opts->config == config_all && !active && !persistent))
autoconf = dev->autoconf.exists;
if (!active && !persistent && !autoconf)
continue;
if (found > 0)
printf("\n");

View File

@@ -41,5 +41,6 @@ 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
--auto-conf Only show auto-configuration data
-V, --verbose Print additional run-time information
-q, --quiet Print only minimal run-time information

View File

@@ -98,26 +98,47 @@ static void dryrun_end_data(void)
#define READ_CHUNK_SIZE 4096
/* Read text from @fd and return resulting NULL-terminated text buffer.
* If @chomp is non-zero, remove trailing newline character. Return %NULL
* on error or when unprintable characters are read. */
static char *read_fd(FILE *fd, int chomp)
/* Read all data from @fd and return address of resulting buffer in
* @buffer_ptr. If @size_ptr is non-zero, use it to store the size of the
* resulting buffer. Return %EXIT_OK on success. */
exit_code_t misc_read_fd(FILE *fd, void **buffer_ptr, size_t *size_ptr)
{
char *buffer = NULL;
size_t done, i;
size_t done = 0;
done = 0;
while (!feof(fd)) {
buffer = realloc(buffer, done + READ_CHUNK_SIZE + 1);
buffer = realloc(buffer, done + READ_CHUNK_SIZE);
if (!buffer)
oom();
done += fread(&buffer[done], 1, READ_CHUNK_SIZE, fd);
if (ferror(fd)) {
free(buffer);
return NULL;
return EXIT_RUNTIME_ERROR;
}
}
buffer = realloc(buffer, done);
if (!buffer && done > 0)
oom();
*buffer_ptr = buffer;
if (size_ptr)
*size_ptr = done;
return EXIT_OK;
}
/* Read text from @fd and return resulting NULL-terminated text buffer.
* If @chomp is non-zero, remove trailing newline character. Return %NULL
* on error or when unprintable characters are read. */
static char *read_fd(FILE *fd, int chomp)
{
char *buffer;
size_t done, i;
if (misc_read_fd(fd, (void **) &buffer, &done))
return NULL;
/* Check if this is a text file at all (required to filter out
* binary sysfs attributes). */
for (i = 0; i < done; i++) {
@@ -131,12 +152,13 @@ static char *read_fd(FILE *fd, int chomp)
if (chomp && done > 0 && buffer[done - 1] == '\n')
done--;
if (buffer) {
/* NULL-terminate. */
buffer[done++] = 0;
}
/* NULL-terminate. */
buffer = realloc(buffer, done + 1);
if (!buffer)
oom();
buffer[done] = 0;
return realloc(buffer, done);
return buffer;
}
static int count_newline(const char *str)
@@ -1085,14 +1107,18 @@ char *misc_readlink(const char *path)
}
/* Determine configuration set. */
config_t get_config(int active, int persistent)
config_t get_config(int active, int persistent, int autoconf)
{
if ((!active && !persistent) || (active && persistent))
return config_all;
else if (active)
return config_active;
else
return config_persistent;
config_t config = 0;
if (active)
config |= config_active;
if (persistent)
config |= config_persistent;
if (autoconf)
config |= config_autoconf;
return config;
}
/* Determine if program is running under z/VM. */
@@ -1226,11 +1252,12 @@ const char *config_to_str(config_t config)
return "active";
case config_persistent:
return "persistent";
case config_autoconf:
return "autoconf";
case config_all:
return "all";
}
/* Should not happen. */
return "";
return "multiple";
}
/* Convert textual config representation to config_t. */
@@ -1240,6 +1267,8 @@ bool str_to_config(const char *str, config_t *config_ptr)
*config_ptr = config_active;
else if (strcasecmp(str, "persistent") == 0)
*config_ptr = config_persistent;
else if (strcasecmp(str, "autoconf") == 0)
*config_ptr = config_autoconf;
else if (strcasecmp(str, "all") == 0)
*config_ptr = config_all;
else
@@ -1688,3 +1717,18 @@ void debug_init(int argc, char *argv[])
fprintf(stderr, "%s\"%s\"", i > 0 ? ", " : "", argv[i]);
fprintf(stderr, "\n");
}
/* Return the last occurrence of @needle in @haystack, or %NULL if @needle
* was not found. */
char *misc_strrstr(const char *haystack, const char *needle)
{
char *result, *next;
result = strstr(haystack, needle);
if (result) {
while ((next = strstr(result + 1, needle)))
result = next;
}
return result;
}

View File

@@ -297,21 +297,25 @@ char *path_get_ccwgroup_devices(const char *drv)
}
/* Return path to udev rule. */
char *path_get_udev_rule(const char *type, const char *id)
char *path_get_udev_rule(const char *type, const char *id, bool vol)
{
const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES;
if (id) {
return path_get("%s/%s-%s-%s%s", PATH_UDEV_RULES,
return path_get("%s/%s-%s-%s%s", path,
UDEV_PREFIX, type, id, UDEV_SUFFIX);
}
return path_get("%s/%s-%s%s", PATH_UDEV_RULES,
return path_get("%s/%s-%s%s", path,
UDEV_PREFIX, type, UDEV_SUFFIX);
}
/* Return path to directory containing all udev rules. */
char *path_get_udev_rules(void)
char *path_get_udev_rules(bool vol)
{
return path_get("%s", PATH_UDEV_RULES);
const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES;
return path_get("%s", path);
}
/* Return path to the specified file in the proc file system. */

View File

@@ -15,6 +15,7 @@
#include "ccwgroup.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "misc.h"
#include "namespace.h"
#include "nic.h"
@@ -1170,6 +1171,37 @@ static exit_code_t check_ineffective_settings(struct setting_list *list,
return rc;
}
/* Check if a possibly conflicting setting is active in the configuration */
static bool conflict_setting_active(struct setting *s)
{
enum qeth_attr_group_type t;
t = get_attr_group_type(s);
if (t != group_bridge && t != group_vnicc) {
/* Check BridgePort and VNICC attributes only */
return false;
}
if (s->specified) {
/* Specified on the command line: We are strict here and do not
* allow to specify VNICC and BridgePort attributes in the same
* command to avoid issues when attributes are enabled/disabled
* in the wrong order. Example: disable VNICC and enable
* BridgePort in the same command would result in an error
* because BridgePort attributes are set first.
*/
return true;
}
if (attrib_match_default(s->attrib, s->value)) {
/* Not active if set to default value */
return false;
}
if (s->actual_value && strncmp(s->actual_value, "n/a", 3) == 0) {
/* Not active if in n/a state (conflicting attribute set) */
return false;
}
return true;
}
/* Check if there are conflicting attribute settings */
static exit_code_t check_conflicting_settings(struct setting_list *list)
{
@@ -1181,6 +1213,8 @@ static exit_code_t check_conflicting_settings(struct setting_list *list)
util_list_iterate(&list->list, s) {
if (s->removed)
continue;
if (!conflict_setting_active(s))
continue;
t = get_attr_group_type(s);
if (t == group_bridge && (!bridge || !bridge->specified))
bridge = s;
@@ -1207,7 +1241,7 @@ static exit_code_t check_layer2(struct device *dev, config_t config)
{
struct setting *l;
int layer2_detected, layer2_active = -1, layer2_persistent = -1,
layer2_modified = 0;
layer2_autoconf = -1, layer2_modified = 0;
exit_code_t rc = EXIT_OK;
layer2_detected = detect_layer2(dev);
@@ -1231,13 +1265,25 @@ static exit_code_t check_layer2(struct device *dev, config_t config)
if (rc)
goto out;
}
l = setting_list_find(dev->autoconf.settings, qeth_attr_layer2.name);
if (l) {
layer2_autoconf = atoi(l->value);
layer2_modified |= l->modified;
} else if (SCOPE_AUTOCONF(config)) {
rc = generate_layer2("autoconf", dev->autoconf.settings,
&layer2_autoconf, &layer2_modified);
if (rc)
goto out;
}
/* Check correct layer2 setting. */
if (layer2_detected != -1) {
if ((SCOPE_ACTIVE(config) && layer2_active != -1 &&
layer2_active != layer2_detected) ||
(SCOPE_PERSISTENT(config) && layer2_persistent != -1 &&
layer2_persistent != layer2_detected)) {
layer2_persistent != layer2_detected) ||
(SCOPE_AUTOCONF(config) && layer2_autoconf != -1 &&
layer2_autoconf != layer2_detected)) {
rc = layer2_mismatch(layer2_detected, layer2_modified);
if (rc)
goto out;
@@ -1256,14 +1302,25 @@ static exit_code_t check_layer2(struct device *dev, config_t config)
if (rc)
goto out;
}
if (SCOPE_AUTOCONF(config)) {
rc = check_ineffective_settings(dev->autoconf.settings,
layer2_autoconf);
if (rc)
goto out;
}
/* check for conflicting layer2 attribute groups */
if (SCOPE_ACTIVE(config)) {
rc = check_conflicting_settings(dev->active.settings);
if (rc)
goto out;
}
if (SCOPE_PERSISTENT(config))
if (SCOPE_PERSISTENT(config)) {
rc = check_conflicting_settings(dev->persistent.settings);
if (rc)
goto out;
}
if (SCOPE_AUTOCONF(config))
rc = check_conflicting_settings(dev->autoconf.settings);
out:
return rc;
@@ -1277,7 +1334,8 @@ static exit_code_t qeth_st_check_pre_configure(struct subtype *st,
/* No need to check if device is deconfigured. */
if ((SCOPE_ACTIVE(config) && dev->active.deconfigured) ||
(SCOPE_PERSISTENT(config) && dev->persistent.deconfigured))
(SCOPE_PERSISTENT(config) && dev->persistent.deconfigured) ||
(SCOPE_AUTOCONF(config) && dev->autoconf.deconfigured))
return EXIT_OK;
rc = check_layer2(dev, config);
@@ -1369,7 +1427,7 @@ static struct ccwgroup_subtype_data qeth_data = {
.num_devs = QETH_NUM_DEVS,
};
static struct subtype qeth_subtype_qeth = {
struct subtype qeth_subtype_qeth = {
.super = &ccwgroup_subtype,
.devtype = &qeth_devtype,
.name = "qeth",
@@ -1421,6 +1479,7 @@ static struct subtype qeth_subtype_qeth = {
&qeth_attr_vnicc_takeover_learning,
&qeth_attr_vnicc_bridge_invisible,
&qeth_attr_vnicc_rx_bcast,
&internal_attr_early,
),
.unknown_dev_attribs = 1,
.support_definable = 1,

View File

@@ -8,11 +8,13 @@
*/
#include <stdlib.h>
#include <string.h>
#include "lib/util_path.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "misc.h"
#include "path.h"
#include "root.h"
@@ -20,31 +22,78 @@
#include "setting.h"
#include "subtype.h"
/* Determine if the root device was modified. If it was modified, run the
* corresponding root-install scripts. */
static bool is_early_removed(struct device *dev)
{
struct setting *s;
s = setting_list_find(dev->persistent.settings,
internal_attr_early.name);
if (!s || !s->modified)
return false;
if (!s->actual_value || strcmp(s->actual_value, "1") != 0)
return false;
if (s->removed || strcmp(s->value, "0") == 0)
return true;
return false;
}
static void add_early_removed(struct util_list *selected)
{
int i, j;
struct devtype *dt;
struct subtype *st;
struct device *dev;
for (i = 0; devtypes[i]; i++) {
dt = devtypes[i];
for (j = 0; dt->subtypes[j]; j++) {
st = dt->subtypes[j];
util_list_iterate(&st->devices->hash.list, dev) {
if (is_early_removed(dev)) {
selected_dev_list_add(selected, dt, st,
dev->id, NULL, EXIT_OK);
}
}
}
}
}
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
* scripts if available. */
exit_code_t root_check(void)
{
struct util_list *selected, *params, *mod = NULL;
struct selected_dev_node *sel;
struct device *dev;
char *params_str;
exit_code_t rc;
exit_code_t rc = EXIT_OK;
struct strlist_node *s;
struct devtype *dt;
struct select_opts *select;
debug("Checking for modified root device configuration\n");
debug("Checking for required initial RAM-disk update\n");
/* Get list of devices that provide the root device. */
/* Get list of devices that provide the root device or require
* early configuration. */
selected = selected_dev_list_new();
rc = select_by_path(NULL, selected, config_active, scope_mandatory,
NULL, NULL, PATH_ROOT, err_ignore);
if (rc) {
/* First add devices that had zdev:early removed or changed to 0.
* The subsequent call to select_devices() will filter out any
* duplicates. */
add_early_removed(selected);
/* Now add devices required for root file system. */
if (select_by_path(NULL, selected, config_active, scope_mandatory,
NULL, NULL, PATH_ROOT, err_ignore)) {
/* Running from an unknown root device is not an error. */
verb("Note: Could not determine if root device configuration "
"needs to be updated\n");
rc = 0;
goto out;
}
/* Finally add devices with zdev:early=1. */
select = select_opts_new();
strlist_add(&select->by_attr, "%s=1", INTERNAL_ATTR_EARLY);
select_devices(select, selected, 1, 0, 0,
config_active | config_persistent, scope_mandatory,
err_ignore);
select_opts_free(select);
/* Determine if any of the devices or device types has been modified. */
mod = strlist_new();
@@ -60,7 +109,7 @@ exit_code_t root_check(void)
/* Check devices. */
dev = device_list_find(sel->st->devices, sel->id, NULL);
if (dev && dev->persistent.exists &&
device_needs_writing(dev, config_persistent)) {
(device_needs_writing(dev, config_persistent) || force)) {
strlist_add(mod, "%s %s", dev->subtype->devname,
dev->id);
}
@@ -68,19 +117,18 @@ exit_code_t root_check(void)
if (util_list_is_empty(mod))
goto out;
info("Note: Some of the changes affect devices providing the root "
"file system:\n");
info("Note: The initial RAM-disk must be updated for these changes to take effect:\n");
util_list_iterate(mod, s)
info(" - %s\n", s->str);
info(" Additional steps such as rebuilding the RAM-disk might be "
"required.\n");
/* Check if script is available. */
if (!util_path_is_reg_file(PATH_ROOT_SCRIPT))
if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) {
warn("A manual update of the initial RAM-disk is required.\n");
goto out;
}
/* Ask for confirmation. */
if (!confirm("Update persistent root device configuration now?")) {
if (!confirm("Update initial RAM-disk now?")) {
rc = EXIT_ABORTED;
goto out;
}
@@ -97,7 +145,7 @@ exit_code_t root_check(void)
/* Run update command. */
if (misc_system(err_delayed_print, "%s %s", PATH_ROOT_SCRIPT,
params_str) != 0) {
error("Failure while updating root device configuration\n");
error("Failure while updating initial RAM-disk\n");
delayed_print(DELAY_INDENT);
rc = EXIT_RUNTIME_ERROR;
}

View File

@@ -248,12 +248,13 @@ static void unblacklist_devices(struct select_opts *select)
bool select_match_state(struct device *dev, struct select_opts *select)
{
struct subtype *st = dev->subtype;
int exists, configured, online;
int exists, configured, autoconf, online;
struct util_list *errors;
exists = dev->active.exists || dev->active.definable;
configured = dev->persistent.exists;
if (select->all && !(exists || configured))
autoconf = dev->autoconf.exists;
if (select->all && !(exists || configured || autoconf))
return false;
if (select->existing && !exists)
return false;
@@ -862,7 +863,8 @@ static exit_code_t select_nocreate(struct select_opts *select,
select->offline || select->online ||
SCOPE_ACTIVE(config),
select->configured || select->all ||
SCOPE_PERSISTENT(config));
SCOPE_PERSISTENT(config),
select->all || SCOPE_AUTOCONF(config));
longrun_total = 0;
if (quiet)
@@ -870,7 +872,7 @@ static exit_code_t select_nocreate(struct select_opts *select,
/* Count devices. */
verb("Scanning for devices in %s configuration%s:\n",
config_to_str(id_config), id_config == config_all ? "s" : "");
config_to_str(id_config), !SCOPE_SINGLE(id_config) ? "s" : "");
for (i = 0; (dt = devtypes[i]); i++) {
if (select->devtype && dt != select->devtype)
continue;
@@ -1128,6 +1130,13 @@ static exit_code_t by_attr_cb(struct subtype *st, const char *id,
/* Check for attribute value in persistent configuration. */
s = setting_list_find(dev->persistent.settings, cb_data->key);
if (s) {
match = setting_match_value(s, cb_data->value);
if (match)
goto out;
}
/* Check for attribute value in autoconf configuration. */
s = setting_list_find(dev->autoconf.settings, cb_data->key);
if (s)
match = setting_match_value(s, cb_data->value);

View File

@@ -646,7 +646,8 @@ static void add_changes(struct util_list *list, struct setting *s)
/* Return a newly allocated string containing the setting changes found
* in PERS and ACT or NULL if no change was found. */
char *setting_get_changes(struct setting_list *act, struct setting_list *pers)
char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
struct setting_list *ac)
{
struct util_list *out;
struct util_list *processed;
@@ -668,6 +669,17 @@ char *setting_get_changes(struct setting_list *act, struct setting_list *pers)
strlist_add(processed, s->name);
}
}
if (ac) {
util_list_iterate(&ac->list, s) {
if (s->removed)
strlist_add(out, "-%s", s->name);
else if (s->modified)
add_changes(out, s);
else
continue;
strlist_add(processed, s->name);
}
}
if (act) {
util_list_iterate(&act->list, s) {
if (!s->modified && !s->removed)

View File

@@ -195,6 +195,13 @@ bool subtype_device_exists_persistent(struct subtype *st, const char *id)
return super->exists_persistent(st, id);
}
bool subtype_device_exists_autoconf(struct subtype *st, const char *id)
{
struct subtype *super = super_get(st, exists_autoconf, 1);
return super->exists_autoconf(st, id);
}
void subtype_add_active_ids(struct subtype *st, struct util_list *ids)
{
struct subtype *super = super_get(st, add_active_ids, 1);
@@ -209,6 +216,13 @@ void subtype_add_persistent_ids(struct subtype *st, struct util_list *ids)
super->add_persistent_ids(st, ids);
}
void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids)
{
struct subtype *super = super_get(st, add_autoconf_ids, 1);
super->add_autoconf_ids(st, ids);
}
exit_code_t subtype_device_read_active(struct subtype *st, struct device *dev,
read_scope_t scope)
{
@@ -226,6 +240,15 @@ exit_code_t subtype_device_read_persistent(struct subtype *st,
return super->read_persistent(st, dev, scope);
}
exit_code_t subtype_device_read_autoconf(struct subtype *st,
struct device *dev,
read_scope_t scope)
{
struct subtype *super = super_get(st, read_autoconf, 1);
return super->read_autoconf(st, dev, scope);
}
exit_code_t subtype_device_configure_active(struct subtype *st,
struct device *dev)
{
@@ -242,6 +265,14 @@ exit_code_t subtype_device_configure_persistent(struct subtype *st,
return super->configure_persistent(st, dev);
}
exit_code_t subtype_device_configure_autoconf(struct subtype *st,
struct device *dev)
{
struct subtype *super = super_get(st, configure_autoconf, 1);
return super->configure_autoconf(st, dev);
}
exit_code_t subtype_device_deconfigure_active(struct subtype *st,
struct device *dev)
{
@@ -258,6 +289,14 @@ exit_code_t subtype_device_deconfigure_persistent(struct subtype *st,
return super->deconfigure_persistent(st, dev);
}
exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
struct device *dev)
{
struct subtype *super = super_get(st, deconfigure_autoconf, 1);
return super->deconfigure_autoconf(st, dev);
}
exit_code_t subtype_check_pre_configure(struct subtype *st, struct device *dev,
int prereq, config_t config)
{
@@ -299,7 +338,7 @@ void subtype_online_set(struct subtype *st, struct device *dev, int online,
int subtype_online_get(struct subtype *st, struct device *dev, config_t config)
{
struct subtype *super = super_get(st, online_get, 0);
int act_online = 1, pers_online = 1;
int act_online = 1, pers_online = 1, auto_online = 1;
if (super)
return super->online_get(st, dev, config);
@@ -310,8 +349,10 @@ int subtype_online_get(struct subtype *st, struct device *dev, config_t config)
act_online = dev->active.exists;
if (SCOPE_PERSISTENT(config))
pers_online = dev->persistent.exists;
if (SCOPE_AUTOCONF(config))
auto_online = dev->autoconf.exists;
return MIN(act_online, pers_online);
return MIN(MIN(act_online, pers_online), auto_online);
}
bool subtype_online_specified(struct subtype *st, struct device *dev,
@@ -495,6 +536,10 @@ bool subtype_device_exists(struct subtype *st, const char *id, config_t config)
if (!subtype_device_exists_persistent(st, id))
return false;
}
if (SCOPE_AUTOCONF(config)) {
if (!subtype_device_exists_autoconf(st, id))
return false;
}
return true;
}
@@ -512,6 +557,8 @@ static struct util_list *get_ids(struct subtype *st, config_t config)
}
if (SCOPE_PERSISTENT(config))
subtype_add_persistent_ids(st, ids);
if (SCOPE_AUTOCONF(config))
subtype_add_autoconf_ids(st, ids);
/* Provide a sorted view. */
strlist_sort_unique(ids, st->namespace->qsort_cmp);
@@ -683,6 +730,19 @@ static exit_code_t read_device(struct subtype *st, const char *id,
goto out;
}
if (SCOPE_AUTOCONF(config)) {
if (subtype_device_exists_autoconf(st, id))
rc = subtype_device_read_autoconf(st, dev, scope);
else if (defined) {
/* Need to copy detected settings to autoconf
* config. */
setting_list_merge(dev->autoconf.settings,
dev->active.settings, false, false);
}
if (rc)
goto out;
}
if (add)
device_list_add(st->devices, dev);
@@ -756,6 +816,25 @@ exit_code_t subtype_write_device(struct subtype *st, struct device *dev,
if (!rc)
namespace_set_modified(dev->subtype->namespace);
}
if (SCOPE_AUTOCONF(config)) {
if (dev->autoconf.deconfigured) {
/* Deconfigure device. */
if (dev->autoconf.exists) {
rc = subtype_device_deconfigure_autoconf(st,
dev);
if (rc)
return rc;
}
} else if (dev->autoconf.exists) {
/* Configure device. */
rc = subtype_device_configure_autoconf(st, dev);
if (rc)
return rc;
}
if (!rc)
namespace_set_modified(dev->subtype->namespace);
}
return EXIT_OK;
}

View File

@@ -24,6 +24,7 @@
#include "udev.h"
int udev_need_settle = 0;
int udev_no_settle;
/* Create a newly allocated udev entry. */
static struct udev_entry_node *udev_entry_node_new(const char *key,
@@ -359,7 +360,8 @@ static bool get_ids_cb(const char *filename, void *data)
/* Add the IDs for all devices of the specified subtype name for which a
* udev rule exists to strlist LIST. */
void udev_get_device_ids(const char *type, struct util_list *list)
void udev_get_device_ids(const char *type, struct util_list *list,
bool autoconf)
{
char *path, *prefix;
struct util_list *files;
@@ -368,7 +370,7 @@ void udev_get_device_ids(const char *type, struct util_list *list)
prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type);
plen = strlen(prefix);
path = path_get_udev_rules();
path = path_get_udev_rules(autoconf);
files = strlist_new();
if (!misc_read_dir(path, files, get_ids_cb, prefix))
goto out;
@@ -387,12 +389,12 @@ out:
}
/* Remove UDEV rule for device. */
exit_code_t udev_remove_rule(const char *type, const char *id)
exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf)
{
char *path;
exit_code_t rc = EXIT_OK;
path = path_get_udev_rule(type, id);
path = path_get_udev_rule(type, id, autoconf);
if (util_path_is_reg_file(path))
rc = remove_file(path);
free(path);
@@ -403,5 +405,39 @@ exit_code_t udev_remove_rule(const char *type, const char *id)
/* Wait for all current udev events to finish. */
void udev_settle(void)
{
if (udev_no_settle)
return;
misc_system(err_ignore, "%s settle", PATH_UDEVADM);
}
/* Extract internal attribute settings from @entry and add to @list.
* Associate corresponding attribute if found in @attribs. */
void udev_add_internal_from_entry(struct setting_list *list,
struct udev_entry_node *entry,
struct attrib **attribs)
{
char *copy, *name, *end, *u;
struct attrib *a;
/* ENV{zdev_var}="1" */
copy = misc_strdup(entry->key);
/* Find attribute name start. */
name = strchr(copy, '{');
end = strrchr(copy, '}');
if (!name || !end)
goto out;
*end = 0;
name++;
/* zdev_ => zdev: */
u = strchr(name, '_');
if (u)
*u = ':';
a = attrib_find(attribs, name);
setting_list_apply_actual(list, a, name, entry->value);
out:
free(copy);
}

View File

@@ -18,6 +18,7 @@
#include "attrib.h"
#include "ccw.h"
#include "device.h"
#include "internal.h"
#include "misc.h"
#include "path.h"
#include "setting.h"
@@ -25,7 +26,7 @@
#include "udev_ccw.h"
/* Check if a udev rule for the specified ccw device exists. */
bool udev_ccw_exists(const char *type, const char *id)
bool udev_ccw_exists(const char *type, const char *id, bool autoconf)
{
char *path, *normid;
bool rc;
@@ -34,7 +35,7 @@ bool udev_ccw_exists(const char *type, const char *id)
if (!normid)
return false;
path = path_get_udev_rule(type, normid);
path = path_get_udev_rule(type, normid, autoconf);
rc = util_path_is_reg_file(path);
free(path);
free(normid);
@@ -49,6 +50,12 @@ static void add_setting_from_entry(struct setting_list *list,
char *copy, *name, *end;
struct attrib *a;
/* ENV{zdev_var}="1" */
if (starts_with(entry->key, "ENV{zdev_") &&
strcmp(entry->op, "=") == 0) {
udev_add_internal_from_entry(list, entry, attribs);
return;
}
/* ATTR{[ccw/0.0.37bf]online}=1 */
if (strncmp(entry->key, "ATTR{[ccw/", 10) != 0 ||
strcmp(entry->op, "=") != 0)
@@ -88,15 +95,16 @@ static void udev_file_get_settings(struct udev_file *file,
}
/* Read the persistent configuration of a CCW device from a udev rule. */
exit_code_t udev_ccw_read_device(struct device *dev)
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
{
struct subtype *st = dev->subtype;
struct device_state *state = &dev->persistent;
struct device_state *state = autoconf ? &dev->autoconf :
&dev->persistent;
struct udev_file *file = NULL;
exit_code_t rc;
char *path;
path = path_get_udev_rule(st->name, dev->id);
path = path_get_udev_rule(st->name, dev->id, autoconf);
rc = udev_read_file(path, &file);
if (rc)
goto out;
@@ -128,12 +136,13 @@ static char *get_label_id(const char *prefix, const char *type,
}
/* Write the persistent configuration of a CCW device to a udev rule. */
exit_code_t udev_ccw_write_device(struct device *dev)
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
{
struct subtype *st = dev->subtype;
struct ccw_subtype_data *data = st->data;
const char *type = st->name, *drv = data->ccwdrv, *id = dev->id;
struct device_state *state = &dev->persistent;
const char *type = st->name, *drv = data->any_driver ? "*" : data->ccwdrv, *id = dev->id;
struct device_state *state = autoconf ? &dev->autoconf :
&dev->persistent;
char *path, *cfg_label = NULL, *end_label = NULL;
struct util_list *list;
struct ptrlist_node *p;
@@ -142,7 +151,7 @@ exit_code_t udev_ccw_write_device(struct device *dev)
FILE *fd;
if (!state->exists)
return udev_remove_rule(type, id);
return udev_remove_rule(type, id, autoconf);
cfg_label = get_label_id("cfg", type, id);
end_label = get_label_id("end", type, id);
@@ -150,7 +159,7 @@ exit_code_t udev_ccw_write_device(struct device *dev)
/* Apply attributes in correct order. */
list = setting_list_get_sorted(state->settings);
path = path_get_udev_rule(type, id);
path = path_get_udev_rule(type, id, autoconf);
debug("Writing %s udev rule file %s\n", type, path);
if (!util_path_exists(path)) {
rc = path_create(path);
@@ -188,7 +197,14 @@ exit_code_t udev_ccw_write_device(struct device *dev)
s = p->ptr;
if (s->removed)
continue;
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name, s->value);
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 {
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name,
s->value);
}
}
/* Write udev rule epilog. */
@@ -234,14 +250,18 @@ out:
}
/* Write a udev rule to free devices from the cio-ignore blacklist. */
exit_code_t udev_ccw_write_cio_ignore(const char *id_list)
exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf)
{
char *path, *curr = NULL;
char *path, *prefix, *curr = NULL;
FILE *fd;
exit_code_t rc = EXIT_OK;
/* Ensure that autoconf version of cio-ignore is not masked
* by normal one. */
prefix = autoconf ? "cio-ignore-autoconf" : "cio-ignore";
/* Create file. */
path = path_get_udev_rule("cio-ignore", NULL);
path = path_get_udev_rule(prefix, NULL, autoconf);
if (!*id_list) {
/* Empty id_list string - remove file. */

View File

@@ -18,6 +18,7 @@
#include "attrib.h"
#include "ccwgroup.h"
#include "device.h"
#include "internal.h"
#include "misc.h"
#include "path.h"
#include "setting.h"
@@ -25,34 +26,34 @@
#include "udev_ccwgroup.h"
static char *get_rule_path_by_devid(const char *type,
struct ccwgroup_devid *devid)
struct ccwgroup_devid *devid, bool autoconf)
{
char *ccw_id, *path;
ccw_id = ccw_devid_to_str(&devid->devid[0]);
path = path_get_udev_rule(type, ccw_id);
path = path_get_udev_rule(type, ccw_id, autoconf);
free(ccw_id);
return path;
}
static char *get_rule_path(const char *type, const char *id)
static char *get_rule_path(const char *type, const char *id, bool autoconf)
{
struct ccwgroup_devid devid;
if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK)
return NULL;
return get_rule_path_by_devid(type, &devid);
return get_rule_path_by_devid(type, &devid, autoconf);
}
/* Check if a udev rule for the specified CCWGROUP device exists. */
bool udev_ccwgroup_exists(const char *type, const char *id)
bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf)
{
char *path;
bool rc;
path = get_rule_path(type, id);
path = get_rule_path(type, id, autoconf);
if (!path)
return false;
rc = util_path_is_reg_file(path);
@@ -68,6 +69,12 @@ static void add_setting_from_entry(struct setting_list *list,
char *copy, *name, *end;
struct attrib *a;
/* ENV{zdev_var}="1" */
if (starts_with(entry->key, "ENV{zdev_") &&
strcmp(entry->op, "=") == 0) {
udev_add_internal_from_entry(list, entry, attribs);
return;
}
/* ATTR{[ccwgroup/0.0.f5f0]online}=1 */
if (strncmp(entry->key, "ATTR{[ccwgroup/", 10) != 0 ||
strcmp(entry->op, "=") != 0)
@@ -143,15 +150,16 @@ static void expand_id(struct device *dev, struct udev_file *file)
}
/* Read the persistent configuration of a CCWGROUP device from a udev rule. */
exit_code_t udev_ccwgroup_read_device(struct device *dev)
exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf)
{
struct subtype *st = dev->subtype;
struct device_state *state = &dev->persistent;
struct device_state *state = autoconf ? &dev->autoconf :
&dev->persistent;
struct udev_file *file = NULL;
exit_code_t rc;
char *path;
path = get_rule_path_by_devid(st->name, dev->devid);
path = get_rule_path_by_devid(st->name, dev->devid, autoconf);
rc = udev_read_file(path, &file);
if (rc)
goto out;
@@ -184,9 +192,11 @@ static char *get_label_id(const char *prefix, const char *type,
}
/* Write the persistent configuration of a CCWGROUP device to a udev rule. */
exit_code_t udev_ccwgroup_write_device(struct device *dev)
exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
{
struct subtype *st = dev->subtype;
struct device_state *state = autoconf ? &dev->autoconf :
&dev->persistent;
struct ccwgroup_subtype_data *data = st->data;
const char *type = st->name, *drv = data->ccwgroupdrv, *id = dev->id;
struct ccwgroup_devid devid;
@@ -200,21 +210,21 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev)
FILE *fd;
unsigned int i;
if (!dev->persistent.exists)
return udev_ccwgroup_remove_rule(type, id);
if (!state->exists)
return udev_ccwgroup_remove_rule(type, id, autoconf);
if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK)
return EXIT_INVALID_ID;
ccw_id = ccw_devid_to_str(&devid.devid[0]);
path = get_rule_path(type, ccw_id);
path = get_rule_path(type, ccw_id, autoconf);
group_label = get_label_id("group", type, ccw_id);
cfg_label = get_label_id("cfg", type, ccw_id);
end_label = get_label_id("end", type, ccw_id);
/* Apply attributes in correct order. */
list = setting_list_get_sorted(dev->persistent.settings);
list = setting_list_get_sorted(state->settings);
debug("Writing %s udev rule file %s\n", type, path);
if (!util_path_exists(path)) {
@@ -279,6 +289,10 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev)
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n",
ccw_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 {
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n", ccw_id,
s->name, s->value);
@@ -357,12 +371,13 @@ static exit_code_t get_ids_cb(const char *path, const char *filename,
/* Add the IDs for all devices of the specified subtype name for which a
* udev rule exists to strlist LIST. */
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list)
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
bool autoconf)
{
struct get_ids_cb_data cb_data;
char *path;
path = path_get_udev_rules();
path = path_get_udev_rules(autoconf);
cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type);
cb_data.ids = list;
@@ -374,7 +389,8 @@ void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list)
}
/* Remove UDEV rule for CCWGROUP device. */
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id)
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
bool autoconf)
{
char *partial_id, *path;
exit_code_t rc = EXIT_OK;
@@ -383,7 +399,7 @@ exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id)
if (!partial_id)
return EXIT_INVALID_ID;
path = path_get_udev_rule(type, partial_id);
path = path_get_udev_rule(type, partial_id, autoconf);
if (util_path_is_reg_file(path))
rc = remove_file(path);
free(path);

View File

@@ -18,6 +18,7 @@
#include "attrib.h"
#include "device.h"
#include "internal.h"
#include "misc.h"
#include "path.h"
#include "scsi.h"
@@ -128,7 +129,7 @@ static bool zfcp_lun_devid_from_entry(struct zfcp_lun_devid *id_ptr,
struct udev_entry_node *entry)
{
struct zfcp_lun_devid id;
char *copy = NULL, *s;
char *copy = NULL, *s, *e, *u;
int i;
bool rc = false;
@@ -182,6 +183,28 @@ static bool zfcp_lun_devid_from_entry(struct zfcp_lun_devid *id_ptr,
goto out;
}
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
if (starts_with(entry->key, "ENV{zdev_")) {
copy = misc_strdup(entry->key);
/* Find ID start (last __) and end (last }). */
s = misc_strrstr(copy, "__");
e = strrchr(copy, '}');
if (!s || !e)
goto out;
*e = 0;
s += 2;
/* Convert variable name to ID format. */
for (i = 0, u = s; (u = strchr(u, '_')); i++, u++) {
if (i < 2)
*u = '.';
else
*u = ':';
}
rc = zfcp_lun_parse_devid(&id, s, err_ignore) == EXIT_OK ?
true : false;
}
out:
free(copy);
if (rc)
@@ -211,11 +234,46 @@ static struct zfcp_lun_node *zfcp_lun_node_from_entry(
return node;
}
static void add_internal_setting_from_entry(struct udev_entry_node *entry,
struct zfcp_lun_node *node)
{
char *copy, *name, *end, *u;
struct attrib *a;
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
copy = misc_strdup(entry->key);
/* Find attribute name start and end. */
name = strchr(copy, '{');
end = misc_strrstr(copy, "__");
if (!name || !end)
goto out;
*end = 0;
name++;
/* zdev_ => zdev: */
u = strchr(name, '_');
if (u)
*u = ':';
a = attrib_find(zfcp_lun_subtype.dev_attribs, name);
setting_list_apply_actual(node->fc_settings, a, name, entry->value);
out:
free(copy);
}
static void add_fc_setting_from_entry(struct udev_entry_node *entry,
struct zfcp_lun_node *node)
{
char *copy, *s, *e;
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
if (starts_with(entry->key, "ENV{zdev_") &&
strcmp(entry->op, "=") == 0) {
add_internal_setting_from_entry(entry, node);
return;
}
/*ATTR{[ccw/0.0.1941]0x500507630510c1ae/0x402340d400000000/failed}="0"*/
if (!starts_with(entry->key, "ATTR{[ccw/"))
return;
@@ -369,14 +427,14 @@ static exit_code_t lun_cb(const char *path, const char *name, void *data)
/* Add the IDs for all zfcp lun devices for which a configuration exists to
* LIST. */
void udev_zfcp_lun_add_device_ids(struct util_list *list)
void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf)
{
struct lun_cb_data cb_data;
char *path;
cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, ZFCP_LUN_NAME);
cb_data.list = list;
path = path_get_udev_rules();
path = path_get_udev_rules(autoconf);
if (util_path_is_dir(path))
path_for_each(path, lun_cb, &cb_data);
@@ -385,7 +443,9 @@ void udev_zfcp_lun_add_device_ids(struct util_list *list)
free(cb_data.prefix);
}
static char *get_zfcp_lun_path(const char *id)
/* Return path to zfcp lun udev rule file containing configuration data for
* all LUNs of a zfcp device. */
static char *get_zfcp_lun_path(const char *id, bool autoconf)
{
char *copy, *e, *path;
@@ -393,12 +453,19 @@ static char *get_zfcp_lun_path(const char *id)
e = strchr(copy, ':');
if (e)
*e = 0;
path = path_get_udev_rule(ZFCP_LUN_NAME, copy);
path = path_get_udev_rule(ZFCP_LUN_NAME, copy, autoconf);
free(copy);
return path;
}
/* Return path to zfcp lun udev rule file containing configuration data for
* a single LUN. */
static char *get_single_zfcp_lun_path(const char *id, bool autoconf)
{
return path_get_udev_rule(ZFCP_LUN_NAME, id, autoconf);
}
/* Apply the settings found in NODE to STATE. */
static void zfcp_lun_node_to_state(struct zfcp_lun_node *node,
struct attrib **attribs,
@@ -428,16 +495,22 @@ static void zfcp_lun_node_to_state(struct zfcp_lun_node *node,
}
/* Read the persistent configuration of a zfcp lun from a udev rule. */
exit_code_t udev_zfcp_lun_read_device(struct device *dev)
exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf)
{
struct subtype *st = dev->subtype;
struct device_state *state = &dev->persistent;
struct device_state *state = autoconf ? &dev->autoconf :
&dev->persistent;
struct util_list *luns;
struct zfcp_lun_node *node;
exit_code_t rc = EXIT_OK;
char *path;
path = get_zfcp_lun_path(dev->id);
/* Check for single lun file first then try multi lun file. */
path = get_single_zfcp_lun_path(dev->id, autoconf);
if (!util_path_exists(path)) {
free(path);
path = get_zfcp_lun_path(dev->id, autoconf);
}
/* Get previous rule data. */
luns = zfcp_lun_node_list_new();
@@ -475,7 +548,7 @@ static struct zfcp_lun_node *state_to_zfcp_lun_node(struct zfcp_lun_devid *id,
s->value);
setting_list_add(node->scsi_settings, n);
} else {
n = setting_new(NULL, s->name, s->value);
n = setting_new(s->attrib, s->name, s->value);
setting_list_add(node->fc_settings, n);
}
}
@@ -565,9 +638,21 @@ static exit_code_t write_luns_rule(const char *path, struct util_list *list)
node->id.lun);
util_list_iterate(&node->fc_settings->list, s) {
fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64 "/0x%016"
PRIx64 "/%s}=\"%s\"\n", hba_id, node->id.wwpn,
node->id.lun, s->name, s->value);
if ((s->attrib && s->attrib->internal) ||
internal_by_name(s->name)) {
fprintf(fd, "ENV{zdev_%s__%x_%x_%04x_0x%016"
PRIx64 "_0x%016" PRIx64 "}=\"%s\"\n",
internal_get_name(s->name),
node->id.fcp_dev.cssid,
node->id.fcp_dev.ssid,
node->id.fcp_dev.devno, node->id.wwpn,
node->id.lun, s->value);
} else {
fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64
"/0x%016" PRIx64 "/%s}=\"%s\"\n",
hba_id, node->id.wwpn, node->id.lun,
s->name, s->value);
}
}
last_node = node;
}
@@ -599,8 +684,10 @@ out:
/* Update the udev rule file that configures the zfcp lun with the specified
* ID. If @state is %NULL, remove the rule, otherwise create a rule that
* applies the corresponding parameters. */
static exit_code_t update_lun_rule(const char *id, struct device_state *state)
* applies the corresponding parameters. If @single is set, update a single
* lun rule file, otherwise update a multi lun rule file. */
static exit_code_t update_lun_rule(const char *id, struct device_state *state,
bool single, bool autoconf)
{
struct zfcp_lun_devid devid;
struct util_list *luns;
@@ -612,7 +699,8 @@ static exit_code_t update_lun_rule(const char *id, struct device_state *state)
rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print);
if (rc)
return rc;
path = get_zfcp_lun_path(id);
path = single ? get_single_zfcp_lun_path(id, autoconf) :
get_zfcp_lun_path(id, autoconf);
/* Get previous rule data. */
luns = zfcp_lun_node_list_new();
@@ -648,27 +736,55 @@ static exit_code_t update_lun_rule(const char *id, struct device_state *state)
/* Write a udev-rule to configure the specified zfcp lun and associated
* device state. */
exit_code_t udev_zfcp_lun_write_device(struct device *dev)
exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf)
{
return update_lun_rule(dev->id, &dev->persistent);
exit_code_t rc;
struct device_state *state = autoconf ? &dev->autoconf :
&dev->persistent;
rc = update_lun_rule(dev->id, state, true, autoconf);
/* We only want single lun rule files so remove any remaining
* references in multi lun rule files. */
update_lun_rule(dev->id, NULL, false, autoconf);
return rc;
}
/* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */
exit_code_t udev_zfcp_lun_remove_rule(const char *id)
exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf)
{
return update_lun_rule(id, NULL);
exit_code_t rc, rc2;
rc = update_lun_rule(id, NULL, true, autoconf);
rc2 = update_lun_rule(id, NULL, false, autoconf);
if (rc)
return rc;
return rc2;
}
/* Determine if a udev rule exists for configuring the specified zfcp lun. */
bool udev_zfcp_lun_exists(const char *id)
bool udev_zfcp_lun_exists(const char *id, bool autoconf)
{
struct zfcp_lun_devid devid;
char *path, *rule, *pattern = NULL;
char *path, *rule = NULL, *pattern = NULL;
bool rc = false;
if (zfcp_lun_parse_devid(&devid, id, err_ignore) != EXIT_OK)
return false;
path = get_zfcp_lun_path(id);
/* Check for single lun rule file first. */
path = get_single_zfcp_lun_path(id, autoconf);
if (util_path_exists(path)) {
rc = true;
goto out;
}
free(path);
/* Check multi lun rule file next. */
path = get_zfcp_lun_path(id, autoconf);
rule = misc_read_text_file(path, 1, err_ignore);
if (!rule)
goto out;

View File

@@ -17,6 +17,7 @@
#include "ccw.h"
#include "device.h"
#include "devtype.h"
#include "internal.h"
#include "misc.h"
#include "path.h"
#include "setting.h"
@@ -247,6 +248,7 @@ struct subtype zfcp_host_subtype = {
&zfcp_host_attr_failed,
&zfcp_host_attr_port_remove,
&zfcp_host_attr_port_rescan,
&internal_attr_early,
),
.unknown_dev_attribs = 1,

View File

@@ -21,6 +21,7 @@
#include "devnode.h"
#include "devtype.h"
#include "misc.h"
#include "internal.h"
#include "namespace.h"
#include "path.h"
#include "scsi.h"
@@ -467,7 +468,14 @@ static exit_code_t zfcp_lun_st_read_persistent(struct subtype *st,
struct device *dev,
read_scope_t scope)
{
return udev_zfcp_lun_read_device(dev);
return udev_zfcp_lun_read_device(dev, false);
}
static exit_code_t zfcp_lun_st_read_autoconf(struct subtype *st,
struct device *dev,
read_scope_t scope)
{
return udev_zfcp_lun_read_device(dev, true);
}
static exit_code_t zfcp_lun_add(struct device *dev)
@@ -564,7 +572,13 @@ static exit_code_t zfcp_lun_st_configure_active(struct subtype *st,
static exit_code_t zfcp_lun_st_configure_persistent(struct subtype *st,
struct device *dev)
{
return udev_zfcp_lun_write_device(dev);
return udev_zfcp_lun_write_device(dev, false);
}
static exit_code_t zfcp_lun_st_configure_autoconf(struct subtype *st,
struct device *dev)
{
return udev_zfcp_lun_write_device(dev, true);
}
static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st,
@@ -578,7 +592,13 @@ static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st,
static exit_code_t zfcp_lun_st_deconfigure_persistent(struct subtype *st,
struct device *dev)
{
return udev_zfcp_lun_remove_rule(dev->id);
return udev_zfcp_lun_remove_rule(dev->id, false);
}
static exit_code_t zfcp_lun_st_deconfigure_autoconf(struct subtype *st,
struct device *dev)
{
return udev_zfcp_lun_remove_rule(dev->id, true);
}
static exit_code_t check_npiv(struct subtype *st, struct device *dev,
@@ -606,7 +626,8 @@ static exit_code_t check_npiv(struct subtype *st, struct device *dev,
if (!allow_lun_scan)
goto out;
if (!(dev->active.deconfigured || dev->persistent.deconfigured)) {
if (!(dev->active.deconfigured || dev->persistent.deconfigured ||
dev->autoconf.deconfigured)) {
delayed_info("Note: Auto LUN scan enabled - manual LUN "
"configuration is redundant for %s %s\n",
zfcp_host_subtype.devname, fcp_dev_id);
@@ -643,7 +664,8 @@ static exit_code_t zfcp_lun_st_check_post_configure(struct subtype *st,
/* Don't show note when an attribute was modified. */
if (setting_list_modified(dev->active.settings) ||
setting_list_modified(dev->persistent.settings))
setting_list_modified(dev->persistent.settings) ||
setting_list_modified(dev->autoconf.settings))
return EXIT_OK;
/* Check for NPIV but don't route exit code to caller - we only
@@ -795,7 +817,12 @@ static bool zfcp_lun_st_exists_active(struct subtype *st, const char *id)
static bool zfcp_lun_st_exists_persistent(struct subtype *st, const char *id)
{
return udev_zfcp_lun_exists(id);
return udev_zfcp_lun_exists(id, false);
}
static bool zfcp_lun_st_exists_autoconf(struct subtype *st, const char *id)
{
return udev_zfcp_lun_exists(id, true);
}
static exit_code_t zfcp_lun_st_is_definable(struct subtype *st, const char *id,
@@ -889,7 +916,13 @@ static void zfcp_lun_st_add_active_ids(struct subtype *st,
static void zfcp_lun_st_add_persistent_ids(struct subtype *st,
struct util_list *ids)
{
udev_zfcp_lun_add_device_ids(ids);
udev_zfcp_lun_add_device_ids(ids, false);
}
static void zfcp_lun_st_add_autoconf_ids(struct subtype *st,
struct util_list *ids)
{
udev_zfcp_lun_add_device_ids(ids, true);
}
static exit_code_t add_sg_cb(const char *path, const char *filename, void *data)
@@ -1065,6 +1098,7 @@ struct subtype zfcp_lun_subtype = {
&zfcp_lun_attr_scsi_timeout,
&zfcp_lun_attr_scsi_state,
&zfcp_lun_attr_scsi_delete,
&internal_attr_early,
),
.prefixes = STRING_ARRAY(SCSI_ATTR_PREFIX),
.unknown_dev_attribs = 1,
@@ -1072,18 +1106,23 @@ struct subtype zfcp_lun_subtype = {
.exists_active = &zfcp_lun_st_exists_active,
.exists_persistent = &zfcp_lun_st_exists_persistent,
.exists_autoconf = &zfcp_lun_st_exists_autoconf,
.add_active_ids = &zfcp_lun_st_add_active_ids,
.add_persistent_ids = &zfcp_lun_st_add_persistent_ids,
.add_autoconf_ids = &zfcp_lun_st_add_autoconf_ids,
.read_active = &zfcp_lun_st_read_active,
.read_persistent = &zfcp_lun_st_read_persistent,
.read_autoconf = &zfcp_lun_st_read_autoconf,
.configure_active = &zfcp_lun_st_configure_active,
.configure_persistent = &zfcp_lun_st_configure_persistent,
.configure_autoconf = &zfcp_lun_st_configure_autoconf,
.deconfigure_active = &zfcp_lun_st_deconfigure_active,
.deconfigure_persistent = &zfcp_lun_st_deconfigure_persistent,
.deconfigure_autoconf = &zfcp_lun_st_deconfigure_autoconf,
.check_pre_configure = &zfcp_lun_st_check_pre_configure,
.check_post_configure = &zfcp_lun_st_check_post_configure,

View File

@@ -774,7 +774,7 @@ static const struct fuse_opt zdsfs_opts[] = {
static void usage(const char *progname)
{
fprintf(stderr,
fprintf(stdout,
"Usage: %s <devices> <mountpoint> [<options>]\n"
"\n"
"Use the zdsfs command to provide read access to data sets stored on one or\n"
@@ -976,14 +976,24 @@ static int zdsfs_process_args(void *UNUSED(data), const char *arg, int key,
return 0;
case KEY_HELP:
usage(outargs->argv[0]);
/*
* Usage output needs to go to stdout to be consistent with
* coding guidelines. FUSE versions before 3.0.0 print help
* output to stderr. Redirect stderr to stdout here to enforce
* consistent behavior.
*/
fflush(stderr);
dup2(STDOUT_FILENO, STDERR_FILENO);
fuse_opt_add_arg(outargs, "-ho");
/* call fuse_main to let library print fuse options */
fuse_main(outargs->argc, outargs->argv, &rdf_oper, NULL);
exit(0);
case KEY_VERSION:
fprintf(stderr, COMP "FUSE file system for z/OS data set access"
fprintf(stdout, COMP "FUSE file system for z/OS data set access"
", program version %s\n", RELEASE_STRING);
fprintf(stderr, "Copyright IBM Corp. 2013, 2017\n");
fprintf(stdout, "Copyright IBM Corp. 2013, 2017\n");
exit(0);
default:
fprintf(stderr, "Unknown argument key %x\n", key);

114
zfcpdump/10-zfcpdump.install.in Executable file
View File

@@ -0,0 +1,114 @@
#!/bin/bash
#
# 10-zfcpdump.install - Installation script to handle zfcpdump kernels
#
# Copyright IBM Corp. 2018
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
#
# This script supports two modes:
#
# 1) Installing the images to /boot/<machine-id>/<kernel-version>
# subdirectories, i.e. BOOT_DIR_ABS, as recommended by the BLS.
# In this case file names are taken over from the original files.
#
# 2) Installing the images directly to /boot. In this case the files are
# renamed to <original-name>-<kernel-version>.
#
# The existence of BOOT_DIR_ABS is taken as trigger to switch between both
# modes.
#
# The KERNEL_VERSION is assumed to contain '@flavor@' to identify the image
# as a zfcpdump kernel.
COMMAND="$1"
KERNEL_VERSION="$2"
BOOT_DIR_ABS="$3"
KERNEL_IMAGE="$4"
# Location zipl looks for the zfcpdump kernel
ZFCPDUMP_IMAGE='@zfcpdump_image@'
# Only handle zfcpdump kernels
echo "$KERNEL_VERSION" | grep -q '@flavor@' || exit 0
case "$COMMAND" in
add)
KERNEL_DIR="$(dirname $KERNEL_IMAGE)"
KERNEL_NAME="$(basename $KERNEL_IMAGE)"
for f in \
"$KERNEL_IMAGE" \
"$KERNEL_DIR"/System.map \
"$KERNEL_DIR"/config \
"$KERNEL_DIR"/zImage.stub
do
test -e "$f" || continue
test -d "$BOOT_DIR_ABS" \
&& DEST="$BOOT_DIR_ABS/$(basename $f)" \
|| DEST="/boot/$(basename $f)-$KERNEL_VERSION"
cp -aT "$f" "$DEST"
test $(command -v restorecon) && restorecon -R "$DEST"
done
# hmac file need special treatment
f="$KERNEL_DIR/.$KERNEL_NAME.hmac"
if [ -e "$f" ]; then
test -d "$BOOT_DIR_ABS" \
&& DEST="$BOOT_DIR_ABS/$(basename $f)" \
|| DEST="/boot/.$KERNEL_NAME-$KERNEL_VERSION.hmac"
cp -aT "$f" "$DEST"
test $(command -v restorecon) && restorecon -R "$DEST"
fi
# Set link so zipl finds the kernel
test -d "$BOOT_DIR_ABS" \
&& TARGET="$BOOT_DIR_ABS/$KERNEL_NAME" \
|| TARGET="/boot/$KERNEL_NAME-$KERNEL_VERSION"
ln -sf "$TARGET" "$ZFCPDUMP_IMAGE"
;;
remove)
# On removal
# $KERNEL_IMAGE is empty -> $KERNEL_NAME is empty -> rebuild it
KERNEL_NAME="$(basename $(readlink $ZFCPDUMP_IMAGE))"
if [ -d "$BOOT_DIR_ABS" ]; then
INSTALL_DIR="$(dirname $BOOT_DIR_ABS)"
else
INSTALL_DIR="/boot/"
KERNEL_NAME="$(echo $KERNEL_NAME \
| sed -e "s#\(.*\)-$KERNEL_VERSION#\1#")"
fi
for f in $(find "$INSTALL_DIR" -name "*$KERNEL_VERSION*"); do
rm -rf "$f"
done
# Update link to latest remaining zfcpdump kernel.
if [ $(readlink "$ZFCPDUMP_IMAGE" | grep "$KERNEL_VERSION") ]
then
NEXT_IMAGE=$( \
find "$INSTALL_DIR" -type f \
| grep '@flavor@' \
| grep "$KERNEL_NAME" \
| grep -v "hmac" \
| sort -V \
| tail -n1 )
test $NEXT_IMAGE \
&& ln -sf "$NEXT_IMAGE" "$ZFCPDUMP_IMAGE" \
|| rm -f "$ZFCPDUMP_IMAGE"
fi
;;
*)
;;
esac
# Prevent execution of all other scripts.
# The zfcpdump kernel is stripped down to the bare minimum needed for
# dumping. It is not supposed to be used for any other purpose.
exit 77

View File

@@ -1,6 +1,7 @@
include ../common.mak
CPIOINIT = $(call echocmd," CPIOINI ",/$@)./cpioinit
INSTALL_SCRIPTS = 10-zfcpdump.install
ifeq (${HAVE_LIBC_STATIC},0)
@@ -20,7 +21,7 @@ check_dep:
"HAVE_LIBC_STATIC=0", \
"-static")
all: check_dep $(ZFCPDUMP_PART_RD)
all: check_dep $(ZFCPDUMP_INITRD) scripts
cpioinit: cpioinit.c
$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
@@ -29,17 +30,26 @@ zfcpdump_part: zfcpdump.o zfcpdump_part.o
$(LINK) $(ALL_LDFLAGS) $^ -static -o $@
$(STRIP) -s $@
$(ZFCPDUMP_PART_RD): cpioinit zfcpdump_part
$(ZFCPDUMP_INITRD): cpioinit zfcpdump_part
$(CPIOINIT) zfcpdump_part > $@.tmp
$(GZIP) -f $@.tmp
$(MV) $@.tmp.gz $(ZFCPDUMP_PART_RD)
$(MV) $@.tmp.gz $(ZFCPDUMP_INITRD)
scripts: $(INSTALL_SCRIPTS)
chmod +x $(INSTALL_SCRIPTS)
install: all
$(INSTALL) -m 611 $(ZFCPDUMP_PART_RD) $(DESTDIR)$(ZFCPDUMP_DIR)
$(INSTALL) -m 611 $(ZFCPDUMP_INITRD) $(DESTDIR)$(ZFCPDUMP_DIR)
%: %.in
zfcpdump_image=$(ZFCPDUMP_DIR)/$(ZFCPDUMP_IMAGE); \
$(SED) -e "s#@zfcpdump_image@#$$zfcpdump_image#g" \
-e "s#@flavor@#$(ZFCPDUMP_FLAVOR)#g" \
< $< > $@
endif
clean:
rm -f *.o *.gz *.tmp *~ zfcpdump_part cpioinit $(ZFCPDUMP_PART_RD)
rm -f *.o *.gz *.tmp *~ zfcpdump_part cpioinit $(ZFCPDUMP_INITRD) \
$(INSTALL_SCRIPTS)
.PHONY: all clean install check_dep
.PHONY: all clean install check_dep scripts

View File

@@ -29,9 +29,6 @@
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#ifdef GZIP_SUPPORT
#include <zlib.h>
#endif
#include "lib/zt_common.h"
#include "zfcpdump.h"
@@ -288,12 +285,10 @@ no_reipl:
/*
* Signal handler for zfcp_dumper
*/
static __sighandler_t dump_sig_handler(int sig, siginfo_t *UNUSED(sip),
void *UNUSED(p))
static void dump_sig_handler(int sig, siginfo_t *UNUSED(sip), void *UNUSED(p))
{
PRINT_ERR("Got signal: %i\n", sig);
terminate(1);
return NULL;
}
/*
@@ -304,7 +299,7 @@ static __sighandler_t dump_sig_handler(int sig, siginfo_t *UNUSED(sip),
static int init_sig(void)
{
g.sigact.sa_flags = (SA_NODEFER | SA_SIGINFO | SA_RESETHAND);
g.sigact.sa_handler = (__sighandler_t)dump_sig_handler;
g.sigact.sa_sigaction = dump_sig_handler;
if (sigemptyset(&g.sigact.sa_mask) < 0)
return -1;
if (sigaction(SIGINT, &g.sigact, NULL) < 0)
@@ -359,41 +354,10 @@ void show_progress(unsigned long done)
time_next = tv.tv_sec + 10;
}
/*
* Load a kernel module
*/
static void modprobe(const char *module)
{
pid_t pid;
pid = fork();
if (pid < 0) {
PRINT_PERR("fork failed\n");
return;
} else if (pid == 0) {
execl("/bin/modprobe", "modprobe", module, "-q", NULL);
execl("/sbin/modprobe", "modprobe", module, "-q", NULL);
exit(1);
} else {
waitpid(pid, NULL, 0);
}
}
/*
* Load all required kernel modules
*/
static void load_modules(const char *module_list[])
{
int i;
for (i = 0; module_list[i]; i++)
modprobe(module_list[i]);
}
/*
* Initialize zfcpdump
*/
int zfcpdump_init(const char *module_list[])
int zfcpdump_init(void)
{
char start_time_str[128], linux_version[256];
@@ -436,7 +400,6 @@ int zfcpdump_init(const char *module_list[])
PRINT_ERR("Could not parse parmline\n");
return -1;
}
load_modules(module_list);
if (enable_zfcp_device()) {
PRINT_ERR("Could not enable dump device\n");
return -1;

View File

@@ -103,7 +103,7 @@ struct mem_chunk {
*/
void release_hsa(void);
__u64 get_hsa_size(void);
int zfcpdump_init(const char *module_list[]);
int zfcpdump_init(void);
void print_newline(void);
void show_progress(unsigned long done);
int terminate(int rc);

View File

@@ -103,7 +103,6 @@ struct scsi_mbr {
/*
* Globals
*/
static const char *module_list[] = {"zfcp", "sd_mod", "zcore_mod", NULL};
static struct scsi_dump_sb dump_sb;
static struct scsi_mbr mbr;
@@ -440,7 +439,7 @@ int main(int UNUSED(argc), char *UNUSED(argv[]))
{
int rc;
if (zfcpdump_init(module_list))
if (zfcpdump_init())
return terminate(1);
PRINT("Dump parameters:\n");
PRINT(" devno....: %s\n", g.dump_devno);

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