- hyptop: Backward compatibility options causes other issues (RHEL-166157) - zipl/boot: Fix stage3 secure boot trailer placement (RHEL-170707) - SEL-EBC: instrumentation of an SEL initramfs to support early boot customization (RHEL-136433) - SEL-EBC: tool to build basic SEL-qcow2 image supporting early boot customization (RHEL-136435) - KVM: Enhance pvimg info command to display additional SE image information (RHEL-73136) - Resolves: RHEL-174898 RHEL-166157 RHEL-170707 RHEL-136433 RHEL-136435 RHEL-73136
1734 lines
48 KiB
Diff
1734 lines
48 KiB
Diff
From 89134a8f40d328a2c7cfc70f0470ae1c1354b036 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:25:08 +0200
|
|
Subject: [PATCH 1/7] Revert "zipl/man: Only mention 3490 tape devices"
|
|
|
|
This reverts commit 075f7f71868be2b21fa6f6c49355db3df53c3926.
|
|
---
|
|
zipl/man/zipl.8.in | 2 +-
|
|
zipl/man/zipl.conf.5.in | 4 ++--
|
|
2 files changed, 3 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/zipl/man/zipl.8.in b/zipl/man/zipl.8.in
|
|
index e7256ea5..1226d481 100644
|
|
--- a/zipl/man/zipl.8.in
|
|
+++ b/zipl/man/zipl.8.in
|
|
@@ -258,7 +258,7 @@ or configuration section on the command line at the same time.
|
|
Install a system dump record on the device identified by DEVNODE.
|
|
Supported devices are DASD ECKD or FBA disk partitions,
|
|
device mapper multipath partitions of FCP attached SCSI disks,
|
|
-partitions of NVMe disks and IBM 3490 tape devices.
|
|
+partitions of NVMe disks and IBM 3480/3490/3590/3592 tape devices.
|
|
|
|
For CCW-type DASD dump, zlib compression is used to compress the
|
|
dump data before writing it to the DASD ECKD partition. Zlib compression
|
|
diff --git a/zipl/man/zipl.conf.5.in b/zipl/man/zipl.conf.5.in
|
|
index 2c25fac8..8d8a0461 100644
|
|
--- a/zipl/man/zipl.conf.5.in
|
|
+++ b/zipl/man/zipl.conf.5.in
|
|
@@ -372,7 +372,7 @@ indicates the menu name.
|
|
.B Configuration section:
|
|
.br
|
|
Specify a DASD partition, device mapper multipath partition device node of a
|
|
-SCSI disk, a NVMe partition or an IBM 3490 tape device on which to
|
|
+SCSI disk, a NVMe partition or an IBM 3480/3490/3590 tape device on which to
|
|
install a system dump record. Once a device prepared in such a way
|
|
is booted, the current system status is written in a raw format to that device
|
|
and can later be retrieved using the
|
|
@@ -596,7 +596,7 @@ file.
|
|
.IP
|
|
.B Configuration section:
|
|
.br
|
|
-Specify a IBM 3490 tape device on which to install a boot record.
|
|
+Specify a IBM 3480/3490/3590 tape device on which to install a boot record.
|
|
|
|
This option cannot be used together with
|
|
.BR 'target' ", "
|
|
--
|
|
2.54.0
|
|
|
|
|
|
From e48f23e21c46b4577c1c23063fbe5ba2cf369144 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:25:38 +0200
|
|
Subject: [PATCH 2/7] Revert "zipl/tape2dump: Remove check for data compaction
|
|
support"
|
|
|
|
This reverts commit 5af1e8cc693ef9be4a8e7efb23b9fa9a4b2e0d6d.
|
|
---
|
|
zipl/boot/tape2dump.c | 22 +++++++++++++++++++---
|
|
1 file changed, 19 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/zipl/boot/tape2dump.c b/zipl/boot/tape2dump.c
|
|
index 3cb69f45..41136160 100644
|
|
--- a/zipl/boot/tape2dump.c
|
|
+++ b/zipl/boot/tape2dump.c
|
|
@@ -25,6 +25,7 @@
|
|
#define WRITE_CMD 0x01 /* Write block */
|
|
#define SENSE_OVERRUN 0x04 /* Sense */
|
|
#define WRITETAPEMARK 0x1f /* Write Tape Mark */
|
|
+#define READ_DEV_CHAR 0x64 /* Read device characteristics */
|
|
#define MODE_SET_DB 0xdb /* Mode set */
|
|
|
|
/*
|
|
@@ -104,12 +105,27 @@ static void start_ccw(uint8_t code, uint8_t flags, uint16_t count, void *cda)
|
|
}
|
|
|
|
/*
|
|
- * Enable data compaction
|
|
+ * Read tape device characteristics to find out if IDRC compression can be used
|
|
*/
|
|
static void setup_idrc_compression(void)
|
|
{
|
|
- ccw_init(&ccw_program.compress, MODE_SET_DB, CCW_FLAG_CC, 0x1, &mode_set_byte);
|
|
- orb.cpa = __pa32(&ccw_program.compress);
|
|
+ uint16_t type;
|
|
+
|
|
+ start_ccw(READ_DEV_CHAR, 0x0, 0x40, ccw_data);
|
|
+
|
|
+ memcpy(&type, &ccw_data[3], sizeof(type));
|
|
+ switch (type) {
|
|
+ case 0x3490:
|
|
+ case 0x3590: // XXX 3592
|
|
+ ccw_init(&ccw_program.compress, MODE_SET_DB, CCW_FLAG_CC, 0x1,
|
|
+ &mode_set_byte);
|
|
+ orb.cpa = __pa32(&ccw_program.compress);
|
|
+ break;
|
|
+ default:
|
|
+ case 0x3480:
|
|
+ orb.cpa = __pa32(&ccw_program.write);
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
--
|
|
2.54.0
|
|
|
|
|
|
From 78202d1ec90774c252c04c4d4247edc020eb3c18 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:26:09 +0200
|
|
Subject: [PATCH 3/7] Revert "zipl/tape2dump: Remove load display command"
|
|
|
|
This reverts commit 145c21a9ca01b65aac527c8c91f455dccca27581.
|
|
---
|
|
zipl/boot/tape2dump.c | 27 +++++++++++++++++++++++++++
|
|
1 file changed, 27 insertions(+)
|
|
|
|
diff --git a/zipl/boot/tape2dump.c b/zipl/boot/tape2dump.c
|
|
index 41136160..6ad795a4 100644
|
|
--- a/zipl/boot/tape2dump.c
|
|
+++ b/zipl/boot/tape2dump.c
|
|
@@ -26,6 +26,7 @@
|
|
#define SENSE_OVERRUN 0x04 /* Sense */
|
|
#define WRITETAPEMARK 0x1f /* Write Tape Mark */
|
|
#define READ_DEV_CHAR 0x64 /* Read device characteristics */
|
|
+#define LOAD_DISPLAY 0x9f /* Load tape display */
|
|
#define MODE_SET_DB 0xdb /* Mode set */
|
|
|
|
/*
|
|
@@ -128,6 +129,17 @@ static void setup_idrc_compression(void)
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * Print message on tape display
|
|
+ */
|
|
+static void ccw_load_display(const char *msg)
|
|
+{
|
|
+ char _msg[24] = {0x20};
|
|
+
|
|
+ strcpy(&_msg[1], msg);
|
|
+ start_ccw(LOAD_DISPLAY, CCW_FLAG_SLI, 0x11, (void *) _msg);
|
|
+}
|
|
+
|
|
/*
|
|
* Write sense data to buffer
|
|
*/
|
|
@@ -170,6 +182,19 @@ static void ccw_write_block(unsigned long addr, unsigned long size,
|
|
panic(EMEM, "Device too small");
|
|
}
|
|
|
|
+/*
|
|
+ * Every 16 MB we update the tape display
|
|
+ */
|
|
+static void progress_print_disp(unsigned long addr)
|
|
+{
|
|
+ char msg[24];
|
|
+
|
|
+ if (addr % (1024 * 1024 * 16) != 0)
|
|
+ return;
|
|
+ snprintf(msg, sizeof(msg), "%08u", addr >> 20);
|
|
+ ccw_load_display(msg);
|
|
+}
|
|
+
|
|
/*
|
|
* Dump all memory to tape
|
|
*/
|
|
@@ -187,9 +212,11 @@ void dt_dump_mem(void)
|
|
ccw_write_block(addr, BLK_SIZE, page);
|
|
total_dump_size += BLK_SIZE;
|
|
progress_print(addr + BLK_SIZE);
|
|
+ progress_print_disp(addr + BLK_SIZE);
|
|
}
|
|
df_s390_em_page_init(page);
|
|
ccw_write_block(page, sizeof(struct df_s390_em), 0);
|
|
free_page(page);
|
|
ccw_write_tapemark();
|
|
+ ccw_load_display("DUMP*END");
|
|
}
|
|
--
|
|
2.54.0
|
|
|
|
|
|
From 724581ae5ccc9623174dd998a00a0797f2d7f993 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:26:23 +0200
|
|
Subject: [PATCH 4/7] Revert "lstape: Remove type filter support"
|
|
|
|
This reverts commit 1bd8ee4b79885bdf2afd389c914c030490319317.
|
|
---
|
|
zconf/lstape | 19 +++++++++++++++++++
|
|
zconf/lstape.8 | 10 ++++++++--
|
|
2 files changed, 27 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/zconf/lstape b/zconf/lstape
|
|
index 943f3256..b37bd9cd 100755
|
|
--- a/zconf/lstape
|
|
+++ b/zconf/lstape
|
|
@@ -28,6 +28,10 @@ function PrintUsage() {
|
|
: Print this help text.
|
|
: --ccw-only|--scsi-only
|
|
: Limit output to CCW or SCSI devices only.
|
|
+ : -t|--type <list of device types>
|
|
+ : Limit output of CCW tape devices to the given
|
|
+ : devices. The list consists of device types
|
|
+ : separated by ','.
|
|
: --online|--offline
|
|
: Show only devices that are either online or
|
|
: offline (only one option is allowed). This
|
|
@@ -59,6 +63,7 @@ function PrintVersion()
|
|
}
|
|
|
|
FLSEP=""
|
|
+DEVLIST="3490"
|
|
SHORTID=false
|
|
SHOWCCW=true
|
|
VERBOSE=false
|
|
@@ -72,6 +77,14 @@ while [ $# -ne 0 ]; do
|
|
PrintUsage
|
|
exit 0
|
|
;;
|
|
+ -t|--type)
|
|
+ if [ $# -lt 2 ]; then
|
|
+ RequireArgument $1 1
|
|
+ exit 1
|
|
+ fi
|
|
+ shift
|
|
+ DEVLIST="$1"
|
|
+ ;;
|
|
--online)
|
|
if $FILTEROFFLINE; then
|
|
echo -n "Option --online and --offline " >&2
|
|
@@ -135,6 +148,10 @@ function SysfsCreateListCCW() {
|
|
medium_state_str[1] = "LOADED "
|
|
medium_state_str[2] = "UNLOADED"
|
|
|
|
+ split("'$DEVLIST'", A, ",")
|
|
+ for(i = 1; i in A; i++) {
|
|
+ devlist[A[i]] = 1
|
|
+ }
|
|
shortid = "'$SHORTID'"=="true" ? 1 : 0
|
|
filteronline = "'$FILTERONLINE'"=="true" ? 1 : 0
|
|
filteroffline = "'$FILTEROFFLINE'"=="true" ? 1 : 0
|
|
@@ -151,6 +168,8 @@ function SysfsCreateListCCW() {
|
|
|
|
devtype = Read(devdir "/devtype")
|
|
split(devtype, A, "/")
|
|
+ if (!(A[1] in devlist))
|
|
+ next
|
|
|
|
online = Read(devdir "/online")
|
|
if (filteronline && !online)
|
|
diff --git a/zconf/lstape.8 b/zconf/lstape.8
|
|
index 6262c64d..019b6e58 100644
|
|
--- a/zconf/lstape.8
|
|
+++ b/zconf/lstape.8
|
|
@@ -64,6 +64,12 @@ of SCSI tape devices.
|
|
Limit output to either online or offline devices. This filter has no effect
|
|
on the output of SCSI devices.
|
|
|
|
+.TP
|
|
+.BR -t | --type " \fI<device-type>\fR"
|
|
+Limit output to given device types, for example 3490
|
|
+(currently only applies to channel-attached
|
|
+tape devices).
|
|
+
|
|
.TP
|
|
.I <device-bus-ID>
|
|
Limits the output to information about the specified tape device or
|
|
@@ -125,9 +131,9 @@ The serial number.
|
|
List all tape devices that are available
|
|
.RE
|
|
|
|
-\fBlstape --ccw-only --online\fR
|
|
+\fBlstape --ccw-only -t 3490 --online\fR
|
|
.RS
|
|
-Show all channel-attached tape devices that are online.
|
|
+Show all 3490 CCW devices that are online.
|
|
.RE
|
|
|
|
\fBlstape --scsi-only --verbose\fR
|
|
--
|
|
2.54.0
|
|
|
|
|
|
From 064e46bf7d7a827086c522d427b3988317f616cc Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:26:41 +0200
|
|
Subject: [PATCH 5/7] Revert "lstape: Remove 3480 and 3590 tape support"
|
|
|
|
This reverts commit 4f0dfae97ea61b0518cb3d61977712f31f1d8206.
|
|
---
|
|
zconf/lstape | 6 ++++--
|
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/zconf/lstape b/zconf/lstape
|
|
index b37bd9cd..9496686b 100755
|
|
--- a/zconf/lstape
|
|
+++ b/zconf/lstape
|
|
@@ -31,7 +31,7 @@ function PrintUsage() {
|
|
: -t|--type <list of device types>
|
|
: Limit output of CCW tape devices to the given
|
|
: devices. The list consists of device types
|
|
- : separated by ','.
|
|
+ : separated by ','. (e.g. -t 3480,3490)
|
|
: --online|--offline
|
|
: Show only devices that are either online or
|
|
: offline (only one option is allowed). This
|
|
@@ -63,7 +63,7 @@ function PrintVersion()
|
|
}
|
|
|
|
FLSEP=""
|
|
-DEVLIST="3490"
|
|
+DEVLIST="3480,3490,3590"
|
|
SHORTID=false
|
|
SHOWCCW=true
|
|
VERBOSE=false
|
|
@@ -142,6 +142,8 @@ function SysfsCreateListCCW() {
|
|
(
|
|
find $1/bus/ccw/drivers/tape_34xx -type l \
|
|
-printf '%f\n' 2>/dev/null
|
|
+ find $1/bus/ccw/drivers/tape_3590 -type l \
|
|
+ -printf '%f\n' 2>/dev/null
|
|
) | awk -v format="$CCWFORMAT" '
|
|
BEGIN{
|
|
medium_state_str[0] = "UNKNOWN "
|
|
--
|
|
2.54.0
|
|
|
|
|
|
From 85b6f905206603c20496b91a8035494d6610ca7c Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:26:59 +0200
|
|
Subject: [PATCH 6/7] Revert "lstape: Remove trailing whitespace"
|
|
|
|
This reverts commit 3d6bb988c24d1723ca4b631e5ff9489d3e419ed7.
|
|
---
|
|
zconf/lstape | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/zconf/lstape b/zconf/lstape
|
|
index 9496686b..e2410e1b 100755
|
|
--- a/zconf/lstape
|
|
+++ b/zconf/lstape
|
|
@@ -220,7 +220,7 @@ function SysfsCreateListCCW() {
|
|
(online==0) ? "N/A" : \
|
|
medium_state_str[medium_state])
|
|
}
|
|
- ' | sort
|
|
+ ' | sort
|
|
}
|
|
|
|
# handle SCSI device not necessarily zfcp-attached, e.g. virtio-scsi-ccw
|
|
--
|
|
2.54.0
|
|
|
|
|
|
From b0e9602ade53403fd6e941e4b1d9ff5f76e9fcaa Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
|
|
Date: Tue, 2 Jun 2026 13:27:23 +0200
|
|
Subject: [PATCH 7/7] Revert "tape390: Remove tape390_display and
|
|
tape390_crypt"
|
|
|
|
This reverts commit 8f83002e379eb84b91f09a303c97d8338adc40e0.
|
|
---
|
|
.gitignore | 2 +
|
|
Makefile | 2 +-
|
|
README.md | 7 +
|
|
tape390/Makefile | 25 ++
|
|
tape390/tape390_common.c | 86 ++++++
|
|
tape390/tape390_common.h | 22 ++
|
|
tape390/tape390_crypt.8 | 108 +++++++
|
|
tape390/tape390_crypt.c | 581 ++++++++++++++++++++++++++++++++++++++
|
|
tape390/tape390_display.8 | 150 ++++++++++
|
|
tape390/tape390_display.c | 287 +++++++++++++++++++
|
|
10 files changed, 1269 insertions(+), 1 deletion(-)
|
|
create mode 100644 tape390/Makefile
|
|
create mode 100644 tape390/tape390_common.c
|
|
create mode 100644 tape390/tape390_common.h
|
|
create mode 100644 tape390/tape390_crypt.8
|
|
create mode 100644 tape390/tape390_crypt.c
|
|
create mode 100644 tape390/tape390_display.8
|
|
create mode 100644 tape390/tape390_display.c
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index 36a2c851..e76abc9a 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -111,6 +111,8 @@ qethqoat/qethqoat
|
|
systemd/cpacfstatsd.service
|
|
systemd/iucvtty-login@.service
|
|
systemd/ttyrun-getty@.service
|
|
+tape390/tape390_crypt
|
|
+tape390/tape390_display
|
|
tunedasd/src/tunedasd
|
|
tunedasd/src/_tunedasd
|
|
tunedasd/src/tunedasd.bash
|
|
diff --git a/Makefile b/Makefile
|
|
index 4dbce8cc..329aebfa 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -11,7 +11,7 @@ BASELIB_DIRS = libutil libseckey
|
|
LIB_DIRS = libvtoc libzds libdasd libccw libvmcp libekmfweb \
|
|
libkmipclient libcpumf libap libpv libzpci
|
|
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
|
- osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
|
+ tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
|
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
|
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
|
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
|
diff --git a/README.md b/README.md
|
|
index 91d61c5a..8298e38c 100644
|
|
--- a/README.md
|
|
+++ b/README.md
|
|
@@ -85,6 +85,13 @@ Package contents
|
|
* qetharp:
|
|
Read and flush the ARP cache on OSA Express network cards.
|
|
|
|
+ * tape390_display:
|
|
+ Display information on the message display facility of a s390 tape
|
|
+ device.
|
|
+
|
|
+ * tape390_crypt:
|
|
+ Control and query crypto settings for 3592 tape devices.
|
|
+
|
|
* osasnmpd:
|
|
NET-SNMP subagent implementing MIBs provided by OSA-Express
|
|
features Fast Ethernet, Gigabit Ethernet, 10 Gigabit Ethernet.
|
|
diff --git a/tape390/Makefile b/tape390/Makefile
|
|
new file mode 100644
|
|
index 00000000..63b5937f
|
|
--- /dev/null
|
|
+++ b/tape390/Makefile
|
|
@@ -0,0 +1,25 @@
|
|
+include ../common.mak
|
|
+
|
|
+ALL_CPPFLAGS += -D_FILE_OFFSET_BITS=64
|
|
+
|
|
+all: tape390_display tape390_crypt
|
|
+
|
|
+tape390_display: tape390_display.o tape390_common.o
|
|
+
|
|
+tape390_crypt: tape390_crypt.o tape390_common.o
|
|
+
|
|
+install: all
|
|
+ $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
|
+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 tape390_display \
|
|
+ $(DESTDIR)$(BINDIR)
|
|
+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 tape390_display.8 \
|
|
+ $(DESTDIR)$(MANDIR)/man8
|
|
+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 tape390_crypt \
|
|
+ $(DESTDIR)$(BINDIR)
|
|
+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 tape390_crypt.8 \
|
|
+ $(DESTDIR)$(MANDIR)/man8
|
|
+
|
|
+clean:
|
|
+ rm -f *.o *~ tape390_display tape390_crypt core
|
|
+
|
|
+.PHONY: all install clean
|
|
diff --git a/tape390/tape390_common.c b/tape390/tape390_common.c
|
|
new file mode 100644
|
|
index 00000000..821e8485
|
|
--- /dev/null
|
|
+++ b/tape390/tape390_common.c
|
|
@@ -0,0 +1,86 @@
|
|
+/*
|
|
+ * tape_390 - Common functions
|
|
+ *
|
|
+ * Copyright IBM Corp. 2006, 2017
|
|
+ *
|
|
+ * s390-tools is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the MIT license. See LICENSE for details.
|
|
+ */
|
|
+
|
|
+#include <fcntl.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/sysmacros.h>
|
|
+
|
|
+#include "tape390_common.h"
|
|
+
|
|
+#define PROC_DEVICES_FILE "/proc/devices"
|
|
+#define PROC_DEVICES_FILE_WIDTH 100
|
|
+
|
|
+char *prog_name; /* Name of tool */
|
|
+
|
|
+/*
|
|
+ * Set name of tool
|
|
+ */
|
|
+void set_prog_name(char *name)
|
|
+{
|
|
+ prog_name = name;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Check whether specified device node is tape device
|
|
+ */
|
|
+int is_not_tape(char *device)
|
|
+{
|
|
+ FILE* fh;
|
|
+ char line[PROC_DEVICES_FILE_WIDTH];
|
|
+ char last_line[PROC_DEVICES_FILE_WIDTH];
|
|
+ int found = 0;
|
|
+ struct stat stat_struct;
|
|
+
|
|
+ if (stat(device, &stat_struct)) {
|
|
+ ERRMSG("%s: Unable to get device status for "
|
|
+ "'%s'. \n", prog_name, device);
|
|
+ perror("");
|
|
+ return 1;
|
|
+ }
|
|
+ fh = fopen(PROC_DEVICES_FILE,"r");
|
|
+ if (!fh) {
|
|
+ ERRMSG("%s: WARNING: Cannot check for tape in file "
|
|
+ PROC_DEVICES_FILE ".\n", prog_name);
|
|
+ perror("");
|
|
+ return(0); /* check not possible, just continue */
|
|
+ }
|
|
+ while (!found && (fscanf(fh, "%s", line) != EOF)) {
|
|
+ if (strcmp(line, "tape") == 0)
|
|
+ found = 1;
|
|
+ else
|
|
+ strcpy(last_line, line);
|
|
+ }
|
|
+ fclose(fh);
|
|
+ if (found && (major(stat_struct.st_rdev) ==
|
|
+ (unsigned int) atoi(last_line)))
|
|
+ return (0);
|
|
+ else {
|
|
+ ERRMSG("%s: '%s' is not a tape device. \n", prog_name, device);
|
|
+ return 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Open the tape device
|
|
+ */
|
|
+int open_tape(char *device)
|
|
+{
|
|
+ int fd;
|
|
+ fd = open(device,O_RDONLY);
|
|
+ if (fd < 0) {
|
|
+ ERRMSG("%s: Cannot open device %s.\n",
|
|
+ prog_name,device);
|
|
+ perror("");
|
|
+ exit(EXIT_MISUSE);
|
|
+ }
|
|
+ return fd;
|
|
+}
|
|
diff --git a/tape390/tape390_common.h b/tape390/tape390_common.h
|
|
new file mode 100644
|
|
index 00000000..d18b88cc
|
|
--- /dev/null
|
|
+++ b/tape390/tape390_common.h
|
|
@@ -0,0 +1,22 @@
|
|
+/*
|
|
+ * tape_390 - Common functions
|
|
+ *
|
|
+ * Copyright IBM Corp. 2006, 2017
|
|
+ *
|
|
+ * s390-tools is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the MIT license. See LICENSE for details.
|
|
+ */
|
|
+
|
|
+#ifndef _TAPE390_COMMON_H
|
|
+#define _TAPE390_COMMON_H
|
|
+
|
|
+#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
|
|
+#define ERRMSG_EXIT(ec,x...) do {fflush(stdout);fprintf(stderr,x);exit(ec);} while(0)
|
|
+#define EXIT_MISUSE 1
|
|
+
|
|
+extern int is_not_tape(char *);
|
|
+extern int open_tape(char *);
|
|
+extern void set_prog_name(char *);
|
|
+extern char *prog_name;
|
|
+
|
|
+#endif
|
|
diff --git a/tape390/tape390_crypt.8 b/tape390/tape390_crypt.8
|
|
new file mode 100644
|
|
index 00000000..b3f0c455
|
|
--- /dev/null
|
|
+++ b/tape390/tape390_crypt.8
|
|
@@ -0,0 +1,108 @@
|
|
+.\" Copyright 2017 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 TAPE390_CRYPT 8 "Apr 2006" "s390-tools"
|
|
+
|
|
+.SH NAME
|
|
+tape390_crypt \- encryption support for zSeries tape devices.
|
|
+
|
|
+.SH SYNOPSIS
|
|
+.B tape390_crypt
|
|
+[OPTION] [DEVICE]
|
|
+
|
|
+.SH DESCRIPTION
|
|
+.B tape390_crypt
|
|
+exploits encryption features available in zSeries tape devices.
|
|
+It can be used to enable or disable tape encryption and to set
|
|
+KEK (Key Encrypting Key) labels.
|
|
+
|
|
+.SH OPTIONS
|
|
+.TP
|
|
+.BR "\-h" " or " "\-\-help"
|
|
+Print help information, then exit.
|
|
+
|
|
+.TP
|
|
+.BR "\-v" " or " "\-\-version"
|
|
+Print version information, then exit.
|
|
+
|
|
+.TP
|
|
+.BR "\-q" " or " "\-\-query"
|
|
+Print current encryption status of the specified tape device and of the
|
|
+loaded medium.
|
|
+If encryption is on and the medium is encrypted ,
|
|
+additional information on the encryption keys is displayed.
|
|
+
|
|
+.TP
|
|
+.BR "\-e " { "on" | "off" } " " or " \-\-encryption=" { "on" | "off" }
|
|
+sets tape encryption on or off.
|
|
+
|
|
+.TP
|
|
+.BR "\-k <value>" [ "<char>label" | "<char>hash" ] " " or " \-\-key=<value>" [ "<char>label" | "<char>hash" ]
|
|
+sets tape encryption keys.
|
|
+.br
|
|
+<value> specifies the KEK
|
|
+(Key Encrypting Key), which can be maximal 64 characters long.
|
|
+.br
|
|
+The store type (either label or hash) specifies how the KEK in <value> is to be stored on the tape medium. Since labels are
|
|
+human readable strings and hence more user friendly than hashes,
|
|
+the default store type is label.
|
|
+.br
|
|
+The \-k option can only be specified, if the tape medium is at load point.
|
|
+.br
|
|
+While processing the \-k option, the tape medium is initialized and all
|
|
+data eventually contained on the tape medium is lost.
|
|
+To avoid inadvertent data loss a prompt message is issued asking the user
|
|
+whether he or she really wants to proceed.
|
|
+.br
|
|
+The \-k option can be specified maximal twice, because on the tape medium
|
|
+maximal two EEDKs (External Encrypted Data Keys) can be stored.
|
|
+If specified once, two identical EEDKs are stored.
|
|
+.br
|
|
+<char> is a character separating the KEK in <value> from the store type
|
|
+(either label or hash). This
|
|
+delimiter can be specified with the \-d option as explained below.
|
|
+
|
|
+.TP
|
|
+.BR "\-d <char>" " or " "\-\-delimiter=<char>
|
|
+specifies the character which separates the KEK
|
|
+in <value> from the store type (either label or hash).
|
|
+The default delimiter is : (colon).
|
|
+The \-d option can only be specified together with the \-k option.
|
|
+
|
|
+.TP
|
|
+.BR "\-f " " or " "\-\-force
|
|
+specifies that no prompt message is to be issued before writing the KEK
|
|
+information and initializing the tape medium.
|
|
+The \-f option can only be specified together with the \-k option.
|
|
+
|
|
+.TP
|
|
+.BR device
|
|
+specifies the device node of the tape device.
|
|
+
|
|
+.SH EXAMPLES
|
|
+1. Scenario:
|
|
+.br
|
|
+mount non-encrypted tape and write data with the
|
|
+.B "default"
|
|
+KEKs:
|
|
+.br
|
|
+tape390_crypt \-e on /dev/ntibm0
|
|
+.br
|
|
+tar cfz /dev/ntibm0 /data
|
|
+
|
|
+2. Scenario:
|
|
+.br
|
|
+mount non-encrypted tape and write data with
|
|
+.B "specific"
|
|
+KEKs:
|
|
+.br
|
|
+tape390_crypt \-k my_first_key \-k my_second_key:hash /dev/ntibm0
|
|
+.br
|
|
+tar cfz /dev/ntibm0 /data
|
|
+
|
|
+3. Scenario:
|
|
+.br
|
|
+mount tape and display current encryption status:
|
|
+.br
|
|
+tape390_crypt \-q /dev/ntibm0
|
|
diff --git a/tape390/tape390_crypt.c b/tape390/tape390_crypt.c
|
|
new file mode 100644
|
|
index 00000000..03bd4522
|
|
--- /dev/null
|
|
+++ b/tape390/tape390_crypt.c
|
|
@@ -0,0 +1,581 @@
|
|
+/*
|
|
+ * tape390_crypt: Provide encryption for tape devices
|
|
+ *
|
|
+ * Copyright 2006, 2017 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.
|
|
+ */
|
|
+
|
|
+#include <ctype.h>
|
|
+#include <errno.h>
|
|
+#include <getopt.h>
|
|
+#include <libgen.h>
|
|
+#include <limits.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/mtio.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include "lib/zt_common.h"
|
|
+#include "tape390_common.h"
|
|
+
|
|
+#define KEKL_LENGTH 65 /* 64 bytes plus trailing \0 */
|
|
+#define TOT_KEKL_LENGTH KEKL_LENGTH+1+5 /* kekl plus colon plus LABEL or HASH */
|
|
+#define ENCRYPTION_ON 1
|
|
+#define ENCRYPTION_OFF 0
|
|
+#define CRYPT_SET_FAILED_MSG "%s: Tape drive does not support encryption.\n"
|
|
+#define CRYPT_QUERY_FAILED_MSG CRYPT_SET_FAILED_MSG
|
|
+#define KEKL_QUERY_FAILED_MSG "%s: Query of encryption keys failed.\n"
|
|
+#define KEKL_SET_FAILED_MSG "%s: Unable to set or modify encryption keys.\n"
|
|
+#define PROC_DEVICES_FILE "/proc/devices"
|
|
+#define PROC_DEVICES_FILE_WIDTH 100
|
|
+#define MAX_BLOCKSIZE 65535 /* max blocksize supported by escon/ficon tapes */
|
|
+
|
|
+#ifndef ENOKEY
|
|
+#define ENOKEY 126
|
|
+#endif
|
|
+#ifndef EKEYREJECTED
|
|
+#define EKEYREJECTED 129
|
|
+#endif
|
|
+
|
|
+#define CHECK_SPEC_MAX(i,j,numstr,str) \
|
|
+ {if (i>j) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
|
|
+ "can only be specified " numstr ".\n",prog_name);}
|
|
+
|
|
+#define PRINT_TYPE(byte) \
|
|
+ {if (byte==TAPE390_KEKL_TYPE_LABEL) printf("label\n");\
|
|
+ else if (byte == TAPE390_KEKL_TYPE_HASH) printf("hash\n");\
|
|
+ else printf("Unsupported type\n");}
|
|
+
|
|
+/*
|
|
+ * Structure tape390_crypt is used to store the command line parameters
|
|
+ */
|
|
+struct tape390_crypt {
|
|
+ int e_switch;
|
|
+ char delimiter;
|
|
+ char devname[PATH_MAX];
|
|
+ char kekl_input[2][TOT_KEKL_LENGTH];
|
|
+ int encryption_specified;
|
|
+ int query_specified;
|
|
+ int key_specified;
|
|
+ int delimiter_specified;
|
|
+ int force_specified;
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+/*
|
|
+ * The following ioctl's belong to linux-2.5/include/asm-s390/tape390.h
|
|
+ *
|
|
+ * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption.
|
|
+ * The "encryption_capable" field is ignored for this ioctl!
|
|
+ */
|
|
+#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info)
|
|
+
|
|
+/*
|
|
+ * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state.
|
|
+ */
|
|
+#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info)
|
|
+
|
|
+struct tape390_crypt_info {
|
|
+ char capability;
|
|
+ char status;
|
|
+ char medium_status;
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+/* Macros for "capable" field */
|
|
+#define TAPE390_CRYPT_SUPPORTED_MASK 0x01
|
|
+#define TAPE390_CRYPT_SUPPORTED(x) \
|
|
+ ((x.capability & TAPE390_CRYPT_SUPPORTED_MASK))
|
|
+
|
|
+/* Macros for "status" field */
|
|
+#define TAPE390_CRYPT_ON_MASK 0x01
|
|
+#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK))
|
|
+
|
|
+/* Macros for "medium status" field */
|
|
+#define TAPE390_MEDIUM_LOADED_MASK 0x01
|
|
+#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02
|
|
+#define TAPE390_MEDIUM_ENCRYPTED(x) \
|
|
+ (((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK))
|
|
+#define TAPE390_MEDIUM_LOADED(x) \
|
|
+ (((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK))
|
|
+
|
|
+/*
|
|
+ * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels.
|
|
+ */
|
|
+#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair)
|
|
+
|
|
+/*
|
|
+ * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels.
|
|
+ */
|
|
+#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair)
|
|
+
|
|
+struct tape390_kekl {
|
|
+ unsigned char type;
|
|
+ unsigned char type_on_tape;
|
|
+ char label[65];
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+struct tape390_kekl_pair {
|
|
+ struct tape390_kekl kekl[2];
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */
|
|
+#define TAPE390_KEKL_TYPE_NONE 0
|
|
+#define TAPE390_KEKL_TYPE_LABEL 1
|
|
+#define TAPE390_KEKL_TYPE_HASH 2
|
|
+
|
|
+/* Full tool name */
|
|
+static const char tool_name[] = "tape390_crpyt: zSeries tape encryption program";
|
|
+
|
|
+/* Copyright notice */
|
|
+static const char copyright_notice[] = "Copyright IBM Corp. 2006, 2017";
|
|
+
|
|
+/*
|
|
+ * Print version information.
|
|
+ */
|
|
+static void print_version (void)
|
|
+{
|
|
+ printf ("%s version %s\n", tool_name, RELEASE_STRING);
|
|
+ printf ("%s\n", copyright_notice);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * prints out the usage text
|
|
+ */
|
|
+static void tape390_crypt_usage (void)
|
|
+{
|
|
+ printf ("Usage: tape390_crypt [OPTIONS] [DEVICE]\n"
|
|
+ "\n"
|
|
+ "Provide encryption for "
|
|
+ "tape devices.\n"
|
|
+ "DEVICE is the node of the tape device (e.g. '/dev/ntibm0')\n"
|
|
+ "\n"
|
|
+ "-h, --help Print this help, then exit\n"
|
|
+ "-v, --version Print version information, "
|
|
+ "then exit\n"
|
|
+ "-q, --query Query information on encryption "
|
|
+ "status and keys\n"
|
|
+ "-k, --key value:type Set encryption key(s)\n"
|
|
+ "-d, --delimiter char Specify character separating "
|
|
+ "key value from key type\n"
|
|
+ "-f, --force Do not prompt user\n"
|
|
+ "-e, --encryption on|off Switch encryption on or off\n");
|
|
+}
|
|
+
|
|
+/*
|
|
+ * initialize the tape390_crypt info structure
|
|
+ */
|
|
+static void init_info(struct tape390_crypt *info)
|
|
+{
|
|
+ info->delimiter = ':';
|
|
+ info->encryption_specified = 0;
|
|
+ info->query_specified = 0;
|
|
+ info->key_specified = 0;
|
|
+ info->delimiter_specified = 0;
|
|
+ info->force_specified = 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * parse the commandline options
|
|
+ */
|
|
+static void tape390_crypt_parse_opts(struct tape390_crypt *info, int argc,
|
|
+ char* argv[])
|
|
+{
|
|
+ int opt, index, kekl_too_long=0, deli_too_long=0, e_switch_invalid=0;
|
|
+ int i;
|
|
+ static struct option crypt_long_options[] = {
|
|
+ { "version", no_argument, NULL, 'v'},
|
|
+ { "encryption", required_argument, NULL, 'e'},
|
|
+ { "query", no_argument, NULL, 'q'},
|
|
+ { "key", required_argument, NULL, 'k'},
|
|
+ { "help", no_argument, NULL, 'h'},
|
|
+ { "delimiter", required_argument, NULL, 'd'},
|
|
+ { "force", no_argument, NULL, 'f'},
|
|
+ { NULL, 0, NULL, 0 }
|
|
+ };
|
|
+ /* Command line option abbreviations */
|
|
+ static const char crypt_option_string[] = "ve:qk:hd:f";
|
|
+
|
|
+ while (1) {
|
|
+ opt = getopt_long(argc, argv, crypt_option_string,
|
|
+ crypt_long_options, &index);
|
|
+ if (opt == -1)
|
|
+ break;
|
|
+ switch (opt) {
|
|
+ case 'v':
|
|
+ print_version();
|
|
+ exit(0);
|
|
+ case 'h':
|
|
+ tape390_crypt_usage();
|
|
+ exit(0);
|
|
+ case 'q':
|
|
+ ++info->query_specified;
|
|
+ break;
|
|
+ case 'k':
|
|
+ ++info->key_specified;
|
|
+ if(strlen(optarg) >= TOT_KEKL_LENGTH)
|
|
+ kekl_too_long = 1;
|
|
+ else if (info->key_specified == 1)
|
|
+ for (i = 0; i < 2; i++)
|
|
+ strcpy(info->kekl_input[i], optarg);
|
|
+ else
|
|
+ strcpy(info->kekl_input[1], optarg);
|
|
+ break;
|
|
+ case 'e':
|
|
+ ++info->encryption_specified;
|
|
+ if (strcmp(optarg,"off") == 0)
|
|
+ info->e_switch = ENCRYPTION_OFF;
|
|
+ else if (strcmp(optarg,"on") == 0)
|
|
+ info->e_switch = ENCRYPTION_ON;
|
|
+ else
|
|
+ e_switch_invalid = 1;
|
|
+ break;
|
|
+ case 'd':
|
|
+ ++info->delimiter_specified;
|
|
+ if(strlen(optarg) > 1)
|
|
+ deli_too_long = 1;
|
|
+ else
|
|
+ info->delimiter = optarg[0];
|
|
+ break;
|
|
+ case 'f':
|
|
+ ++info->force_specified;
|
|
+ break;
|
|
+ default:
|
|
+ fprintf(stderr, "Try '%s --help' for more"
|
|
+ " information.\n",prog_name);
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+ CHECK_SPEC_MAX(info->query_specified, 1, "once", "query");
|
|
+ CHECK_SPEC_MAX(info->encryption_specified, 1, "once", "encryption");
|
|
+ CHECK_SPEC_MAX(info->delimiter_specified, 1, "once", "delimiter");
|
|
+ CHECK_SPEC_MAX(info->force_specified, 1, "once", "force");
|
|
+ CHECK_SPEC_MAX(info->key_specified,2, "twice", "key");
|
|
+ if (kekl_too_long)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: Specified key too long.\n",prog_name);
|
|
+ if (deli_too_long)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: Delimiter must be one character.\n",prog_name);
|
|
+ if (e_switch_invalid)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: ERROR: encryption can be set 'on' or 'off'.\n",
|
|
+ prog_name);
|
|
+ if (((info->query_specified) &&
|
|
+ (info->key_specified + info->encryption_specified > 0)) ||
|
|
+ ((info->encryption_specified) &&
|
|
+ (info->key_specified + info->query_specified > 0)) ||
|
|
+ ((info->force_specified) &&
|
|
+ (info->encryption_specified)) ||
|
|
+ ((info->delimiter_specified) &&
|
|
+ (info->encryption_specified + info->query_specified > 0)))
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: Conflicting options specified.\n",prog_name);
|
|
+ if (info->query_specified + info->encryption_specified +
|
|
+ info->key_specified == 0)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: ERROR: Missing options.\n",prog_name);
|
|
+ /* save device */
|
|
+ if (optind >= argc)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: No device specified.\n",prog_name);
|
|
+ if (optind + 1 < argc)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: More than one device specified.\n",prog_name);
|
|
+ strcpy(info->devname, argv[optind]);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * check and parse key operand, must be value:type
|
|
+ * where value is an arbitrary string, maximal 64 char long
|
|
+ * : is a 1-char delimiter specified with the -d option (default :)
|
|
+ * type is the type identifier, which can be either 'hash' or 'label'
|
|
+ * default is 'label'
|
|
+ */
|
|
+static void fill_kekl(char *s, char delimiter,
|
|
+ struct tape390_kekl *mykekl)
|
|
+{
|
|
+ int i;
|
|
+ char typestring[TOT_KEKL_LENGTH] = {0};
|
|
+ for (i = strlen(s); i >= 0; i--)
|
|
+ if (*(s+i) == delimiter)
|
|
+ break;
|
|
+ if (i == -1) /* delimiter not found, no type specified */
|
|
+ mykekl->type_on_tape = TAPE390_KEKL_TYPE_LABEL; /* default type*/
|
|
+ else if (i == 0)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: ERROR: delimiter '%c' found as first "
|
|
+ "character.\n",prog_name,delimiter);
|
|
+ else if (i == (int) strlen(s) - 1)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: ERROR: Delimiter '%c' found as last "
|
|
+ "character.\n",prog_name,delimiter);
|
|
+ else {
|
|
+ strcpy(typestring,s+i+1);
|
|
+ *(s+i) = '\0';
|
|
+ if (strcmp(typestring,"hash") == 0)
|
|
+ mykekl->type_on_tape = TAPE390_KEKL_TYPE_HASH;
|
|
+ else if (strcmp(typestring,"label") == 0)
|
|
+ mykekl->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
|
|
+ else
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: Invalid key type '%s',"
|
|
+ " must be either 'label' or 'hash'.\n",
|
|
+ prog_name,typestring);
|
|
+ }
|
|
+ if (strlen(s) >= KEKL_LENGTH)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,
|
|
+ "%s: Specified key value too long, has %d chars.\n",
|
|
+ prog_name,(int)strlen(s));
|
|
+ else {
|
|
+ strcpy(mykekl->label, s);
|
|
+ mykekl->type = TAPE390_KEKL_TYPE_LABEL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Write two tapemarks on tape to initialize tape after kekl set
|
|
+ */
|
|
+
|
|
+static int init_tape(int fd)
|
|
+{
|
|
+ struct mtop mtop;
|
|
+ int rc;
|
|
+
|
|
+ mtop.mt_op = MTWEOF;
|
|
+ mtop.mt_count = 2;
|
|
+ rc = ioctl(fd, MTIOCTOP, &mtop);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ mtop.mt_op = MTREW;
|
|
+ return ioctl(fd, MTIOCTOP, &mtop);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Tell the current block on tape
|
|
+ */
|
|
+
|
|
+static int tell_tape(int fd)
|
|
+{
|
|
+ struct mtop mtop;
|
|
+
|
|
+ mtop.mt_op = MTTELL;
|
|
+ mtop.mt_count = 1;
|
|
+ return ioctl(fd, MTIOCTOP, &mtop);
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * Do read IO to tape in order to enforce update of KEKL information.
|
|
+ * Leave tape position unchanged.
|
|
+ */
|
|
+
|
|
+static int read_tape(int fd)
|
|
+{
|
|
+ struct mtop mtop;
|
|
+ int block_number, n_read;
|
|
+ char buffer[MAX_BLOCKSIZE];
|
|
+
|
|
+ /* remember current block on tape */
|
|
+ block_number = tell_tape(fd);
|
|
+ n_read = read(fd, buffer, sizeof(buffer));
|
|
+ if (n_read == -1) {
|
|
+ /* tape read failed, ignore if caused by end-of-volume */
|
|
+ if (errno == ENOSPC)
|
|
+ return 0;
|
|
+ else
|
|
+ return 1;
|
|
+ }
|
|
+ if (block_number != tell_tape(fd)) {
|
|
+ /* re-position tape */
|
|
+ mtop.mt_op = MTSEEK;
|
|
+ mtop.mt_count = block_number;
|
|
+ if (ioctl(fd, MTIOCTOP, &mtop) != 0)
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * set Key Encrypting Key labels
|
|
+ */
|
|
+static int set_encryption_keys(int fd, struct tape390_crypt *info)
|
|
+{
|
|
+ struct tape390_kekl_pair kekls;
|
|
+ char delim;
|
|
+ char *s, inp_buffer[5];
|
|
+ int i, rc;
|
|
+
|
|
+ delim = info->delimiter;
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ s = info->kekl_input[i];
|
|
+ fill_kekl(s, delim, &kekls.kekl[i]);
|
|
+ }
|
|
+ if (info->force_specified == 0) {
|
|
+ printf("--->> ATTENTION! <<---\n");
|
|
+ printf("All data on tape %s will be lost.\nType "
|
|
+ "\"yes\" to continue: ", info->devname);
|
|
+ if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL) {
|
|
+ fprintf(stderr, "Reading from terminal failed.\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ if (strcasecmp(inp_buffer,"yes\n")) {
|
|
+ printf("Tape and its encryption keys "
|
|
+ "remain unchanged.\n");
|
|
+ exit(0);
|
|
+ }
|
|
+ }
|
|
+ rc = ioctl(fd, TAPE390_KEKL_SET, &kekls);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ return init_tape(fd);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Switch on/off encryption
|
|
+ */
|
|
+static int switch_encryption_on_or_off(int fd,struct tape390_crypt *info)
|
|
+{
|
|
+ struct tape390_crypt_info myinfo;
|
|
+
|
|
+ memset(&myinfo, 0, sizeof(myinfo));
|
|
+ if (info->e_switch == ENCRYPTION_ON)
|
|
+ myinfo.status |= TAPE390_CRYPT_ON_MASK;
|
|
+ return ioctl(fd, TAPE390_CRYPT_SET, &myinfo);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Query information on encryption and keys
|
|
+ */
|
|
+static int query_encryption(int fd,struct tape390_crypt *info)
|
|
+{
|
|
+ struct tape390_crypt_info myinfo;
|
|
+ struct tape390_kekl_pair kekls;
|
|
+ int i, ret;
|
|
+
|
|
+ ret = ioctl(fd, TAPE390_CRYPT_QUERY, &myinfo);
|
|
+ if (ret)
|
|
+ return -1;
|
|
+ if (!TAPE390_MEDIUM_LOADED(myinfo)) {
|
|
+ printf("Medium not loaded\n");
|
|
+ return 0;
|
|
+ }
|
|
+ printf("ENCRYPTION: ");
|
|
+ if (TAPE390_CRYPT_ON(myinfo))
|
|
+ printf("ON\n");
|
|
+ else
|
|
+ printf("OFF\n");
|
|
+ printf("MEDIUM: ");
|
|
+ if (TAPE390_MEDIUM_ENCRYPTED(myinfo))
|
|
+ printf("ENCRYPTED\n");
|
|
+ else {
|
|
+ printf("NOT ENCRYPTED\n");
|
|
+ return 0;
|
|
+ }
|
|
+ /*
|
|
+ * do a dummy read in order to force the control unit to get
|
|
+ * the key information from the EKM
|
|
+ */
|
|
+ ret = read_tape(fd);
|
|
+ if (ret && (info->force_specified == 0))
|
|
+ return -2;
|
|
+ ret = ioctl(fd, TAPE390_KEKL_QUERY, &kekls);
|
|
+ if (ret)
|
|
+ return -2;
|
|
+ printf("KEKLs on TAPE:\n");
|
|
+ if (kekls.kekl[0].type == TAPE390_KEKL_TYPE_NONE) {
|
|
+ ERRMSG("Unable to retrieve key information.\n");
|
|
+ return 0;
|
|
+ }
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ printf(" KEY%i:\n",i+1);
|
|
+ if (kekls.kekl[i].type == TAPE390_KEKL_TYPE_NONE)
|
|
+ printf("None\n");
|
|
+ else {
|
|
+ printf(" value: %s\n",kekls.kekl[i].label);
|
|
+ printf(" type: ");
|
|
+ PRINT_TYPE(kekls.kekl[i].type);
|
|
+ printf(" ontape: ");
|
|
+ PRINT_TYPE(kekls.kekl[i].type_on_tape);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ struct tape390_crypt info;
|
|
+ char error_msg[80];
|
|
+ int rc=0, fd=-1;
|
|
+
|
|
+ /* set name of program */
|
|
+ set_prog_name(basename(argv[0]));
|
|
+
|
|
+ /* set default values */
|
|
+ init_info(&info);
|
|
+
|
|
+ /* parse command line options and check syntax */
|
|
+ tape390_crypt_parse_opts(&info, argc, argv);
|
|
+
|
|
+ /* check whether specified device node is tape */
|
|
+ if (is_not_tape(info.devname))
|
|
+ exit(EXIT_MISUSE);
|
|
+
|
|
+ /* open device */
|
|
+ fd = open_tape(info.devname);
|
|
+
|
|
+ /* process -k or -e or -q operand */
|
|
+ if (info.key_specified >= 1) {
|
|
+ rc = set_encryption_keys(fd, &info);
|
|
+ if (rc == 0)
|
|
+ printf("SUCCESS: key information set.\n");
|
|
+ strcpy(error_msg, KEKL_SET_FAILED_MSG);
|
|
+ } else if (info.encryption_specified) {
|
|
+ rc = switch_encryption_on_or_off(fd, &info);
|
|
+ strcpy(error_msg, CRYPT_SET_FAILED_MSG);
|
|
+ } else if (info.query_specified) {
|
|
+ rc = query_encryption(fd, &info);
|
|
+ if (rc == -1)
|
|
+ strcpy(error_msg, CRYPT_QUERY_FAILED_MSG);
|
|
+ else if (rc == -2)
|
|
+ strcpy(error_msg, KEKL_QUERY_FAILED_MSG);
|
|
+ }
|
|
+ if (rc) {
|
|
+ ERRMSG(error_msg, prog_name);
|
|
+ switch (errno) {
|
|
+ case ENOKEY:
|
|
+ ERRMSG("EKM error.\n");
|
|
+ break;
|
|
+ case ENOTCONN:
|
|
+ ERRMSG("Could not connect to EKM.\n");
|
|
+ break;
|
|
+ case EKEYREJECTED:
|
|
+ ERRMSG("Key not available on EKM.\n");
|
|
+ break;
|
|
+ case EUNATCH:
|
|
+ ERRMSG("Encryption must be set ON prior to "
|
|
+ "setting or querying encryption "
|
|
+ "keys.\n");
|
|
+ break;
|
|
+ case EBADSLT:
|
|
+ ERRMSG("Tape must be at load point in order "
|
|
+ "to set encryption keys.\n");
|
|
+ break;
|
|
+ case ENOSYS:
|
|
+ ERRMSG("Tape device does not support "
|
|
+ "encryption.\n");
|
|
+ break;
|
|
+ case EINVAL:
|
|
+ ERRMSG("Kernel does not support tape "
|
|
+ "encryption.\n");
|
|
+ break;
|
|
+ default:
|
|
+ perror("");
|
|
+ }
|
|
+ }
|
|
+ if (fd != -1)
|
|
+ close(fd);
|
|
+ return(rc);
|
|
+}
|
|
diff --git a/tape390/tape390_display.8 b/tape390/tape390_display.8
|
|
new file mode 100644
|
|
index 00000000..0c51c5a0
|
|
--- /dev/null
|
|
+++ b/tape390/tape390_display.8
|
|
@@ -0,0 +1,150 @@
|
|
+.\" Copyright 2017 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 TAPE390_DISPLAY 8 "Apr 2006" "s390-tools"
|
|
+
|
|
+.SH NAME
|
|
+tape390_display \- display messages on the display unit of a zSeries tape
|
|
+device.
|
|
+
|
|
+.SH SYNOPSIS
|
|
+.TP 16
|
|
+.B tape390_display
|
|
+.RB [ \-b | \-\-blink ]
|
|
+.br
|
|
+.RB [ \-h | \-\-help ]
|
|
+.br
|
|
+.RB [ \-l | \-\-load ]
|
|
+.br
|
|
+.RB [ \-t <type>| \-\-type <type>]
|
|
+.br
|
|
+.RB [ \-q | \-\-quiet ]
|
|
+.br
|
|
+.RB [ \-v | \-\-version ]
|
|
+.br
|
|
+.IR message1
|
|
+.RB [
|
|
+.I message2
|
|
+.RB ]
|
|
+.I device
|
|
+
|
|
+.SH DESCRIPTION
|
|
+\fBtape390_display\fR displays one or two 8-byte messages on the display
|
|
+unit of a zSeries tape device. Characters to be displayed include capital
|
|
+letters A-Z, numerics 0-9 and special characters.
|
|
+However some special characters may not display on all device types. The
|
|
+characters that should display on model 3490 are:
|
|
+.br
|
|
+ '@$#,./()*&+-=%|:_<>?;' and the <cent> character.
|
|
+.br
|
|
+Spaces and shell-sensitive characters have to be quoted.
|
|
+
|
|
+.SH OPTIONS
|
|
+.TP 8
|
|
+\fB\-h\fR or \fB\-\-help\fR
|
|
+Print help text.
|
|
+
|
|
+.TP
|
|
+\fB\-b\fR or \fB\-\-blink\fR
|
|
+Display \fImessage1\fR repeatedly for 2 seconds at half-second intervals.
|
|
+This option is ignored if two messages are specified on command line.
|
|
+
|
|
+.TP
|
|
+\fB\-l\fR or \fB\-\-load\fR
|
|
+If this option is given the display request will cause a load request to be
|
|
+sent to the automatic tape loader (if installed). The next indexed tape will
|
|
+then be loaded if the loader is in 'system' mode. Otherwise the request is
|
|
+ignored.
|
|
+
|
|
+.TP
|
|
+\fB\-q\fR or \fB\-\-quiet\fR
|
|
+This option causes the command to run in quiet mode which will suppress
|
|
+all warning messages.
|
|
+
|
|
+.TP
|
|
+\fB\-t\fR \fItype\fR or \fB\-\-type\fR \fItype\fR
|
|
+Set the type of the message to be displayed. This influences how long
|
|
+the message(s) stay on the display. Available types are:
|
|
+
|
|
+.RS
|
|
+.TP 16
|
|
+.B standard
|
|
+The message(s) stay displayed until the drive executes the next tape
|
|
+movement command. This is the default.
|
|
+.TP
|
|
+.B load
|
|
+Displays the message(s) until a tape is loaded. If there already is
|
|
+a tape loaded to the device, nothing is displayed at all.
|
|
+.TP
|
|
+.B unload
|
|
+This will display the message(s) until currently loaded tape is unloaded.
|
|
+Again, if the drive \fIis\fR currently unloaded there is no output at all.
|
|
+.TP
|
|
+.B noop
|
|
+For testing purposes only, this will access the drive but won't do anything
|
|
+at all (no operation). This doesn't seem to work with 3590 tape devices.
|
|
+.TP
|
|
+.B reload
|
|
+This display type \fBrequires\fR two messages. The first message is
|
|
+displayed as long as there is a tape loaded up to the time the unload
|
|
+operation is completed (or, if there isn't a tape loaded, it will be
|
|
+ignored). The second message is displayed as soon as a tape gets loaded
|
|
+into the drive.
|
|
+.RE
|
|
+
|
|
+.TP
|
|
+\fB\-v\fR or \fB\-\-version\fR
|
|
+Print the S/390 tools package version, the utility version and exit.
|
|
+
|
|
+.TP 8
|
|
+\fBmessage1\fR [ \fBmessage2\fR ]
|
|
+The message(s) to be displayed. They stay displayed until either the
|
|
+ending condition for the message type takes place or the display is
|
|
+updated with another message.
|
|
+.br
|
|
+If two messages are specified, they are alternated on the display.
|
|
+Each message is then displayed repeatedly for 2 seconds
|
|
+at half-second intervals.
|
|
+
|
|
+.TP
|
|
+\fBdevice\fR
|
|
+The tape device on which the message(s) will be displayed, e.g.:
|
|
+.sp
|
|
+ \fB/dev/ntibm\fR\fI0\fR
|
|
+.br
|
|
+
|
|
+.SH EXAMPLES
|
|
+\fBtape390_display \-\-blink \-\-type unload "TESTING" /dev/ntibm\fR\fI0\fR
|
|
+.RS
|
|
+Let the message TESTING blink on the display of the tape unit until the
|
|
+tape is removed (or another message is given). If there is no tape in the
|
|
+drive, nothing happens.
|
|
+.RE
|
|
+\fBtape390_display "BACKUP" "COMPLETE" /dev/ntibm\fR\fI0\fR
|
|
+.RS
|
|
+This will display the messages BACKUP and COMPLETE each for 2 seconds
|
|
+until the tape is moved, ejected or (if there isn't a tape in the
|
|
+device) inserted.
|
|
+.RE
|
|
+\fBtape390_display \-\-type reload "UNLOAD" "LOAD" /dev/ntibm\fR\fI0\fR
|
|
+.RS
|
|
+The UNLOAD message will be displayed if there is a tape inserted and as
|
|
+long as the tape isn't removed. After that the LOAD message is displayed
|
|
+until a tape is inserted. If there is no tape inserted when the command
|
|
+.RE
|
|
+\fBtape390_display \-\-load \-\-type load "LOADING" /dev/ntibm\fR\fI0\fR
|
|
+.RS
|
|
+Causes the device to display the message LOADING until a tape is inserted
|
|
+and to instruct the automatic stacker to load the next tape (if the mode
|
|
+of operation is \fIsystem\fR). If there already is a tape loaded, nothing
|
|
+will happen at all.
|
|
+.RE
|
|
+
|
|
+.SH AUTHOR
|
|
+.nf
|
|
+This man-page was written by Despina Papadopoulou<despina_p@de.ibm.com>
|
|
+.nf
|
|
+Updates by Stefan Bader<shbader@de.ibm.com>
|
|
+.fi
|
|
+
|
|
diff --git a/tape390/tape390_display.c b/tape390/tape390_display.c
|
|
new file mode 100644
|
|
index 00000000..a77b6dba
|
|
--- /dev/null
|
|
+++ b/tape390/tape390_display.c
|
|
@@ -0,0 +1,287 @@
|
|
+/*
|
|
+ * tape390_display - Display messages on the display unit of a tape drive
|
|
+ *
|
|
+ * Copyright IBM Corp. 2002, 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 <ctype.h>
|
|
+#include <getopt.h>
|
|
+#include <libgen.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include "lib/zt_common.h"
|
|
+#include "tape390_common.h"
|
|
+
|
|
+#define TAPE390_DISPLAY _IOW('d', 1, struct display_struct)
|
|
+
|
|
+/*
|
|
+ * The TAPE390_DISPLAY belongs to linux-2.5/include/asm-s390/tape390.h
|
|
+ *
|
|
+ * The TAPE390_DISPLAY ioctl calls the Load Display command
|
|
+ * which transfers 17 bytes of data from the channel to the subsystem:
|
|
+ * - 1 format control byte, and
|
|
+ * - two 8-byte messages
|
|
+ *
|
|
+ * Format control byte:
|
|
+ * 0-2: New Message Overlay
|
|
+ * 3: Alternate Messages
|
|
+ * 4: Blink Message
|
|
+ * 5: Display Low/High Message
|
|
+ * 6: Reserved
|
|
+ * 7: Automatic Load Request
|
|
+ *
|
|
+ */
|
|
+#define TAPE_MSGTYPE_STANDARD 0
|
|
+#define TAPE_MSGTYPE_UNLOAD 1
|
|
+#define TAPE_MSGTYPE_LOAD 2
|
|
+#define TAPE_MSGTYPE_NOOP 3
|
|
+#define TAPE_MSGTYPE_UNLOAD_LOAD 7
|
|
+
|
|
+typedef struct display_struct {
|
|
+ struct {
|
|
+ unsigned char type :3;
|
|
+ unsigned char alternate :1;
|
|
+ unsigned char blink :1;
|
|
+ unsigned char use_second :1;
|
|
+ unsigned char reserved :1;
|
|
+ unsigned char load_request :1;
|
|
+ } cntrl;
|
|
+ char message1[8];
|
|
+ char message2[8];
|
|
+} __attribute__ ((packed)) display_struct;
|
|
+
|
|
+/* definitions */
|
|
+static char *help_text =
|
|
+ "tape390_display: display one or two 8-byte messages on the display"
|
|
+ "unit of a tape drive\n"
|
|
+ "\n"
|
|
+ "Usage: tape390_display <options> \"<message1>\" [\"<message2>\"] "
|
|
+ "<device>"
|
|
+ "\n\n"
|
|
+ "where <options> are:\n"
|
|
+ "\t-b | --blink\n"
|
|
+ "\t\twill cause a single message to blink every 2 seconds\n"
|
|
+ "\t\t(this option has only effect with a single message)\n"
|
|
+ "\t-h | --help\n"
|
|
+ "\t\tprint this text\n"
|
|
+ "\t-v | --version\n"
|
|
+ "\t\toutput version information and exit\n"
|
|
+ "\t-l | --load\n"
|
|
+ "\t\twill try to load the next tape if the loader is in system mode\n"
|
|
+ "\t-q | --quiet\n"
|
|
+ "\t\twill suppress all warning messages\n"
|
|
+ "\t-t | --type \"standard|load|unload|noop|reload\"\n"
|
|
+ "\t\tcontrols how the message is displayed:\n"
|
|
+ "\t\t\tstandard = until the next tape movement (default)\n"
|
|
+ "\t\t\tload = until a tape is loaded\n"
|
|
+ "\t\t\tunload = until a tape is unloaded\n"
|
|
+ "\t\t\tnoop = not at all (test purposes)\n"
|
|
+ "\t\t\treload = message1 until tape is unloaded and message2\n"
|
|
+ "\t\t\t when the next tape is loaded\n"
|
|
+ "\n"
|
|
+ "Note: Characters to be displayed include capital letters (A-Z), "
|
|
+ "numerics (0-9)\n"
|
|
+ "and special characters within single quotes. However not all "
|
|
+ "characters\n"
|
|
+ "might be displayed on all tape devices. Special characters that "
|
|
+ "are supported\n"
|
|
+ "for 3490 are '@$#,./()*&+-=%|:_<>?;'.\n";
|
|
+
|
|
+static int quiet;
|
|
+
|
|
+/* end of definitions */
|
|
+
|
|
+static int typename2int(char *name)
|
|
+{
|
|
+ char *typenames[] = {
|
|
+ "standard",
|
|
+ "unload",
|
|
+ "load",
|
|
+ "noop",
|
|
+ NULL,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ "reload"
|
|
+ };
|
|
+ int i;
|
|
+
|
|
+ for(i = 0; i < 8; i++) {
|
|
+ if(typenames[i] == NULL)
|
|
+ continue;
|
|
+ if(strcmp(typenames[i], name) == 0) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "Invalid message type <%s>\n", name);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void strchkcpy(char *tgt, const char *src)
|
|
+{
|
|
+ static char *nowarn = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
+ "@$#,./'()*&+-=%:_<>?; ";
|
|
+ char c;
|
|
+ char warned;
|
|
+
|
|
+ warned = 0;
|
|
+ for(c=0; c<8 && *(src+c); c++) {
|
|
+ *(tgt+c) = toupper(*(src+c));
|
|
+ if (index(nowarn, *(tgt+c)) == NULL && !quiet && !warned) {
|
|
+ fprintf(
|
|
+ stderr,
|
|
+ "WARNING: Some special characters may not "
|
|
+ "display on all device types.\n"
|
|
+ );
|
|
+ warned = 1;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[]) {
|
|
+
|
|
+ char *options = "hblqt:v";
|
|
+ struct option long_options[] = {
|
|
+ { "help", no_argument, NULL, 'h' },
|
|
+ { "blink", no_argument, NULL, 'b' },
|
|
+ { "load", no_argument, NULL, 'l' },
|
|
+ { "quiet", no_argument, NULL, 'q' },
|
|
+ { "type", required_argument, NULL, 't' },
|
|
+ { "version", no_argument, NULL, 'v' },
|
|
+ { NULL, 0, NULL, 0 }
|
|
+ };
|
|
+ char *pathname;
|
|
+ int c;
|
|
+ int fd, ret = 0;
|
|
+ struct display_struct ds;
|
|
+
|
|
+ /* set name of program */
|
|
+ set_prog_name(basename(argv[0]));
|
|
+
|
|
+ memset(&ds, 0, sizeof(ds));
|
|
+ ds.cntrl.type = TAPE_MSGTYPE_STANDARD;
|
|
+
|
|
+ while(
|
|
+ (c = getopt_long(argc, argv, options, long_options, NULL))
|
|
+ != EOF
|
|
+ ) {
|
|
+ switch(c) {
|
|
+ case 'h':
|
|
+ fprintf(stdout, "%s", help_text);
|
|
+ exit(0);
|
|
+ case 'b':
|
|
+ ds.cntrl.blink = 1;
|
|
+ break;
|
|
+ case 'l':
|
|
+ ds.cntrl.load_request = 1;
|
|
+ break;
|
|
+ case 'q':
|
|
+ quiet = 1;
|
|
+ break;
|
|
+ case 't': {
|
|
+ int type = typename2int(optarg);
|
|
+
|
|
+ if(type < 0)
|
|
+ exit(1);
|
|
+
|
|
+ ds.cntrl.type = type;
|
|
+ break;
|
|
+ }
|
|
+ case 'v': {
|
|
+ printf("tape390_display: zSeries tape "
|
|
+ "display control program version %s\n",
|
|
+ RELEASE_STRING);
|
|
+ printf("Copyright IBM Corp. 2002, 2017\n");
|
|
+ exit(0);
|
|
+ }
|
|
+ default:
|
|
+ fprintf(stderr, "Try '%s --help' for more"
|
|
+ " information.\n",prog_name);
|
|
+ exit(1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(optind + 2 < argc ) {
|
|
+ if(
|
|
+ ds.cntrl.type == TAPE_MSGTYPE_LOAD &&
|
|
+ ds.cntrl.load_request
|
|
+ ) {
|
|
+ if(!quiet) {
|
|
+ fprintf(
|
|
+ stderr,
|
|
+ "WARNING: "
|
|
+ "A <load> message with the "
|
|
+ "--load option will only "
|
|
+ "display the first"
|
|
+ "\nmessage.\n"
|
|
+ );
|
|
+ }
|
|
+ } else if(
|
|
+ ds.cntrl.type == TAPE_MSGTYPE_UNLOAD_LOAD &&
|
|
+ ds.cntrl.load_request
|
|
+ ) {
|
|
+ if(!quiet) {
|
|
+ fprintf(
|
|
+ stderr,
|
|
+ "WARNING: "
|
|
+ "A <reload> message with the "
|
|
+ "--load option will only "
|
|
+ "display the second"
|
|
+ "\nmessage.\n"
|
|
+ );
|
|
+ }
|
|
+ } else {
|
|
+ ds.cntrl.alternate = 1;
|
|
+
|
|
+ if(ds.cntrl.blink) {
|
|
+ ds.cntrl.blink = 0;
|
|
+ if(!quiet) {
|
|
+ fprintf(
|
|
+ stderr,
|
|
+ "Alternate messages "
|
|
+ "override blinking\n"
|
|
+ );
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ strchkcpy(ds.message1, argv[optind]);
|
|
+ strchkcpy(ds.message2, argv[optind+1]);
|
|
+ pathname = argv[optind+2];
|
|
+ } else if(optind + 1 < argc) {
|
|
+ if(ds.cntrl.type == TAPE_MSGTYPE_UNLOAD_LOAD) {
|
|
+ fprintf(stderr, "Reload message type requires "
|
|
+ "two messages.\n");
|
|
+ exit(1);
|
|
+ } else if(ds.cntrl.type == TAPE_MSGTYPE_LOAD) {
|
|
+ strchkcpy(ds.message2, argv[optind]);
|
|
+ }
|
|
+ strchkcpy(ds.message1, argv[optind]);
|
|
+ pathname = argv[optind+1];
|
|
+ } else {
|
|
+ fprintf(stderr, "%s", help_text);
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ /* check whether specified device node is tape */
|
|
+ if (is_not_tape(pathname))
|
|
+ exit(EXIT_MISUSE);
|
|
+
|
|
+ /* open device */
|
|
+ fd = open_tape(pathname);
|
|
+
|
|
+ ret = ioctl(fd, TAPE390_DISPLAY, &ds);
|
|
+ if (ret != 0)
|
|
+ fprintf(stderr, "TAPE390_DISPLAY failed\n");
|
|
+
|
|
+ close(fd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
--
|
|
2.54.0
|
|
|