commit 9b729e2accfa940ac5ba1398415c17621c9edd9f398bae00e1d76c85c326edbb Author: Marcus Meissner Date: Tue Feb 21 11:14:26 2017 +0000 Accepting request 459343 from openSUSE:Factory:zSystems New package per "Factory first" policy. Please list me as bug owner and maintainer, if possible. OBS-URL: https://build.opensuse.org/request/show/459343 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/59-dasd.rules-wait_for.patch b/59-dasd.rules-wait_for.patch new file mode 100644 index 0000000..03d86e9 --- /dev/null +++ b/59-dasd.rules-wait_for.patch @@ -0,0 +1,14 @@ +--- s390-tools-1.34.0/etc/udev/rules.d/59-dasd.rules 2016-04-22 13:37:54.000000000 -0400 ++++ s390-tools-1.34.0/etc/udev/rules.d/59-dasd.rules 2016-04-22 13:38:15.000000000 -0400 +@@ -33,11 +33,3 @@ + ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_SAFE}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_SAFE}" + + LABEL="dasd_symlinks_end" +- +-# on device add set request queue scheduler to deadline +-SUBSYSTEM!="block", GOTO="sched_end" +- +-ACTION!="add", GOTO="sched_end" +-KERNEL=="dasd*[!0-9]", WAIT_FOR="queue/scheduler", ATTR{queue/scheduler}="deadline" +- +-LABEL="sched_end" diff --git a/59-graf.rules b/59-graf.rules new file mode 100644 index 0000000..c1e1fc7 --- /dev/null +++ b/59-graf.rules @@ -0,0 +1,13 @@ +# +# Rules for unique 3270 device nodes created in /dev/3270/ +# This file should be installed in /usr/lib/udev/rules.d +# + +SUBSYSTEM!="ccw", GOTO="graf_end" +DRIVER!="3270", GOTO="graf_end" + +# Configure 3270 device +ACTION=="add", SUBSYSTEM=="ccw", PROGRAM="/sbin/chccwdev -e $kernel" +ACTION=="remove", SUBSYSTEM=="ccw", PROGRAM="/sbin/chccwdev -d $kernel" + +LABEL="graf_end" diff --git a/59-prng.rules b/59-prng.rules new file mode 100644 index 0000000..2248d55 --- /dev/null +++ b/59-prng.rules @@ -0,0 +1,5 @@ +# +# Rule for prandom character device node permissions +# This file should be installed in /usr/lib/udev/rules.d +# +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="prandom", MODE="0444" diff --git a/59-zfcp-compat.rules b/59-zfcp-compat.rules new file mode 100644 index 0000000..9baeb8f --- /dev/null +++ b/59-zfcp-compat.rules @@ -0,0 +1,23 @@ +# Rules for creating the ID_PATH for SCSI devices based on the CCW bus +# using the form: ccw--zfcp-: +# +ACTION=="remove", GOTO="zfcp_scsi_device_end" + +# +# Set environment variable "ID_ZFCP_BUS" to "1" if the devices +# (both disk and partition) are SCSI devices based on FCP devices +# +KERNEL=="sd*", SUBSYSTEMS=="ccw", DRIVERS=="zfcp", ENV{.ID_ZFCP_BUS}="1" + +# For SCSI disks +KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi", \ + ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk", \ + SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}" + + +# For partitions on a SCSI disk +KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi", \ + ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition", \ + SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n" + +LABEL="zfcp_scsi_device_end" diff --git a/90-s390-tools.conf b/90-s390-tools.conf new file mode 100644 index 0000000..a83661d --- /dev/null +++ b/90-s390-tools.conf @@ -0,0 +1,25 @@ +# +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# All rights reserved. +# +# Please don't edit this file. Place your settings into +# /etc/modprobe.d/99-local.conf instead. +# +# The dasd_diag_mod kernel module will not function properly +# unless the dasd_fba_mod module is also loaded. However, +# there are no cross-module symbol dependencies that would +# cause and entry to be placed in +# /lib/modules/$(uname -r)/modules.dep +# So, we're adding this "soft" dependency here to make sure that +# any time dasd_diag_mod gets loaded, so will dasd_fba_mod. +# +# Additionally, DASD devices that are supposed to be used in +# DIAG250 mode will have problems because as far as the kernel +# is concerned, and hence udev, the driver is dasd_fba_mod. So, +# we need to also have the reverse dependency so that when +# dasd_fba_mod gets loaded, so will dasd_diag_mod. This will +# prevent problems that would show up in the system log as: +# Setting the DASD online failed because of missing DIAG discipline +# +softdep dasd_diag_mod pre: dasd_fba_mod +softdep dasd_fba_mod pre: dasd_diag_mod diff --git a/README.SUSE b/README.SUSE new file mode 100644 index 0000000..1d98ca5 --- /dev/null +++ b/README.SUSE @@ -0,0 +1,57 @@ + +ls - Addons by SUSE + + The following utility and its man page have been added to make it + easier to determine the machine type on which Linux is running. + + * cputype + Usage: cputype + + The following utilities and their man pages have been added by SUSE to + ease the activation and deactivation of devices. These scripts are also + used by YaST. Functionality not provided by these scripts cannot be + provided by YaST. + These scripts also create/delete the needed udev rules. + Detailed information on some parameters are in the + "Device Drivers, Features and Commands" for this release. + + General parameters + channel numbers are with lower letters + parameters switching things on or off are + 1 for on and 0 for off + + * ctc_configure + Usage: /sbin/ctc_configure [] + To configure CTC connections + Valid Parameters for the protocal are 0, 1 and 3 + For a detailed explanation please look in the Device Driver book + + * dasd_configure + Usage: dasd_configure + To set DASDs online/offline + The use_diag makes only sense under z/VM. In an + LPAR just set it to 0 + + * iucv_configure + Usage: /sbin/iucv_configure + To set an IUCV IP-network online/offline + + * qeth_configure + Usage: /sbin/qeth_configure [options] + Set qeth, hipersocket adapter online/offline. + options could be one of the following: + + -i Configure IP takeover + -l Configure Layer2 support + -p NAME QETH Portname to use + -n 1/0 QETH port number to use + + + * zfcp_disk_configure + Usage: /sbin/zfcp_disk_configure + set a disk online/offline. This require that the repective + Adapter is online. See command below. + + * zfcp_host_configure + Usage: /sbin/zfcp_host_configure + Set a zfcp Adapter online/offline diff --git a/appldata b/appldata new file mode 100644 index 0000000..db9347b --- /dev/null +++ b/appldata @@ -0,0 +1,183 @@ +#!/bin/sh +# Copyright (c) 2003 SUSE LINUX AG Nuernberg, Germany. +# +# Submit feedback to http://www.suse.de/feedback/ +# +# /etc/init.d/appldata +# +# and symbolic its link +# +# /use/sbin/rcappldata +# +# System startup script for "Linux - z/VM Monitor Stream". +# +### BEGIN INIT INFO +# Provides: appldata +# Required-Start: $network $remote_fs +# Required-Stop: $null +# Default-Start: 3 5 +# Default-Stop: 0 1 6 +# Short-Description: Linux - z/VM Monitor Stream +# Description: Start the Linux - z/VM Monitor Stream +### END INIT INFO +# + +# Local settings +LOCKFILE=/var/lock/appldata +CONFIGFILE=/etc/sysconfig/appldata + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +rc_reset + +# APPLDATA support in kernel? +if [ ! -e /proc/sys/appldata/interval ]; then + echo "No kernel support for \"Linux - z/VM Monitor Stream\"!" + exit 1 +fi + + +# Source config file +if [ -f $CONFIGFILE ]; then + . $CONFIGFILE +else + echo "No config file found (should be $CONFIGFILE)." + exit 1 +fi + +RETVAL=0 + +start() { + echo "Starting \"Linux - z/VM Monitor Stream\" ..." + if [ -e $LOCKFILE ]; then + echo -n "(already running)" + rc_status -v + rc_exit + fi + echo -n "(interval $APPLDATA_INTERVAL milliseconds) " + echo $APPLDATA_INTERVAL > /proc/sys/appldata/interval + if [ "$APPLDATA_MEM" = "yes" ]; then + if [ ! -e /proc/sys/appldata/mem ]; then + echo -n "(mem) " + modprobe appldata_mem 2>&1 + if [ "$?" -ne 0 ] ; then + rc_failed 1 + else + echo 1 > /proc/sys/appldata/mem + fi + fi + fi + if [ "$APPLDATA_OS" = "yes" ]; then + if [ ! -e /proc/sys/appldata/os ]; then + echo -n "(os) " + modprobe appldata_os 2>&1 + if [ "$?" -ne 0 ]; then + rc_failed 1 + else + echo 1 > /proc/sys/appldata/os + fi + fi + fi + if [ "$APPLDATA_NET_SUM" = "yes" ]; then + if [ ! -e /proc/sys/appldata/net_sum ]; then + echo -n "(net_sum) " + modprobe appldata_net_sum 2>&1 + if [ "$?" -ne 0 ]; then + rc_failed 1 + else + echo 1 > /proc/sys/appldata/net_sum + fi + fi + fi + echo -n "(timer)" + echo 1 > /proc/sys/appldata/timer + touch $LOCKFILE + rc_status -v +} + +stop() { + echo -n "Stopping \"Linux - z/VM Monitor Stream\" " + echo -n "(timer" + echo 0 > /proc/sys/appldata/timer + if [ -e /proc/sys/appldata/mem ]; then + echo -n ",mem" + echo 0 > /proc/sys/appldata/mem + rmmod appldata_mem + fi + if [ -e /proc/sys/appldata/os ]; then + echo -n ",os" + echo 0 > /proc/sys/appldata/os + rmmod appldata_os + fi + if [ -e /proc/sys/appldata/net_sum ]; then + echo -n ",net_sum" + echo 0 > /proc/sys/appldata/net_sum + rmmod appldata_net_sum + fi + echo -n ")" + rm -f $LOCKFILE + rc_status -v +} + +restart() { + stop + start +} + +status() { + echo "\"Linux - z/VM Monitor Stream\" status..." + echo -n "interval " + cat /proc/sys/appldata/interval + echo -n "timer " + cat /proc/sys/appldata/timer + echo -n "mem " + if [ -e /proc/sys/appldata/mem ]; then + cat /proc/sys/appldata/mem + else + echo 0 + fi + echo -n "os " + if [ -e /proc/sys/appldata/os ]; then + cat /proc/sys/appldata/os + else + echo 0 + fi + echo -n "net_sum " + if [ -e /proc/sys/appldata/net_sum ]; then + cat /proc/sys/appldata/net_sum + else + echo 0 + fi +} + +# How are we called? +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + restart|reload) + restart + ;; + *) + echo "Usage: appldata {start|stop|status|restart|reload}" + RETVAL=1 +esac + +exit $RETVAL + diff --git a/boot.cpi b/boot.cpi new file mode 100644 index 0000000..8a18fcc --- /dev/null +++ b/boot.cpi @@ -0,0 +1,56 @@ +#!/bin/sh +# +# Copyright (c) 2001-2002 SuSE Linux AG, Nuernberg, Germany. +# Copyright (c) 2008 SuSE LINUX Products GmbH, Nuernberg, Germany. +# All rights reserved. +# +# /etc/init.d/boot.cpi +# +### BEGIN INIT INFO +# Provides: boot.cpi +# Required-Start: boot.rootfsck +# Required-Stop: $null +# Should-Start: +# X-Start-Before: +# Default-Start: B S +# Default-Stop: +# Description: Set Control Program Identification data +# Short-Description: Set Control Program Identification data +### END INIT INFO + +. /etc/rc.status +. /etc/sysconfig/cpi + +rc_reset + +case "$1" in + start|restart|reload) + if test "$CPI_SET" == "yes"; then + if test ! -e /sys/firmware/cpi; then + echo -n "sclp_cpi interface not found" + rc_status -s + rc_exit + fi + echo "$CPI_SYSTEM_NAME" >/sys/firmware/cpi/system_name + echo "$CPI_SYSPLEX_NAME" >/sys/firmware/cpi/sysplex_name + echo "LINUX " >/sys/firmware/cpi/system_type + awk "BEGIN { split(\"`uname -r`\",x,\".\"); printf(\"0x0000000000%02x%02x%02x\", x[1],x[2],x[3]) }" >/sys/firmware/cpi/system_level + echo 1 >/sys/firmware/cpi/set 2>/dev/null + rc_status -v -r + else + rc_status -u + fi + ;; + stop) + rc_status -s + ;; + status) + rc_status -s + ;; + *) + echo "Usage: $0 {start|stop|status|restart|reload}" + exit 1 + ;; +esac + +rc_exit diff --git a/cio_ignore.service b/cio_ignore.service new file mode 100644 index 0000000..66b09ff --- /dev/null +++ b/cio_ignore.service @@ -0,0 +1,13 @@ +[Unit] +Description=Setup devices for cio_ignore +DefaultDependencies=no +Before=local-fs.target +ConditionKernelCommandLine=cio_ignore + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/systemd/scripts/setup_cio_ignore.sh + +[Install] +WantedBy=sysinit.target diff --git a/cputype b/cputype new file mode 100644 index 0000000..572f528 --- /dev/null +++ b/cputype @@ -0,0 +1,67 @@ +#!/bin/sh +# +# cputype +# +# Copyright (c) 2014-2016 SUSE LINUX GmbH, Nuernberg, Germany. +# +# Based on the IBM machine model, returns a (hopefully) human understandable +# string that identifies the processor. +# +# Usage: +# cputype +# +# Return values: +# 1 The script was executed on a system that is a non-IBM mainframe +# architecture +# 2 The search for the machine type in /proc/cpuinfo returned a null string +# 3 The parsing of the machine type returned a null string +# 4 The machine type found is (probably) a new one, and the script needs to +# be updated to handle it. +# + +architecture=$(/bin/uname -m) +if [ "${architecture}" != "s390x" -a "${architecture}" != "s390" ]; then + echo "This command is only useful on IBM mainframes." >&2 + exit 1 +fi + +args=$(/usr/bin/grep machine /proc/cpuinfo | /usr/bin/cut -f2- -d: | /usr/bin/tr -d ' ' | /usr/bin/tr ',' ';' ) + +if [ -z "${args}" ]; then + echo "I couldn't find the machine type. Please report a bug with this output:" >&2 + /bin/cat /proc/cpuinfo >&2 + echo "******************" >&2 + /usr/bin/grep machine /proc/cpuinfo >&2 + exit 2 +fi + +eval ${args} + +if [ -z "${machine}" ] ; then + echo "The machine type came out null. Please report a bug with this output:" >&2 + /bin/cat /proc/cpuinfo >&2 + exit 3 +fi + +case "${machine}" in + 2064) echo "${machine} = z900 IBM eServer zSeries 900" ;; + 2066) echo "${machine} = z800 IBM eServer zSeries 800" ;; + 2084) echo "${machine} = z990 IBM eServer zSeries 990" ;; + 2086) echo "${machine} = z890 IBM eServer zSeries 890" ;; + 2094) echo "${machine} = z9-EC IBM System z9 Enterprise Class" ;; + 2096) echo "${machine} = z9-BC IBM System z9 Business Class" ;; + 2097) echo "${machine} = z10-EC IBM System z10 Enterprise Class" ;; + 2098) echo "${machine} = z10-BC IBM System z10 Business Class" ;; + 2817) echo "${machine} = z196 IBM zEnterprise 196" ;; + 2818) echo "${machine} = z114 IBM zEnterprise 114" ;; + 2827) echo "${machine} = z12-EC IBM zEnterprise EC12" ;; + 2828) echo "${machine} = z12-BC IBM zEnterprise BC12" ;; + 2964) echo "${machine} = z13 IBM z13" ;; + 2965) echo "${machine} = z13s IBM z13s (single frame)" ;; + *) echo "An unknown machine type was reported: ${machine}" >&2 + echo "Please file a bug report with this output:" >&2 + /bin/cat /proc/cpuinfo >&2 + exit 4 + ;; +esac + diff --git a/cputype.1 b/cputype.1 new file mode 100644 index 0000000..1ee5733 --- /dev/null +++ b/cputype.1 @@ -0,0 +1,50 @@ +.TH cputype 1 "April 2014" "s390-tools" +.SH NAME +cputype \- Based on the IBM machine model, returns a (hopefully) human understandable string that identifies the processor. +.SH SYNOPSIS +.B cputype +.SH DESCRIPTION +.B cputype +is intended to make it easy to find out the type of the mainframe system in use, by examining /proc/cpuinfo and converting that to the name typically known by people familiar with the IBM mainframe. +.SH PARAMETERS +.IP None +.SH FILES +.I /proc/cpuinfo +.RS +Read to determine the IBM machine model for the running system. +.RE +.SH DIAGNOSTICS +The following messages may be issued on stderr: +.IP +.B This command is only useful on IBM mainframes. +.RS +The command was executed on a system that is running on a non-IBM mainframe architecture. +Return code 1 is set. +.RE +.IP +.B I couldn't find the machine type. Please report a bug with this output: +.RS +The contents of /proc/cpuinfo are printed as well as the output from the grep command used. +Return code 2 is set. +.RE +.IP +.B The machine type came out null. Please report a bug with this output: +.RS +The contents of /proc/cpuinfo are printed. Return code 3 is set. +.RE +.IP +.B An unknown machine type was reported: mmmm +.RS +.B Please file a bug report with this output: +.RE +.RS +This is most likely seen because the command was run on a newer generation processor +and the script has not been updated with the new model number. +The contents of /proc/cpuinfo are printed. Return code 4 is set. +.RE +.SH Author +Mark Post (mpost@suse.com) +.SH Copyright +Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. diff --git a/ctc_configure b/ctc_configure new file mode 100644 index 0000000..ddaeaf0 --- /dev/null +++ b/ctc_configure @@ -0,0 +1,317 @@ +#! /bin/sh +# +# ctc_configure +# +# Configures a CTC device +# +# Usage: +# ctc_configure [] +# +# read/write channel = x.y.ssss where +# x is always 0 until IBM creates something that uses that number +# y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero +# ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros. +# online = 0 to take the device offline +# 1 to bring the device online +# protocol = 0 Compatibility with peers other than OS/390®, or z/OS, for example, a z/VM TCP service machine. This is the default. +# 1 Enhanced package checking for Linux peers. +# 3 For compatibility with OS/390 or z/OS peers. +# 4 For MPC connections to VTAM on traditional mainframe operating systems. +# +# Return values: +# 1 sysfs not mounted +# 2 Invalid status for +# 3 No device found for read-channel +# 4 No device found for write-channel +# 5 Invalid device type +# 6 Device type mismatch +# 7 Could not load module +# 8 CCW devices grouped different devices +# 9 Could not group devices +# 10 Could not set device online +# 11 Could not set device offline +# + +if [ "${DEBUG}" != "yes" ]; then + DEBUG="no" +fi + +DATUM=$(date) + +add_channel_for_cio() { + echo "$* # $DATUM" >> /boot/zipl/active_devices.txt +} + +remove_channel_for_cio() { + [ -w /boot/zipl/active_devices.txt ] && sed -i -e "/^$1/d" /boot/zipl/active_devices.txt +} + +mesg () { + echo "$@" +} + +debug_mesg () { + case "$DEBUG" in + yes) mesg "$@" ;; + *) ;; + esac +} + +# Get the mount point for sysfs +while read MNTPT MNTDIR MNTSYS MNTTYPE; do + if test "$MNTSYS" = "sysfs"; then + SYSFS="$MNTDIR" + break; + fi +done []" + echo " read/write channel = x.y.ssss where" + echo " x is always 0 until IBM creates something that uses that number" + echo " y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero" + echo " ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros." + echo " online = 0 to take the device offline" + echo " 1 to bring the device online" + echo " protocol = 0 Compatibility with peers other than OS/390®, or z/OS, for example, a z/VM TCP service machine. This is the default." + echo " 1 Enhanced package checking for Linux peers." + echo " 3 For compatibility with OS/390 or z/OS peers." + echo " 4 For MPC connections to VTAM on traditional mainframe operating systems." + exit 1 +fi + +CTC_READ_CHAN=$1 +CTC_WRITE_CHAN=$2 +ONLINE=$3 +CTC_MODE=$4 + +[ -z "$CTC_MODE" ] && CTC_MODE=0 + +if [ -z "$ONLINE" ] || [ "$ONLINE" -ne "1" -a "$ONLINE" -ne "0" ]; then + mesg "Invalid device status $ONLINE" + exit 2 +fi + +_ccw_dir=${SYSFS}/bus/ccw/devices + +debug_mesg "Configuring CTC/LCS device ${CTC_READ_CHAN}/${CTC_WRITE_CHAN}" + + +if test ! -d "$_ccw_dir/$CTC_READ_CHAN" ; then + mesg "device $_ccw_dir/$CTC_READ_CHAN does not exist" + exit 3 +fi +if test ! -d "$_ccw_dir/$CTC_WRITE_CHAN" ; then + mesg "device $_ccw_dir/$CTC_WRITE_CHAN does not exist" + exit 4 +fi + +CCW_CHAN_GROUP= +for ccw in $_ccw_dir/$CTC_READ_CHAN $_ccw_dir/$CTC_WRITE_CHAN; do + + read _cu_type < $ccw/cutype + read _dev_type < $ccw/devtype + + case "$_cu_type" in + 3088/01) + # P/390 network adapter + CCW_CHAN_NAME="cu3088" + CCW_CHAN_GROUP="lcs" + ;; + 3088/08) + # Channel To Channel + CCW_CHAN_NAME="cu3088" + CCW_CHAN_GROUP="ctcm" + ;; + 3088/1e) + # FICON adapter + CCW_CHAN_NAME="cu3088" + CCW_CHAN_GROUP="ctcm" + ;; + 3088/1f) + # ESCON adapter (I.e. hardware CTC device) + CCW_CHAN_NAME="cu3088" + CCW_CHAN_GROUP="ctcm" + ;; + 3088/60) + # Lan Channel Station + CCW_CHAN_NAME="cu3088" + CCW_CHAN_GROUP="lcs" + ;; + *) + CCW_CHAN_NAME= + ;; + esac + + if [ -z "$CCW_CHAN_NAME" ]; then + mesg "Not a valid CTC device (cu $_cutype, dev $_devtype)" + exit 5 + fi + + [ -z "$tmp_chan" ] && tmp_chan=$CCW_CHAN_GROUP +done + +if [ "$tmp_chan" != "$CCW_CHAN_GROUP" ] ; then + mesg "CTC type mismatch (read: $tmp_chan, write: $CCW_CHAN_GROUP)" + exit 6 +fi + +_ccw_groupdir=${SYSFS}/bus/ccwgroup + +# Check for modules +if test ! -d "${_ccw_groupdir}/drivers/${CCW_CHAN_GROUP}" ; then + /sbin/modprobe $CCW_CHAN_GROUP + + # Re-check whether module loading has succeeded + if test ! -d "${_ccw_groupdir}/drivers/${CCW_CHAN_GROUP}"; then + mesg "Could not load module ${CCW_CHAN_GROUP}" + exit 7 + fi +fi + +# Check for grouping +_ccw_status_dir= +if [ -e ${_ccw_dir}/${CTC_READ_CHAN}/group_device ] ; then + _ccw_status_dir=$(cd -P ${_ccw_dir}/${CTC_READ_CHAN}/group_device; echo $PWD) +fi +if [ -e ${_ccw_dir}/${CTC_WRITE_CHAN}/group_device ] ; then + _tmp_status_dir=$(cd -P ${_ccw_dir}/${CTC_READ_CHAN}/group_device; echo $PWD) + if [ "$_ccw_status_dir" ] && [ "$_ccw_status_dir" != "$_tmp_status_dir" ] ; then + mesg "CCW devices grouped to different devices" + exit 8 + fi + _ccw_status_dir=$_tmp_status_dir +fi +# +# Addresses are free (but may be bound to the wrong driver) +# +_ccw_drivers=${SYSFS}/bus/ccw/drivers +for i in ${CTC_READ_CHAN} ${CTC_WRITE_CHAN} + do + if [ "$CCW_CHAN_GROUP" = "lcs" ] + then + if [ -e "${_ccw_drivers}/ctcm/${i}" ] ; then + echo $i > ${_ccw_drivers}/ctcm/unbind + fi + if [ ! -e "${_ccw_drivers}/lcs/${i}" ] ; then + echo $i > ${_ccw_drivers}/ctcm/bind + fi + else + if [ -e "${_ccw_drivers}/lcs/${i}" ] ; then + echo $i > ${_ccw_drivers}/lcs/unbind + fi + if [ ! -e "${_ccw_drivers}/ctcm/${i}" ] ; then + echo $i > ${_ccw_drivers}/ctcm/bind + fi + fi + done + +debug_mesg "Group is ${_ccw_groupdir}/drivers/${CCW_CHAN_GROUP}/group" +if [ -z "$_ccw_status_dir" ] ; then + echo "$CTC_READ_CHAN,$CTC_WRITE_CHAN" > ${_ccw_groupdir}/drivers/${CCW_CHAN_GROUP}/group + if [ -e ${_ccw_dir}/${CTC_READ_CHAN}/group_device ] ; then + _ccw_status_dir=$(cd -P ${_ccw_dir}/${CTC_READ_CHAN}/group_device; echo $PWD) + fi +fi + +if [ -z "$_ccw_status_dir" -o ! -e "$_ccw_status_dir" ] ; then + mesg "Could not group $CCW_CHAN_GROUP devices $CTC_READ_CHAN/$CTC_WRITE_CHAN" + exit 9 +fi + +CCW_CHAN_ID=${_ccw_status_dir##*/} + +read _ccw_dev_status < $_ccw_status_dir/online + +if [ "$ONLINE" -eq 1 ]; then + # Check whether we need to do something + if [ "$_ccw_dev_status" -eq 0 ]; then + if [ "$CTC_MODE" -gt 0 -a "$CCW_CHAN_GROUP" != "lcs" ]; then + echo $CTC_MODE > $_ccw_status_dir/protocol + fi + # Set the device online + debug_mesg "Setting device online" + echo "1" > $_ccw_status_dir/online + # Re-read device status + read _ccw_dev_status < $_ccw_status_dir/online + if [ "$_ccw_dev_status" -eq 0 ]; then + mesg "Could not set device ${CCW_CHAN_ID} online" + exit 10 + fi + else + debug_mesg "Device ${CCW_CHAN_ID} is already online" + fi +else + if [ "$_ccw_dev_status" -eq 1 ]; then + # Set the device offline + debug_mesg "Setting device offline" + echo "$ONLINE" > $_ccw_status_dir/online + + # Re-read to check whether we have succeeded + _ccw_dev_status=$(cat $_ccw_status_dir/online) + if [ "$_ccw_dev_status" -ne "$ONLINE" ]; then + mesg "Could not set device ${CCW_CHAN_ID} offline" + exit 11 + fi + else + debug_mesg "Device ${CCW_CHAN_ID} is already offline" + fi + # Always reset CTC Protocol + if [ "$CCW_CHAN_GROUP" != "lcs" ]; then + echo 0 > $_ccw_status_dir/protocol + fi +fi + +RULES_DIR=/etc/udev/rules.d +RULES_FILE=51-${CCW_CHAN_GROUP}-${CCW_CHAN_ID}.rules + +if [ -d "$RULES_DIR" ]; then + if [ -f ${RULES_DIR}/${RULES_FILE} ]; then + rm -f ${RULES_DIR}/${RULES_FILE} + fi + remove_channel_for_cio "$CTC_READ_CHAN" + remove_channel_for_cio "$CTC_WRITE_CHAN" + + if [ "$ONLINE" -eq "1" ]; then + add_channel_for_cio "$CTC_READ_CHAN,$CTC_WRITE_CHAN" + # Write a new udev rules file + cat > ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <.rules +.RE +.I /etc/udev/rules.d/51-lcs-.rules +.RS +These files provide the udev rules necessary to activate a specific CTC or LCS. +.RE +.SH ENVIRONMENT +.IP DEBUG +If set to "yes" some minimal debugging information is output during execution. +.SH DIAGNOSTICS +The following messages may be issued on stdout: +.IP +.B /sysfs not present +.RS +The sysfs file system could not be found in /proc/mounts, so there's nothing the script can +do. Return code 1 is set. +.RE +.IP +.B Invalid device status ${ONLINE} +.RS +A value other than 0 or 1 was specified for the third parameter, online. Return code 2 is set. +.RE +.IP +.B Device ${CTC_READ_CHAN} does not exist +.RS +A non-existent was specified for the first parameter. Remember the x.y.ssss format is necessary. Return code 3 is set. +.RE +.IP +.B Device ${CTC_READ_CHAN} does not exist +.RS +A non-existent was specified for the second parameter. Remember the x.y.ssss format is necessary. Return code 4 is set. +.RE +.IP +.B Not a valid CTC device (cu ${_cutype}, dev ${_devtype}) +.RS +The device number specified does not correspond to a valid CTC or LCS device type. Return code 5 is st. +.RE +.IP +.B CTC type mismatch (read: ${tmp_chan}, write: ${CCW_CHAN_GROUP}) +.RS +The device number specified for the read channel has a different device type than the device number specified for the write channel. Return code 6 is set. +.RE +.IP +.B Could not load module ${CCW_CHAN_GROUP} +.RS +The kernel module for the device type failed to load. Try "dmesg" to see if there is any indication why. Return code 7 is set. +.RE +.IP +.B CCW devices grouped to different devices +.RS +The read and write channels are already grouped, but not within the same interface. Try again with different devices. Return code 8 is set. +.RE +.IP +.B Could not group ${CCW_CHAN_GROUP} devices ${CTC_READ_CHAN}/${CTC_WRITE_CHAN} +.RS +The attempt to group the read and write channels into an interface failed. Try "dmesg" to see if there is any indication why. Return code 9 is set. +.RE +.IP +.B Could not set device ${CCW_CHAN_ID} online +.RS +The attempt to bring the grouped devices online failed. Try "dmesg" to see if there is any indication why. Return code 10 is set. +.RE +.IP +.B Could not set device ${CCW_CHAN_ID} offline +.RS +The attempt to take the grouped devices offline failed. Try "dmesg" to see if there is any indication why. Return code 11 is set. +.RE + +If environment variable DEBUG is set to "yes," the following messages may be issued on stdout: +.IP +.B +Configuring CTC/LCS device ${CTC_READ_CHAN}/${CTC_WRITE_CHAN} +.RS +Just a little bit of verbosity, since it just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B Group is ${_ccw_groupdir}/drivers/${CCW_CHAN_GROUP}/group +.RS +Just a little bit of verbosity. +.RE +.IP +.B Setting device online +.RS +Just a little bit of verbosity. +.RE +.IP +.B Device ${CCW_CHAN_ID} is already online +.RS +An attempt was made to bring the adapter online when it was already online. +.RE +.IP +.B Setting device offline +.RS +Just a little bit of verbosity. +.RE +.IP +.B Device ${CCW_CHAN_ID} is already offline +.RS +An attempt was made to take the adapter offline when it was already offline. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. diff --git a/dasd_configure b/dasd_configure new file mode 100644 index 0000000..1c3afea --- /dev/null +++ b/dasd_configure @@ -0,0 +1,409 @@ +#! /bin/sh +# +# dasd_configure +# $Id: dasd_configure,v 1.10 2004/11/26 15:50:48 hare Exp $ +# +# Copyright (c) 2001-2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# Configures or deconfigures a DASD device +# +# Usage: +# dasd_configure [-f -t ] [use_diag] +# +# -f force creation of udev rules, do not check values in /sys. +# -t DASD type. Must be provided if -f is used. +# ccwid = x.y.ssss where +# x is always 0 until IBM creates something that uses that number +# y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero +# ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros. +# online = 0 to take the device offline +# 1 to bring the device online +# use_diag = 0 to _not_ use z/VM DIAG250 I/O, which is the default +# 1 to use z/VM DIAG250 I/O +# +# Return values: +# 1 If the "Usage:" line is displayed, not enough parameters specified. +# 1 sysfs not mounted (if the "Usage:" line is not displayed). +# 2 Invalid status for +# 3 No device found for +# 4 Could not change state of the device +# 5 Device is not a DASD +# 6 Could not load module +# 7 Failed to activate DASD +# 8 DASD not formatted +# 9 Only dasd-fba or dasd-eckd is supported. +# + +if [ "${DEBUG}" != "yes" ]; then + DEBUG="no" +fi + +exitcode=0 +DASD_FORCE=0 +DASD_TYPE="unknown" + +DATUM=$(date) + +add_channel_for_cio() { + echo "$* # $DATUM" >> /boot/zipl/active_devices.txt +} + +remove_channel_for_cio() { + [ -w /boot/zipl/active_devices.txt ] && sed -i -e "/^$1/d" /boot/zipl/active_devices.txt +} + +mesg () { + echo "$@" +} + +debug_mesg () { + case "$DEBUG" in + yes) mesg "$@" ;; + *) ;; + esac +} + +if [ $# -lt 2 ] ; then + echo "Usage: $0 [options] [use_diag]" + echo + echo " -f force creation of udev rules, do not check values in /sys." + echo " -t DASD type. Must be provided if -f is used." + echo " ccwid = x.y.ssss where" + echo " x is always 0 until IBM creates something that uses that number" + echo " y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero" + echo " ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros." + echo " online = 0 to take the device offline" + echo " 1 to bring the device online" + echo " use_diag = 0 to _not_ use z/VM DIAG250 I/O, which is the default" + echo " 1 to use z/VM DIAG250 I/O" + exit 1 +fi + +while [ $# -gt 0 ] ; do + case "$1" in + -f) # force creation of udev rules, do not check values in /sys + DASD_FORCE=1 + ;; + -t*) # drive type. Must be provided if -f is used. + if [ "$1" = "-t" ] ; then + if [ "$2" = "dasd-eckd" -o "$2" = "dasd-fba" ]; then + DASD_TYPE=$2 + shift + else + debug_mesg "Only dasd-eckd or dasd-fba are supported." + exit 9 + fi + fi + ;; + *) + break; + ;; + esac + shift +done + +if [ $DASD_FORCE -eq 0 ]; then + # Get the mount point for sysfs + while read MNTPT MNTDIR MNTSYS MNTTYPE; do + if test "$MNTSYS" = "sysfs"; then + SYSFS="$MNTDIR" + break; + fi + done &1 > /dev/null + if [ -x /sbin/vmcp -a $? -eq 0 ]; then + # Unconditionally load the vmcp module, loader might be broken + [ -x /sbin/modprobe ] && /sbin/modprobe -q vmcp + # Wait until udev is settled + [ -x /sbin/udevadm ] && /sbin/udevadm settle --timeout=30 + + # Check read-only status of virtual DASDs from z/VM + if /sbin/vmcp q v dasd > /dasd_attr.lst 2> /dev/null; then + while read x dev type label attr1 attr2 rest; do + dev=`echo $dev|tr A-F a-f` + if test "$type" = "ON"; then + attr="$attr2" + else + attr="$attr1" + fi + if [ "$CCW_CHAN_ID" = "0.0.$dev" ]; then + if test "$attr" = "R/O"; then + _ccw_use_readonly="1" + fi + fi + done < /dasd_attr.lst + fi + rm -f /dasd_attr.lst + fi # if [ -x /sbin/vmcp -a $? -eq 0 ] + + if [ "$ONLINE" -eq 1 ]; then + # Check whether we need to do something + read _ccw_use_diag < $_ccw_status_dir/use_diag + + if [ "$_ccw_use_diag" -ne "$USE_DIAG" ] && + [ "$_ccw_dev_status" -eq 1 ] ; then + # We need to change the DIAG access mode + # so we have to set the device offline first + debug_mesg "Setting device offline for DIAG access" + echo "0" > $_ccw_status_dir/online + # Re-read device status + read _ccw_dev_status < $_ccw_status_dir/online + if [ "$_ccw_dev_status" -ne 0 ]; then + mesg "Could not set the device offline for DIAG access" + exit 4 + fi + fi + + if [ "$_ccw_dev_status" -eq 0 ]; then + # Set readonly access if detected + if [ "$_ccw_use_readonly" ]; then + debug_mesg "Setting device read-only" + echo 1 > $_ccw_status_dir/readonly + fi + + if [ "$USE_DIAG" -eq 1 ]; then + # Load the diag module if possible + [ -x /sbin/modprobe ] && /sbin/modprobe -q dasd_diag_mod + _has_dasd_diag=$(/bin/sed -n '/^dasd_diag_mod/p' /proc/modules) + if [ "$_has_dasd_diag" ]; then + # DIAG mode is special: + # We can only be sure if DIAG is available + # _after_ we have activated the device + debug_mesg "Activating DIAG access mode" + echo "$USE_DIAG" > $_ccw_status_dir/use_diag + read _ccw_use_diag < $_ccw_status_dir/use_diag + # Set the device online + debug_mesg "Setting device online" + echo "1" > $_ccw_status_dir/online 2>/dev/null + # Re-read device status + read _ccw_dev_status < $_ccw_status_dir/online + if [ "$_ccw_dev_status" -eq 0 ]; then + mesg "Could not activate DIAG access mode for device ${CCW_CHAN_ID}" + USE_DIAG=0 + echo "$USE_DIAG" > $_ccw_status_dir/use_diag + # Set the device online + debug_mesg "Setting device online" + echo "1" > $_ccw_status_dir/online + else + MODULE=dasd_diag_mod + fi + else + debug_mesg "DIAG mode not available" + USE_DIAG=0 + # Set the device online + debug_mesg "Setting device online" + echo "1" > $_ccw_status_dir/online + fi # if [ "$_has_dasd_diag" ]; + else + if [ "$_ccw_use_diag" -eq 1 ] ; then + debug_mesg "Deactivating DIAG access mode" + echo "0" > $_ccw_status_dir/use_diag + read _ccw_use_diag < $_ccw_status_dir/use_diag + fi + # Set the device online + debug_mesg "Setting device online" + echo "1" > $_ccw_status_dir/online + fi # if [ "$USE_DIAG" -eq 1 ] + + # Re-read device status + read _ccw_dev_status < $_ccw_status_dir/online + if [ "$_ccw_dev_status" -eq 0 ]; then + mesg "Could not set device ${CCW_CHAN_ID} online" + exit 4 + fi + + # Wait for the device to come online + read _dasd_state < $_ccw_status_dir/status + i=0 + while [ "$_dasd_state" != "online" ] ; do + if [ "$_dasd_state" = "unformatted" ] ; then + mesg "Device ${CCW_CHAN_ID} is unformatted" + exitcode=8 + break + fi + [ $i -gt 30 ] && break + i=$(expr $i + 1) + sleep .1 + read _dasd_state < $_ccw_status_dir/status + done + else + debug_mesg "Device ${CCW_CHAN_ID} is already online" + fi # if [ "$_ccw_dev_status" -eq 0 ] + + read _dasd_state < $_ccw_status_dir/status + if [ "$_dasd_state" != "online" ] && [ "$_dasd_state" != "unformatted" ] ; then + mesg "Failed to activate device ${CCW_CHAN_ID}, device in state $_dasd_state" + exit 7 + fi + else + if [ "$_ccw_dev_status" -eq 1 ]; then + # Set the device offline + debug_mesg "Setting device offline" + echo "$ONLINE" > $_ccw_status_dir/online + + # Re-read to check whether we have succeeded + _ccw_dev_status=$(cat $_ccw_status_dir/online) + if [ "$?" -ne 0 -o "$_ccw_dev_status" -ne "$ONLINE" ]; then + mesg "Could not set device ${CCW_CHAN_ID} offline" + exit 4 + fi + else + debug_mesg "Device ${CCW_CHAN_ID} is already offline" + fi + + if [ -d "$_ccw_status_dir" ] ; then + # Always disabling DIAG access + echo "0" > $_ccw_status_dir/use_diag + fi + + # Set readonly access if detected + if [ "$_ccw_use_readonly" ]; then + debug_mesg "Setting device read-only" + echo 1 > $_ccw_status_dir/readonly + fi + fi # if [ "$ONLINE" -eq 1 ] + + # Wait until udev is settled + [ -x /sbin/udevadm ] && /sbin/udevadm settle --timeout=30 + +fi # Second instance of if [ $DASD_FORCE -eq 0 ] + +if [ $DEBUG = "no" ]; then + RULES_DIR=/etc/udev/rules.d +else + RULES_DIR=. +fi + +RULES_FILE=51-dasd-${CCW_CHAN_ID}.rules + +if [ -d "$RULES_DIR" ]; then + if [ -f ${RULES_DIR}/${RULES_FILE} ]; then + rm -f ${RULES_DIR}/${RULES_FILE} + fi + remove_channel_for_cio "${CCW_CHAN_ID}" + + if [ "$ONLINE" -eq "1" ]; then + add_channel_for_cio "${CCW_CHAN_ID}" + # Write a new hwcfg file + cat > ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <.rules +.RS +This file provides the udev rules necessary to activate a specific DASD volume. +.RE +.SH ENVIRONMENT +.IP DEBUG +If set to "yes" some minimal debugging information is output during execution. +.SH DIAGNOSTICS +The following messages may be issued on stdout: +.IP +.B /sysfs not present +.RS +The sysfs file system could not be found in /proc/mounts, so there's nothing the script can do. Return code 1 is set. +.RE +.IP +.B Invalid device status $ONLINE It must be a zero or a one. +.RS +A value other than 0 or 1 was specified for the second parameter, online. Return code 2 is set. +.RE +.IP +.B No device ${CCW_CHAN_ID} +.RS +A non-existent was specified for the DASD volume. Remember the x.y.ssss format is necessary. Return code 3 is set. +.RE +.IP +.B Could not set the device offline for DIAG access +.RS +You specified that the DIAG driver be used for this device. However, the device was already online without DIAG mode set, and something prevented it from being taken offline. (The use_diag value can only be modified when the disk is offline to the system.) Return code 4 is set. +.RE +.IP +.B Could not set device ${CCW_CHAN_ID} online +.RS +The attempt to bring the DASD volume online failed. Try "dmesg" to see if there is any indication why. Return code 4 is set. +.RE +.IP +.B Could not set device ${CCW_CHAN_ID} offline +.RS +The attempt to take the DASD volume offline failed. Try "dmesg" to see if there is any indication why. Return code 4 is set. +.RE +.IP +.B Not a DASD device (cu $_cutype, dev $_devtype) +.RS +The ccwid you specified does not refer to a DASD volume. Return code 5 is set. +.RE +.IP +.B Could not load module ${MODULE} +.RS +The dasd_eckd_mod.ko or dasd_fba_mod.ko module failed to load. Try "dmesg" to see if there is any indication why. Return code 6 is set. +.RE +.IP +.B Failed to activate device ${CCW_CHAN_ID}, device in state $_dasd_state +.RS +The attempt to bring the DASD volume online failed. The volume was left in the state described (which will not be online or offline.) Return code 7 is set. +.RE +.IP +.B Device ${CCW_CHAN_ID} is unformatted +.RS +The DASD volume was brought online, but it has not been formatted with dasdfmt. This condition is really only important for YaST to determine if it should prompt the user to decide if they want to format it or not at that point. The udev rules are not created. After the disk has been formatted, re-run dasd_configure to take the volume offline, and then again to bring it online. Return code 8 is set. +.RE +.IP +.B Only dasd-eckd or dasd-fba are supported. +.RS +Either an invalid -t value was specified, or -f was specified without -t. Return code 9 is set. +.RE + +If environment variable DEBUG is set to "yes," the following messages may be issued on stdout: +.IP +.B Configuring device ${CCW_CHAN_ID} +.RS +Just a little bit of verbosity, since it just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B Setting device offline for DIAG access +.RS +Just a little bit of verbosity. +.RE +.IP +.B Setting device read-only +.RS +Just a little bit of verbosity. +.RE +.IP +.B Activating DIAG access mode +.RS +Just a little bit of verbosity. +.RE +.IP +.B DIAG mode not available +.RS +You specified that the DIAG driver should be used for this DASD volume. The script tried to honor this, but was not able to do so. Non-DIAG mode was used instead. +.RE +.IP +.B Deactivating DIAG access mode +.RS +You specified that the DIAG driver NOT be used for this DASD volume, but the use_diag flag was already set for it. +.RE +.IP +.B Setting device online +.RS +Just a little bit of verbosity. +.RE +.IP +.B Device ${CCW_CHAN_ID} is already online +.RS +An attempt was made to bring the DASD volume online when it was already online. +.RE +.IP +.B Setting device offline +.RS +Just a little bit of verbosity. +.RE +.IP +.B Device ${CCW_CHAN_ID} is already offline +.RS +An attempt was made to take the DASD volume offline when it was already offline. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. diff --git a/dasd_reload b/dasd_reload new file mode 100644 index 0000000..060a6fa --- /dev/null +++ b/dasd_reload @@ -0,0 +1,137 @@ +#!/bin/sh +# +# dasd_reload +# $Id: dasd_reload,v 1.2 2004/05/26 15:17:09 hare Exp $ +# +# Deconfigures all active DASDs, unloads the modules +# and activates the configured DASDs again. +# Needed to establish an identical device mapping +# in the installation system and in the running system. +# All DASD access need to be cancelled prior to running +# this script. +# +# Usage: +# dasd_reload +# +# Return values: +# 1 Cannot read /proc/modules +# 2 Missing module programs +# 3 /sys not mounted +# 4 Failure on deactivate DASDs +# + +if [ ! -r /proc/modules ]; then + echo "Cannot read /proc/modules" + exit 1 +fi + +if [ ! -x /sbin/rmmod -o ! -x /sbin/modprobe ]; then + echo "Missing module programs" + exit 2 +fi + +if [ ! -d /sys/bus ]; then + echo "sysfs not mounted" + exit 3 +fi + +let anymd=0 +if [ -f /proc/mdstat ]; then + for mddevice in $(grep active /proc/mdstat | cut -f1 -d:); do + mdadm -S /dev/${mddevice} + let anymd=1 + done + udevadm settle +fi + +# +# Setting HyperPAV alias devices offline +# +dasd_alias= +let EXITRC=0 +for dev in /sys/bus/ccw/devices/*; do + if [ -f $dev/use_diag ]; then + read _online < $dev/online + read _alias < $dev/alias + if [ "$_online" -eq 1 -a "$_alias" -eq 1 ]; then + echo "setting DASD HyperPAV alias $(basename $dev) offline" + echo "0" > $dev/online + read _online < $dev/online + dasd_alias="$dasd_alias $(basename $dev)" + if [ "$_online" -eq 1 ]; then + echo "failure on setting DASD HyperPAV alias $(basename $dev) offline !" + let EXITRC=4 + fi + fi + fi +done + +# +# Setting "normal" DASD and HyperPAV base devices offline +# +dasd_base= +for dev in /sys/bus/ccw/devices/*; do + if [ -f $dev/use_diag ]; then + read _online < $dev/online + read _alias < $dev/alias + if [ "$_online" -eq 1 -a "$_alias" -eq 0 ]; then + echo "setting DASD $(basename $dev) offline" + echo "0" > $dev/online + read _online < $dev/online + dasd_base="$dasd_base $(basename $dev)" + if [ "$_online" -eq 1 ]; then + echo "failure on setting DASD $(basename $dev) offline !" + let EXITRC=4 + fi + fi + fi +done + +udevadm settle + +module_list= +module_test_list="dasd_diag_mod dasd_eckd_mod dasd_fba_mod dasd_mod" +for module in $module_test_list; do + if grep -q "$module" /proc/modules; then + module_list="$module $module_list" + : Unloading $module + /sbin/rmmod $module + fi +done + +if [ -d /etc/udev/rules.d ]; then + cd /etc/udev/rules.d +# +# Re-activating "normal" DASD and HyperPAV base devices +# + for dasd in $dasd_base; do + file="51-dasd-${dasd}.rules" + if [ -f "$file" ] ; then + echo Activating $dasd + if grep -q use_diag $file ; then + DASD_USE_DIAG=1 + else + DASD_USE_DIAG=0 + fi + /sbin/dasd_configure $dasd 1 $DASD_USE_DIAG + fi + done + +# +# Re-activating HyperPAV alias devices +# + for dasd in $dasd_alias; do + file="51-dasd-${dasd}.rules" + if [ -f "$file" ] ; then + echo Activating $dasd + if grep -q use_diag $file ; then + DASD_USE_DIAG=1 + else + DASD_USE_DIAG=0 + fi + /sbin/dasd_configure $dasd 1 $DASD_USE_DIAG + fi + done +fi + +exit ${EXITRC} diff --git a/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch b/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch new file mode 100644 index 0000000..11cd2b0 --- /dev/null +++ b/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch @@ -0,0 +1,71 @@ +From 943e577440d74ad7f8787af2590c8ab4579a459b Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 5 Nov 2015 10:57:38 +0100 +Subject: [PATCH] dasdfmt: retry BIODASDINFO if device is busy + +Modern udev have the wonderful 'feature' to sending a 'change' +event whenever a device opened with O_RDWR is closed again. +The reasoning is that the said program _might_ have changed +the partition table and hence we _might_ have missed a partition +update. +But in doing so it not only generated tons of pointless events +but also confused the hell out of other programs. +Idiots. + +References: bsc#937340 + +Signed-off-by: Hannes Reinecke +--- + dasdfmt/dasdfmt.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c +index e1877ac..f03cbad 100644 +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -270,7 +270,7 @@ static void init_info(dasdfmt_info_t *info) + static void check_disk(dasdfmt_info_t *info) + { + dasd_information_t dasd_info; +- int ro, errno_save; ++ int ro, errno_save, i = 0; + + if (ioctl(filedes, BLKROGET, &ro) != 0) { + errno_save = errno; +@@ -283,7 +283,7 @@ static void check_disk(dasdfmt_info_t *info) + if (ro) { + ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n"); + } +- ++retry: + if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) { + errno_save = errno; + close(filedes); +@@ -294,8 +294,23 @@ static void check_disk(dasdfmt_info_t *info) + } + + if (!info->force) +- if (dasd_info.open_count > 1) ++ /* ++ * udev strikes again. ++ * Modern udev will issue a 'change' event whenever ++ * a device opened with O_RDWR is closed again. ++ * On the ground that program _might_ have changed ++ * the partition table. ++ * And confusing the hell out ouf anyone else. ++ * Bah. ++ */ ++ if (dasd_info.open_count > 1) { ++ if (i < 5) { ++ ++i; ++ sleep(1); ++ goto retry; ++ } + ERRMSG_EXIT(EXIT_BUSY, "Disk in use!\n"); ++ } + + info->usage_count = dasd_info.open_count; + info->devno = dasd_info.devno; +-- +1.8.4.5 + diff --git a/dasdro b/dasdro new file mode 100644 index 0000000..da7b401 --- /dev/null +++ b/dasdro @@ -0,0 +1,20 @@ +#!/bin/bash +# checks DASD accessibility in VM and sets Linux-side readonly attributes +# accordingly + +modprobe -q vmcp + +vmcp q v dasd 2>/dev/null >/dev/null || exit 0 # not running in VM + +vmcp q v dasd | while read x dev rest +do + dev=`echo $dev|tr A-F a-f` + roattr=/sys/bus/ccw/devices/?.?.$dev/readonly + test -e $roattr || continue + if echo "$rest"|grep -q R/O + then + echo 1 >$roattr + else + echo 0 >$roattr + fi +done diff --git a/detach_disks.sh b/detach_disks.sh new file mode 100644 index 0000000..fdac12d --- /dev/null +++ b/detach_disks.sh @@ -0,0 +1,158 @@ +#!/bin/sh + +COOKIE=$(mcookie) +DASDFILE=/tmp/dasd.list.${COOKIE} +DETFILE=/tmp/detach.disks.${COOKIE} +KEEPFILE=/tmp/keep.disks.${COOKIE} +NICFILE=/tmp/nic.list.${COOKIE} +FAILFILE=/tmp/error.${COOKIE} + +function expand_RANGE(){ +local RANGE=${1} +local RANGE_SAVE=${RANGE} +local DEVNO +local BEGIN=0 +local END=0 + +RANGE=$(IFS=":-"; echo ${RANGE} | cut -f1-2 -d" " ) +set -- ${RANGE} +let BEGIN=0x$1 2>/dev/null +let END=0x$2 2>/dev/null + +if [ ${BEGIN} -eq 0 ] || [ ${END} -eq 0 ]; then + ${msg} "An invalid device number range was specified: ${RANGE_SAVE}" >&2 + touch ${FAILFILE} + return +fi + +for DEVNO in $(eval echo {${BEGIN}..${END}}) + do printf "%d\n" ${DEVNO} + done +} + +function usage(){ + echo "Usage: ${0} [ -F ] [ -q ] [ -h ]" + echo " -F Exit with failure if any invalid parms are detected." + echo " -q Don't generate any output." + echo " -h Display this help message." +} + +msg="echo" +let FORCE_FAIL=0 + +############################################################ +# Parse the parameters from the command line +# +ARGS=$(getopt -a --options Fhq -n "detach_devices" -- "$@") +if [ $? -ne 0 ]; then + usage + exit 3 +fi + +eval set -- "${ARGS}" +for ARG; do + case "${ARG}" in + -F) let FORCE_FAIL=1 + shift 1 + ;; + -h) usage; + exit 0 + ;; + -q) msg="/bin/true" + shift 1 + ;; + --) shift 1 + ;; + *) ${msg} "Extraneous input detected: ${1}" + shift 1 + ;; + esac +done + +if [ -r /etc/sysconfig/virtsetup ]; then + . /etc/sysconfig/virtsetup +else ${msg} "No /etc/sysconfig/virtsetup file was found." + exit 1 +fi + +# First, get a list of all the DASD devices we have for this guest, in decimal. +# (Trying to handle things in hex gets complicated.) +/sbin/vmcp -b1048576 q v dasd | cut -f2 -d" " |\ + while read HEXNO + do let DECNO=0x${HEXNO} + echo ${DECNO} + done > ${DASDFILE} 2>/dev/null + +# If the system administrator specified certain devices to be detached +# let's put those device numbers in a file, one per line. +touch ${DETFILE} +for ADDR in $(IFS=", " ; echo ${ZVM_DISKS_TO_DETACH}) + do if $(echo ${ADDR} | grep -iqE ":|-" 2>/dev/null) + then expand_RANGE ${ADDR} >> ${DETFILE} + else let DEVNO=0 + let DEVNO=0x${ADDR} 2>/dev/null + if [ ${DEVNO} -eq 0 ]; then + ${msg} "An invalid device number was specified: ${ADDR}" >&2 + touch ${FAILFILE} + else printf "%d\n" ${DEVNO} + fi + fi + done > ${DETFILE} + +# If the system administrator specified certain devices that should _not_ +# be detached, let's put those in another file, one per line. +touch ${KEEPFILE} +for ADDR in $(IFS=", " ; echo ${ZVM_DISKS_TO_NOT_DETACH}) + do if $(echo ${ADDR} | grep -iqE ":|-" 2>/dev/null) + then expand_RANGE ${ADDR} >> ${KEEPFILE} + else let DEVNO=0 + let DEVNO=0x${ADDR} 2>/dev/null + if [ ${DEVNO} -eq 0 ]; then + ${msg} "An invalid device number was specified: ${ADDR}" >&2 + touch ${FAILFILE} + else printf "%d\n" ${DEVNO} + fi + fi + done > ${KEEPFILE} + +if [ ${FORCE_FAIL} -eq 1 ] && [ -e ${FAILFILE} ]; then + let RETURN_CODE=1 + ${msg} "Terminating detach_disk because of input errors." +else +# If the system administrator specified that all "unused" disks should be +# detached, compare the disks lsdasd show as activated to the complete +# list of disks we have currently, and add the inactive ones to the +# file containing devices to be detached + if [ "${ZVM_DETACH_ALL_UNUSED}" == "yes" ]; then + lsdasd -s | sed -e 1,2d | cut -f1 -d" " | \ + while read ADDR + do let DEVNO=0x${ADDR} + sed -i -e "/^${DEVNO}$/d" ${DASDFILE} + done + cat ${DASDFILE} >> ${DETFILE} + fi + +# Now remove any "to be kept" disks from the detach file + while read DEVNO + do sed -i -e "/^${DEVNO}/d" ${DETFILE} + done < ${KEEPFILE} + +# Get a list of all the virtual NICs since they require an +# extra keyword to detach. Contrary to what we've done before +# these will be hex values + /sbin/vmcp -b1048576 q nic | grep Adapter | cut -f2 -d" " | cut -f1 -d. > ${NICFILE} + +# Now we sort the device numbers and detach them. + sort -un ${DETFILE} | \ + while read DEVNO + do HEXNO=$(printf %04X ${DEVNO}) + if grep -q ^${HEXNO}$ ${NICFILE} 2>/dev/null ; then + vmcp detach nic ${HEXNO} 2>/dev/null + else vmcp detach ${HEXNO} 2>/dev/null + fi + done + let RETURN_CODE=0 +fi + +rm -f ${DASDFILE} ${DETFILE} ${KEEPFILE} ${NICFILE} ${FAILFILE} +exit ${RETURN_CODE} diff --git a/hsnc b/hsnc new file mode 100644 index 0000000..2de81ec --- /dev/null +++ b/hsnc @@ -0,0 +1,258 @@ +#! /bin/sh +# Copyright (c) 2003 SUSE LINUX AG Nuernberg, Germany. +# +# Please send feedback to http://www.suse.de/feedback/ +# +# /etc/init.d/hsnc +# +# and symbolic its link +# +# /usr/sbin/ip_watcher.pl +# /usr/sbin/xcec-bridge +# /usr/sbin/start_hsnc.sh +# /use/sbin/rchsnc +# +# +# System startup script for the HiperSockets Network Concentrator +# +### BEGIN INIT INFO +# Provides: hsnc +# Required-Start: $network $remote_fs +# Required-Stop: $null +# Default-Start: 3 5 +# Default-Stop: 0 1 6 +# Short-Description: HiperSockets Network Concentrator +# Description: Start the qeth HiperSockets Network Concentrator +### END INIT INFO +# +# +# +# +# +# +# /etc/hsnc.conf should contain the following lines: +# +# operating_mode=[unicast|full|no] +# unicast means, only unicast forwarded between the hsint's and osaint's. +# this is the default mode +# full means, unicast, multicast and broadcast are forwarded, if supported +# by the hardware +# +# hsi_int=" [ [...]]" +# described all the HiperSockets interfaces involved in the HSN +# +# osa_int="" +# describes the OSA interface connecting to other LANs +# + + +START_HSNC_BIN=/usr/sbin/start_hsnc.sh +IP_WATCHER_BIN=/usr/sbin/ip_watcher.pl +XCEC_BRIDGE_BIN=/usr/sbin/xcec-bridge + +HSNC_CONFIG_FILE=/etc/sysconfig/hsnc +HSNC_CLEANUP_FILE=/var/run/hsnc.cleanup + +test -x $START_HSNC_BIN || exit 5 +test -x $IP_WATCHER_BIN || exit 5 +test -x $XCEC_BRIDGE_BIN || exit 5 + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - generic or unspecified error +# 2 - invalid or excess argument(s) +# 3 - unimplemented feature (e.g. "reload") +# 4 - insufficient privilege +# 5 - program is not installed +# 6 - program is not configured +# 7 - program is not running +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signalling is not supported) are +# considered a success. + +#call with cleanup or not +read_config_file() { + if [ "$1" == "cleanup" ]; then + file=$HSNC_CLEANUP_FILE + else + file=$HSNC_CONFIG_FILE + fi + + if [ -s $file ]; then + source $file + else + echo -ne "\nCannot read $file: empty or nonexistant! " + # Means not configured: + return 3 + fi +} + +#call with cleanup or not +set_osa_mode() { +# for full mode, we set up the osa as multicast router. otherwise, no +# special setup is required for the osa. + if [ "$operating_mode" == "full" ]; then + if [ "$1" == "cleanup" ]; then + echo no_router > /sys/class/net/$osa_int/device/route4 + else + echo multicast_router > /sys/class/net/$osa_int/device/route4 + fi + fi +} + +#call with cleanup or not +set_hsi_mode() { +# set all the involved HiperSockets interfaces as primary_connector. For +# special HA setups, some more tweaking is needed, but then a handcarved +# solution should be used anyway. + for i in $hsi_int ; do + if [ "$1" == "cleanup" ]; then + echo no_router > /sys/class/net/$i/device/route4 + else + echo primary_connector > /sys/class/net/$i/device/route4 + fi + done +} + +do_start_hsnc() { + set_osa_mode + set_hsi_mode + if [ "$operating_mode" == "full" ]; then + $IP_WATCHER_BIN --check + else + $IP_WATCHER_BIN --check $osa_int + fi + CODE=$? + if [ $CODE != 0 ]; then + return $CODE + else + cp $HSNC_CONFIG_FILE $HSNC_CLEANUP_FILE + # + # To match the LSB spec, startproc returns 0, + # even if the program it already running. + # + if [ "$operating_mode" == "full" ]; then + startproc $START_HSNC_BIN + else + startproc $START_HSNC_BIN $osa_int + fi + return $? + fi +} + +service="HiperSockets Network concentrator" +case "$1" in + start) + if [ -e /sys/devices/qeth ]; then + echo -n "Starting $service " + else + echo -n "- cannot start $service, no /sys/devices/qeth " + rc_failed 1 + fi + + if checkproc $START_HSNC_BIN; then + # Starting an already running service is success: + echo -n "(already running)" + else + if read_config_file; then + do_start_hsnc + fi + fi + + # Remember status and be verbose + rc_status -v + ;; + stop) + echo -n "Shutting down $service " + + # kill ip_watcher, start_hsnc, which started it needs cleans up + # then: + killproc -TERM $IP_WATCHER_BIN + rc_failed $? + if [ -f $HSNC_CLEANUP_FILE ]; then + read_config_file cleanup + # remove all connector settings(not yet implemented): + set_osa_mode cleanup + set_hsi_mode cleanup + + # remove the file in /var/run + rm -f $HSNC_CLEANUP_FILE + else + echo -n "- no cleanup file found " + fi + + # Remember status and be verbose + rc_status -v + ;; + try-restart) + ## Stop the service and if this succeeds (i.e. the + ## service was running before), start it again. + ## Note: try-restart is not (yet) part of LSB (as of 0.7.5) + $0 status >/dev/null && $0 restart + + # Remember status and be quiet + rc_status + ;; + restart) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + force-reload) + ## start_hsnc.sh does not listen to signals + + echo -n "Force-reload $service " + + $0 stop && $0 start + rc_status + ;; + reload) + ## start_hsnc.sh does not listen to signals + + echo -n "Reload $service: not supported" + + ## it does not support reload: + rc_failed 3 + rc_status -v + ;; + status) + echo -n "Checking $service " + ## Check status with checkproc(8), if process is running + ## checkproc will return with exit status 0. + + # Status has a slightly different for the status command: + # 0 - service running + # 1 - service dead, but /var/run/ pid file exists + # 2 - service dead, but /var/lock/ lock file exists + # 3 - service not running + + # NOTE: checkproc returns LSB compliant status values. + checkproc $START_HSNC_BIN + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart}" + exit 1 + ;; +esac +rc_exit diff --git a/iucv_configure b/iucv_configure new file mode 100644 index 0000000..416389d --- /dev/null +++ b/iucv_configure @@ -0,0 +1,133 @@ +#! /bin/sh +# +# iucv_configure +# +# Configures a z/VM IUCV network adapter +# +# Usage: +# iucv_configure +# +# peer_userid = z/VM userid of the IUCV peer +# online = 0 to take the device offline +# 1 to bring the device online +# +# Return values: +# 1 sysfs not mounted +# 2 Invalid status for +# 3 Could not create iucv device +# 4 Could not remove iucv device +# + +if [ "${DEBUG}" != "yes" ]; then + DEBUG="no" +fi + +mesg () { + echo "$@" +} + +debug_mesg () { + case "$DEBUG" in + yes) mesg "$@" ;; + *) ;; + esac +} + +if [ $# -ne 2 ] ; then + echo "Usage: $0 " + echo " peer_userid = z/VM userid of the IUCV peer" + echo " online = 0 to take the device offline" + echo " 1 to bring the device online" + exit 1 +fi + +# Get the mount point for sysfs +while read MNTPT MNTDIR MNTSYS MNTTYPE; do + if test "$MNTSYS" = "sysfs"; then + SYSFS="$MNTDIR" + break; + fi +done $_iucv_drv/connection + if [ $? -ne 0 ] ; then + mesg "Unable to connect to $PEER_USERID" + exit 3 + fi + for _iucv_dev in $_iucv_dir/netiucv?* ; do + [ -d $_iucv_dev ] || continue + read user < $_iucv_dev/user + if [ "$user" = "$PEER_USERID" ] ; then + iucvdev=${_iucv_dev##*/} + break; + fi + done + if [ "$iucvdev" ] ; then + debug_mesg "Configured device $iucvdev" + fi +elif [ "$iucvdev" -a $ONLINE -eq 0 ] ; then + for _net_dev in $_iucv_dir/$iucvdev/net/* ; do + [ -d $_net_dev ] || continue + netdev=${_net_dev##*/} + break; + done + if [ "$netdev" ] ; then + echo $netdev > $_iucv_drv/remove + if [ $? -ne 0 ] ; then + mesg "Unable to remove device $netdev" + exit 4 + else + debug_mesg "Removed device $iucvdev" + rm -f /etc/udev/rules.d/51-iucv-$PEER_USERID.rules /etc/udev/rules.d/51-iucv-$PEER_USERID_LOWER.rules + iucvdev= + fi + fi + +fi + +if [ "$iucvdev" ] ; then + cat > /etc/udev/rules.d/51-iucv-$PEER_USERID.rules <.rules +.RS +This file provide the udev rules necessary to activate a specific IUCV adapter. +.RE +.SH ENVIRONMENT +.IP DEBUG +If set to "yes" some minimal debugging information is output during execution. +.SH DIAGNOSTICS +The following messages may be issued on stdout: +.IP +.B /sysfs not present +.RS +The sysfs file system could not be found in /proc/mounts, so there's nothing the script can +do. Return code 1 is set. +.RE +.IP +.B No IUCV user name given +.RS +You didn't specify the z/VM userid of the virtual machine to which you want to connect. Return code 2 is set. +.RE +.IP +.B Unable to connect to $PEER_USERID +.RS +The attempt to connect to the IUCV peer failed. Try "dmesg" to see if there is any indication why. Return code 3 is set. +.RE +.IP +.B Unable to remove device $netdev +.RS +The attempt to remove the IUCV adapter failed. Try "dmesg" to see if there is any indication why. Return code 4 is set. +.RE + +If environment variable DEBUG is set to "yes," the following messages may be issued on stdout: +.IP +.B +Configuring IUCV device ${PEER_USERID} +.RS +Just a little bit of verbosity, since it just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B Configured device $iucvdev +.RS +The attempt to create the IUCV adapter was successful. +.RE +.IP +.B Removed device $iucvdev +.RS +The attempt to remove the IUCV adapter was successful. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. diff --git a/killcdl b/killcdl new file mode 100644 index 0000000..1bdf61b --- /dev/null +++ b/killcdl @@ -0,0 +1,217 @@ +#!/bin/sh + +# +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Released under the GNU General Public License version 2. +# + +let FORCE=0 +DEVPARM="" + +usage(){ + echo "Usage: ${0} [ -f ] devno|busid" + echo " -f Force unformatting for DASD volumes in the CMS device range of 19x." + echo " devno The \"plain\" device number of the volume, e.g. 3184." + echo " busid The full specification of the volume, e.g., 0.0.3184." +} + +ARCH="$(/bin/uname -m)" +if [ "${ARCH}" != "s390x" ] && [ "${ARCH}" != "s390" ]; then + echo "This script is only useful on IBM mainframes." + exit 1 +fi + +############################################################ +# Parse the parameters from the command line +# +ARGS=$(getopt -a --options f -n "killcdl" -- "$@") +if [ $? -ne 0 ]; then + usage + exit 3 +fi + +eval set -- "${ARGS}" +for ARG; do + case "${ARG}" in + -f) FORCE=1 + shift 1 + ;; + --) shift 1 + ;; + [0-9a-fA-F]*) if [ ! -z "${DEVPARM}" ]; then + echo "More than one parameter specified." + usage + exit 4 + fi + DEVPARM=${1} + shift 1 + ;; + *) echo "That looks invalid" + usage + exit 5 + ;; + esac +done + +if [ -z "${DEVPARM}" ]; then + echo "You must specify the device number of the DASD volume to be unformatted." + usage + exit 6 +fi + +DEVNO=$(echo "${DEVPARM}" | tr A-Z a-z) + +# Validate the device number or busid provided +set -- $(IFS='.'; echo ${DEVNO}) +let NUMPARMS=${#} +if [ ${NUMPARMS} -ne 1 ] && [ ${NUMPARMS} -ne 3 ]; then + echo "You have not specified the device number in a recognizable format." + echo "It must either be the plain device number, e.g., 0123, or in" + echo "so-called busid format, e.g., 0.0.0123" + exit 7 +fi + +# Just a device number, SIMPLE=1. A busid, SIMPLE=0 +SIMPLE=0 +if [ ${NUMPARMS} -eq 1 ]; then + let SIMPLE=1 + let FIRST=0 + let FIRSTLEN=1 + let SECOND=0 + let SECONDLEN=1 + DEVNO="${1}" + let DEVNOLEN=${#1} +else FIRST="${1}" + let FIRSTLEN=${#FIRST} + SECOND="${2}" + let SECONDLEN=${#SECOND} + DEVNO="${3}" + let DEVNOLEN=${#3} +fi + +if [ ${FIRSTLEN} -ne 1 ] || [ ${SECONDLEN} -ne 1 ]; then + echo "The first and second fields of the busid may only be one digit long." + exit 8 +fi + +if [ ${DEVNOLEN} -gt 4 ]; then + echo "The device number may only be 4 digits long." + exit 9 +fi + +if [ ${DEVNOLEN} -lt 4 ]; then + DEVNO=$(echo "0000${DEVNO}" | rev | cut -c1-4 | rev) +fi + +BUSID="${FIRST}.${SECOND}.${DEVNO}" + +if [ ! -h /sys/bus/ccw/devices/${BUSID} ]; then + echo "Busid ${BUSID} was not found." + /sbin/cio_ignore -i ${BUSID} > /dev/null + if [ $? -eq 0 ]; then + echo "That device is in the cio_ignore list." + echo "Please remove it with \"cio_ignore -r ${BUSID}\" before trying again." + fi + exit 10 +fi + +case ${DEVNO:0:3} in + 019) if grep -q "version = FF" /proc/cpuinfo 2>/dev/null; then + echo "That looks like a CMS disk." + if [ ${FORCE} -eq 0 ]; then + echo "Specify the -f option to force the operation." + exit 11 + fi + echo "But you specified -f so we'll kill it anyway." + fi + ;; +esac + +read ORIG_ONLINE_STATUS < /sys/bus/ccw/devices/${BUSID}/online + +DISCIPLINE="none" +if [ -r /sys/bus/ccw/devices/${BUSID}/discipline ]; then + # We have to bring the device online before the kernel will fill in + # the value for discipline. + if [ ${ORIG_ONLINE_STATUS} -eq 0 ]; then + /sbin/chccwdev -e ${BUSID} + /sbin/udevadm settle + fi + + read STATUS < /sys/bus/ccw/devices/${BUSID}/status + if [ "${STATUS}" == "unformatted" ]; then + echo "DASD device ${BUSID} is already in an unformatted state." + if [ ${ORIG_ONLINE_STATUS} -eq 0 ]; then + /sbin/chccwdev -d -s ${BUSID} + /sbin/udevadm settle + fi + exit 0 + fi + + read DISCIPLINE < /sys/bus/ccw/devices/${BUSID}/discipline +else read CU_TYPE < /sys/bus/ccw/devices/${BUSID}/cutype + read DEV_TYPE < /sys/bus/ccw/devices/${BUSID}/devtype + case "${CU_TYPE}" in + 3990/*|2105/*|2107/*|1750/*|9343/*) + DISCIPLINE=ECKD + ;; + 3880/*) + case "${DEV_TYPE}" in + 3390/*) + DISCIPLINE=ECKD + ;; + esac + ;; + esac +fi + +if [ "${DISCIPLINE}" != "ECKD" ]; then + echo "This script only works on ECKD DASD." + if [ ${ORIG_ONLINE_STATUS} -eq 0 ]; then + /sbin/chccwdev -d -s ${BUSID} + fi + exit 12 +fi + +read STATUS < /sys/bus/ccw/devices/${BUSID}/online +if [ ${STATUS} -eq 1 ]; then + if [ ! -h /dev/disk/by-path/ccw-${BUSID} ]; then + echo "The udev-generated symbolic link in /dev/disk/by-path was not found." + exit 13 + fi + + /sbin/chccwdev -d -s ${BUSID} + /sbin/udevadm settle + + read STATUS < /sys/bus/ccw/devices/${BUSID}/online + if [ ${STATUS} -ne 0 ]; then + echo "Device number ${DEVNO} didn't go offline. Unable to continue." + exit 14 + fi +fi + +/sbin/chccwdev -a raw_track_access=1 -e ${BUSID} +/sbin/udevadm settle + +read STATUS < /sys/bus/ccw/devices/${BUSID}/online +if [ ${STATUS} -ne 1 ]; then + echo "Unable to bring ${DEVNO} online. Unable to continue." + exit 15 +fi + +# After this point, we will kill the formatting on the device +perl -e 'for ($h=0;$h<2;$h++){printf "\0\0\0%c\0\0\0\x8%s",$h,(("\0"x8).("\xff"x8).("\0"x65512))}' | dd bs=65536 count=2 oflag=direct of=/dev/disk/by-path/ccw-${BUSID} >/dev/null 2>&1 + +if [ "$?" -ne 0 ]; then + echo "The writing of the null record 0 failed." + exit 16 +fi + +echo "Setting ${BUSID} back offline with raw track access disabled." +/sbin/chccwdev -d -s -a raw_track_access=0 ${BUSID} +/sbin/udevadm settle + +if [ ${ORIG_ONLINE_STATUS} -eq 1 ]; then + /sbin/chccwdev -e ${BUSID} + /sbin/udevadm settle +fi diff --git a/lgr_check b/lgr_check new file mode 100644 index 0000000..5e691df --- /dev/null +++ b/lgr_check @@ -0,0 +1,335 @@ +#!/bin/sh + +function check_sysoper(){ +local SYSOPER=$(vmcp q sysoper | cut -f4 -d" ") +local USERID=$(vmcp q userid | cut -f1 -d" ")"." +if [ "${SYSOPER}" == "${USERID}" ]; then +return 0 +else return 1 +fi +} + +function check_disc(){ +local USERID=$(vmcp q userid | cut -f1 -d" ") +local DISCONNECTED=$(vmcp q ${USERID} | cut -f2 -d-) +if [ "${DISCONNECTED}" == " DSC" ]; then + return 1 +else return 0 +fi +} + +function check_3270(){ +local CONMODE=$(vmcp q term | sed -n -e '/CONMODE/ {s/CONMODE \([0-9]*\), .*$/\1/;p}') +if [ "${CONMODE}" == "3270" ]; then + return 0 +else return 1 +fi +} + +function check_graf(){ +local GRAF +GRAF=$(vmcp -b 1048576 q v graf 2>/dev/null | grep -v "^CONS" | grep "ON LDEV" ) +if [ ${?} -eq 0 ] && [ -n "${GRAF}" ]; then + return 0 +else return 1 +fi +} + +function check_ascii_console(){ +local SYSASCII=$(vmcp q v sysascii 2>/dev/null | grep "not attached to you") +if [ -z "${SYSASCII}" ]; then + return 0 +else return 1 +fi +} + +function check_tdisk(){ +local TDISK=$(vmcp -b 1048576 q v dasd 2>/dev/null | grep TEMP) +if [ -n "${TDISK}" ]; then + return 0 +else return 1 +fi +} + +function check_ctc(){ +local CTC +CTC=$(vmcp -b 1048576 q v ctc 2>/dev/null) +if [ ${?} -eq 0 ]; then + return 0 +else return 1 +fi +} + +function check_dynamic_switch(){ +local SWCH +SWCH=$(vmcp -b 1048576 q v switches 2>/dev/null) +if [ ${?} -eq 0 ]; then + return 0 +else return 1 +fi +} + +function check_maint_mdisks(){ +local MDISKS +MDISKS=$(vmcp -b 1048576 q v dasd | grep -E "0190|0191|0193|019D|019E") +if [ -n "${MDISKS}" ]; then + return 0 +else return 1 +fi +} + +function check_wrkalleg(){ +local WRKALLEG +WRKALLEG=$(vmcp -b 1048576 q wrkalleg | grep "is not simulated") +if [ -z "${WRKALLEG}" ]; then + return 0 +else return 1 +fi +} + +function check_isolated_vswitch(){ +local ISOLATED=0 +local VSWITCH + +# Find out if we have any NICs coupled to any VSWITCH or not. If not, we're OK. +VSWITCH=$(vmcp -b 1048576 q nic | sed -e '1~2 {N;s/\n//;}' | grep VSWITCH) +if [ -z "${VSWITCH}" ]; then + return 1 +fi + +ISOLATED=$(vmcp -b 1048576 q nic | sed -e '1~2 {N;s/\n//;}' | \ + grep VSWITCH | \ + sed -e 's/^.* VSWITCH: //' | \ + while read owner name + do VSWITCH=$(vmcp -b 1048576 q vswitch $name | grep RDEV) + if [ -z "${VSWITCH}" ]; then + echo 1 + fi + done) + +if [ "${ISOLATED}" == "1" ]; then + return 0 +else return 1 +fi +} + +function check_chpidvirt(){ +local CHPIDV +CHPIDV=$(vmcp q chpidv 2>/dev/null | grep "CHPID Virtualization is on") +if [ -z "${CHPIDV}" ]; then + return 0 +else return 1 +fi +} + +function check_pci_functions(){ +local PCIF +local RETCODE +PCIF=$(vmcp -b 1048576 q v pcif 2>/dev/null | grep "A PCI function was not found.") +RETCODE=${?} +if [ ${RETCODE} -eq 0 ] && [ -z "${PCIF}" ]; then + return 0 +else return 1 +fi +} + +function check_tape_assign(){ +local TAPES +local RETCODE=1 +TAPES=$(vmcp -b 1048576 q v tapes 2>/dev/null | grep "Device TAPE does not exist") +if [ -n "${TAPES}" ]; then + return 1 +fi + +TAPES=$(vmcp -b 1048576 q v tapes 2>/dev/null | grep "NOASSIGN") +if [ -n "${TAPES}" ]; then + return 0 +else return 1 +fi +} + +function check_open_spool(){ +local QSPOOL +local OPENSPOOL=0 +QSPOOL=$(vmcp -b 1048576 q pun \* all 2>/dev/null | grep "OPEN") +if [ -n "${QSPOOL}" ]; then + let OPENSPOOL=1 +fi + +QSPOOL=$(vmcp -b 1048576 q prt \* all 2>/dev/null | grep "OPEN" | grep -v " CON ") +if [ -n "${QSPOOL}" ]; then + let OPENSPOOL=1 +fi + +if [ ${OPENSPOOL} -eq 1 ]; then + return 0 +else return 1 +fi +} + +function check_xstore(){ +local XSTOR +XSTOR=$(vmcp -b 1048576 q v xstor 2>/dev/null | grep "XSTORE = none") +if [ -z "${XSTOR}" ]; then + return 0 +else return 1 +fi +} + +function check_iucv(){ +local QIUCV +QIUCV=$(vmcp -b 1048576 q iucv 2>/dev/null | grep -vE "^No IUCV paths exist|^Source| *MSG| *MSGALL") +if [ -n "${QIUCV}" ]; then + return 0 +else return 1 +fi +} + +function usage(){ + echo "Usage: ${0} [ -f ] [ -h ] devno|busid" + echo " -q Don't generate any output, just set a return code." + echo " -m Suppress the check for local minidisks." + echo " Only use this if you know for certain all minidisks for this" + echo " guest are NOT local to this instance of z/VM." + echo " -h Display this help message." +} + +ARCH="$(/bin/uname -m)" +if [ "${ARCH}" != "s390x" ] && [ "${ARCH}" != "s390" ]; then + echo "This script is only useful on IBM mainframes." + exit 1 +fi + +HYPERVISOR=$(systemd-detect-virt) +if [ "${HYPERVISOR}" != "zvm" ]; then + echo "This script is only useful for guests of the z/VM hypervisor." + exit 1 +fi + +MDISK_SUPPRESS=0 +msg="echo" + +############################################################ +# Parse the parameters from the command line +# +ARGS=$(getopt -a --options qhm -n "lgr_check" -- "$@") +if [ $? -ne 0 ]; then + usage + exit 3 +fi + +eval set -- "${ARGS}" +for ARG; do + case "${ARG}" in + -h) usage; + exit 0 + ;; + -m) let MDISK_SUPPRESS=1; + shift 1 + ;; + -q) msg="/bin/true" + shift 1 + ;; + --) shift 1 + ;; + *) ${msg} "Extraneous input detected: ${1}" + shift 1 + ;; + esac +done + + +let FAIL=0 +##let COLS=$(stty -a | sed -n -e '/columns/{s/^.*columns \([0-9]*\);.*$/\1/;p}') + +if [ ! -c /dev/vmcp ]; then + ${msg} "Cannot find /dev/vmcp to issue z/VM CP commands." + exit 1 +fi + +${msg} "Checking for conditions that might prevent Live Guest Relocation" + +if check_chpidvirt; then + ${msg} "This guest does not have CHPID Virtualization set for it in the CP directory." + ${msg} "Live Guest Relocation is absolutely not possible for this guest." + # exit 99 + let FAIL=1 +fi +if check_sysoper ; then + ${msg} "This guest is currently the z/VM system operator." + let FAIL=1 +fi +let GUEST_CONN=0 +if check_disc; then + ${msg} "The guest is not running disconnected." + let GUEST_CONN=1 + let FAIL=1 +fi +if check_3270; then + ${msg} -n "The guest has a 3270 console, " + if [ ${GUEST_CONN} -eq 0 ]; then + ${msg} "but it is not currently in use." + else ${msg} "and it is currently in use." + let FAIL=1 + fi +fi +if check_graf; then + ${msg} "The guest has a DIALED 3270 device in current use." + let FAIL=1 +fi +if check_ascii_console; then + ${msg} "The guest has the ASCII console attached to it." + let FAIL=1 +fi +if check_tdisk; then + ${msg} "The guest has a temporary disk (T-disk) attached to it." + let FAIL=1 +fi +if check_ctc; then + ${msg} "The guest has a Channel-to-Channel device (CTC) attached to it." + let FAIL=1 +fi +if check_dynamic_switch; then + ${msg} "The guest has a dynamic switching device attached to it." + let FAIL=1 +fi +if check_wrkalleg; then + ${msg} "The guest is currently using virtual working allegiance." + let FAIL=1 +fi +if [ ${MDISK_SUPPRESS} -eq 0 ] && check_maint_mdisks; then + ${msg} "The guest currently has one or more Minidisks that might be local to this instance of z/VM." + let FAIL=1 +fi +if check_isolated_vswitch; then + ${msg} "The guest is currently coupled to an isolated VSWITCH." + let FAIL=1 +fi +if check_pci_functions; then + ${msg} "The guest has PCI functions available to it." + let FAIL=1 +fi +if check_tape_assign; then + ${msg} "The guest has potential problems with a tape." + let FAIL=1 +fi +if check_open_spool; then + ${msg} "The guest has an open SPOOL file that is not from the virtual console." + let FAIL=1 +fi +if check_xstore; then + ${msg} "The guest has Expanded Storage attached to it." + let FAIL=1 +fi +if check_iucv; then + ${msg} "The guest has an IUCV connection to a z/VM system service or another z/VM user." + let FAIL=1 +fi + +if [ ${FAIL} == 1 ]; then + ${msg} "The guest is currently not eligible for Live Guest Relocation." + exit 1 +else ${msg} "As far as can be determined from within the guest, it is currently eligible for Live Guest Relocation." + ${msg} "This is not a guarantee. Other factors that cannot be checked from within the guest may prevent it from being eligible for LGR." +fi + diff --git a/mkdump.8 b/mkdump.8 new file mode 100644 index 0000000..a1335af --- /dev/null +++ b/mkdump.8 @@ -0,0 +1,72 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36. +.TH MKDUMP "8" "August 2011" "mkdump 2.0" "System Administration Utilities" +.SH NAME +mkdump \- Preparing disks for use as S/390 dump device. +.SH SYNOPSIS +.B mkdump +[\fIOPTIONS\fR] [\fIDEVICE\fR]... +.SH DESCRIPTION +mkdump 2.0.2 +.PP +Prepare one or more volumes for use as S/390 dump device. Supported devices +are ECKD DASD and SCSI over zFCP disks, while multi\-volumes are limited to DASD. +.PP +Only whole disks can be used, no partitions! If the device is incompatible +formatted/partioned, the script will refuse to install the dump record +unless the \fB\-\-force\fR switch is given. +.PP +Disks which are in use or have mounted partitions will not be listed and can't be used. +The mentioning of "dumpdevice" after a disk indicates that it is an already usable dump device. Additionally multi\-volume dump devices are indicated by the list of including DASD ids. +.SH OPTIONS +.TP +\fB\-h\fR, \fB\-\-help\fR +display this help and exit +.TP +\fB\-V\fR, \fB\-\-version\fR +display version information and exit +.TP +\fB\-d\fR, \fB\-\-debug\fR +debug mode, do not run programs which commit changes +.TP +\fB\-v\fR, \fB\-\-verbose\fR +be verbose and show command outputs +.TP +\fB\-f\fR, \fB\-\-force\fR +force overwrite of the disk +.TP +\fB\-l\fR, \fB\-\-list\-dump\fR +display dump disks +.TP +\fB\-D\fR, \fB\-\-list\-dasd\fR +display usable DASD disks (Device, Size, ID, Dump) +.TP +\fB\-Z\fR, \fB\-\-list\-zfcp\fR +display usable SCSI over zFCP disks (Device, Size, ID, WWPN, LUN, Dump) +.SH DIAGNOSTICS +mkdump returns the following exit codes: +.RS +.IP 0 +Normal (no errors or warnings detected) +.IP 11 +Invalid or unusable disk (fatal) +.IP 12 +Incompatible formatting/partitioning, can be corrected with --force +.IP 13 +Missing support programs +.IP 14 +Bad command line parameters +.IP 15 +Access problem +.IP other +Support program failed +.SH AUTHOR +Written by Tim Hardeck . +.SH "REPORTING BUGS" +Report bugs on https://bugzilla.novell.com/ +.SH COPYRIGHT +Copyright \(co 2011 SUSE LINUX Products GmbH +License GPLv2 or (at your option) any later version. + +.br +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. diff --git a/mkdump.pl b/mkdump.pl new file mode 100644 index 0000000..b69a4ac --- /dev/null +++ b/mkdump.pl @@ -0,0 +1,584 @@ +#!/usr/bin/perl +######################################################################## +# +# mkdump.pl - Preparing disks for use as S/390 dump device +# +# Copyright (c) 2011 Tim Hardeck, SUSE LINUX Products GmbH +# bases on mkdump.sh (c) 2004 Hannes Reinecke, SuSE AG +# +# License: +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +######################################################################## + +use strict; +use warnings; +use Fcntl; +use Getopt::Long; + +my $VERSION = "2.0.2"; + +my $BLKID = "/sbin/blkid"; +my $PARTED = "/usr/sbin/parted"; +my $FDASD = "/sbin/fdasd"; +my $DASDVIEW = "/sbin/dasdview"; +my $DASDFMT = "/sbin/dasdfmt"; +my $ZIPL = "/sbin/zipl"; +my $UDEVADM = "/sbin/udevadm"; +my $ZGETDUMP = "/sbin/zgetdump"; + +my $MNTPOINT = "/var/run/mkdump." . getppid(); +# temporary DASD device configuration file for Zipl +my $MDPATH = "/tmp/mvdump.conf"; +# zFCP dump dir, without a leading '/' +my $ZFCP_DUMP_DIR = "mydumps"; + +my $OPT_DEBUG = 0; +my $OPT_FORCE = 0; +my $OPT_VERBOSE = 0; + +sub cleanup +{ + # DASD + if (-e $MDPATH) { + system("rm -f $MDPATH"); + } + # zFCP + if (-d $MNTPOINT) { + system("umount $MNTPOINT"); + system("rmdir $MNTPOINT"); + } +} + +sub exit_with +{ + my $message = shift(); + my $exitcode = shift(); + + print STDERR "$message Exiting...\n"; + cleanup(); + + # fdasd isn't able to create volume label interactively + # could be fixed with a reformat + if ($exitcode == 65280) { + $exitcode = 12; + } + + # bigger exit codes are not supported + if ($exitcode > 255) { + $exitcode = 255; + } + + exit($exitcode); +} + +sub run_cmd +{ + my $cmd = shift(); + + my $output = ""; + if (! $OPT_DEBUG) { + my ($app) = $cmd =~ /\/(\w+) /; + + # run command + $output = `$cmd`; + my $exit_code = $?; + # wait for udev to finish processing + system("$UDEVADM settle"); + + # only print output in case of an error or in verbose mode + if ($output and ($exit_code != 0 or $OPT_VERBOSE)) { + print("$output\n"); + } + + if ($exit_code != 0) { + exit_with("$app failed with exit code $exit_code", $exit_code); + } + } else { + # only print the command in debug mode + print("\`$cmd\`\n"); + } + return($output); +} + +sub check_paths +{ + for my $path ($BLKID, $PARTED, $FDASD, $DASDVIEW, $DASDFMT, $ZIPL, $UDEVADM, $ZGETDUMP) { + unless ( -x $path) { + exit_with("Command $path is not available.", 13); + } + } +} + +sub read_file +{ + my $path = shift(); + + open(my $file, "<", "$path") or exit_with("Unable to access $path: $!.", 15); + my @content = <$file>; + close($file); + + # no need for arrays in case of single lines + if (@content > 1) { + return @content; + } else { + chomp($content[0]); + return($content[0]); + } +} + +sub is_dasd +{ + # remove leading /dev/ + my $device = substr(shift(), 5); + + if (-r "/sys/block/$device/device/discipline") { + return(1); + } else { + return(0); + } +} + +sub is_zfcp +{ + # remove leading /dev/ + my $device = substr(shift(), 5); + my $devpath = "/sys/block/$device/device"; + + unless (-r "$devpath/hba_id" or -r "$devpath/type") { + return(0); + } + + my $devtype = read_file("$devpath/type"); + + # SCSI type '0' means disk + if ($devtype == 0) { + return(1); + } else { + return(0); + } +} + +sub get_partition_num +{ + # remove leading /dev/ + my $device = substr(shift, 5); + + my $part_num = grep(/\s+$device\d+/, read_file("/proc/partitions")); + + return($part_num); +} + +sub print_device +{ + my $device = shift(); + my $only_dump_disks = shift(); + + my $devpath = "/sys/block/" . substr($device, 5); + my $output = $device; + my $dump_device = 0; + + my $size = int(read_file("$devpath/size") / 2048); # 512 Byte blocks + # size can't be read this way in case of unformatted devices + if ($size != 0) { + $output .= "\t${size}MB"; + } else { + $output .= "\tunknown"; + } + + if (is_dasd($device)) { + my ($busid) = readlink("$devpath/device") =~ /(\w\.\w\.\w{4})/; + $output .= "\t$busid"; + + # check for dump record and list multi volumes + my $zgetdump_output = `$ZGETDUMP -d $device 2>&1`; + my @dump_devs = $zgetdump_output =~ /(\w\.\w\.\w{4})/g; + if (@dump_devs) { + $dump_device = 1; + $output .= "\tdumpdevice"; + # no need to output the dump ids for a single device + if (@dump_devs > 1) { + for my $id (@dump_devs) { + $output .= "|$id"; + } + } + } else { + # check for single volume dump devices + if ($zgetdump_output =~ /Single-volume DASD dump tool/) { + $dump_device = 1; + $output .= "\tdumpdevice"; + } + } + } else { + my $adapter = read_file("$devpath/device/hba_id"); + my $wwpn = read_file("$devpath/device/wwpn"); + my $lun = read_file("$devpath/device/fcp_lun"); + $output .= "\t$adapter\t$wwpn\t$lun"; + + # check for dump record + system("mkdir -p $MNTPOINT"); + if (get_partition_num($device) == 1 and system("mount -o ro ${device}1 $MNTPOINT 2>/dev/null") == 0) { + if ( -r "$MNTPOINT/bootmap" and -d "$MNTPOINT/$ZFCP_DUMP_DIR") { + $dump_device = 1; + $output .= "\tdumpdevice"; + } + system("umount $MNTPOINT"); + } + system("rmdir $MNTPOINT"); + } + if ($only_dump_disks) { + if ($dump_device) { + print("$output\n"); + } + } else { + print("$output\n"); + } +} + +sub list_free_disks +{ + my $devices_ref = shift(); + my $type = shift(); + + if (@$devices_ref) { + for my $device (@$devices_ref) { + print_device($device); + } + } else { + print STDERR "No free $type devices available!\n"; + } +} + +sub list_dump_disks +{ + my @devices = @_; + + if (@devices) { + for my $device (@devices) { + print_device($device, 1); + } + } else { + print STDERR "No dump devices available!\n"; + } +} + +sub determine_free_disks +{ + my @dasd; + my @zfcp; + my @devices; + + # gather block devices + my $path="/sys/block/"; + opendir(DIR, $path) or exit_with("Unable to find $path: $!", 15); + while (defined(my $file = readdir(DIR))) { + # no need to add other devices then dasd* or sd* + if ($file =~ /^dasd[a-z]+$/ or $file =~ /^sd[a-z]+$/) { + push(@devices, $file); + } + } + closedir(DIR); + + for my $entry (@devices) { + # only allow disks, no partitions + my ($device) = $entry =~ /^([a-z]+)$/; + next unless ($device); + + $device = "/dev/$device"; + + # determine if the block device could be accessed exclusively + if(-b $device and sysopen(my $blockdev, $device, O_RDWR|O_EXCL)) { + close($blockdev); + if (is_dasd($device)) { + push(@dasd, $device); + } + if (is_zfcp($device)) { + push(@zfcp, $device); + } + } + } + + return(\@dasd, \@zfcp); +} + +sub prepare_dasd +{ + my @devices = @_; + + my $format_disks = ""; + + # check formatting + for my $device (@devices) { + # determine disk layout + my ($fmtstr) = `$DASDVIEW -x -f $device` =~ /(\w\w\w) formatted/; + + SWITCH: + for($fmtstr) { + if (/NOT/) { + print("Unformatted disk, formatting $device.\n"); + $format_disks .= " $device"; + last SWITCH; + } + if (/LDL/) { + if ($OPT_FORCE) { + print("Linux disk layout, reformatting $device.\n"); + $format_disks .= " $device"; + } else { + print("$device was formatted with the Linux disk layout.\n"); + print("Unable to use it without reformatting.\n"); + exit_with("Re-issue the mkdump command with the --force option.", 12); + } + last SWITCH; + } + if (/CDL/) { + # allow reformatting with force, since fdasd isn't able to create volume label interactively + if ($OPT_FORCE) { + print("Compatible disk layout, force reformatting $device.\n"); + $format_disks .= " $device"; + } else { + print("$device: Compatible disk layout, Ok to use.\n"); + } + last SWITCH; + } + exit_with("Unknown layout ($fmtstr), cannot use disk.", 11); + } + } + + # format devices + if ($format_disks) { + #up to eight devices in parallel + run_cmd("$DASDFMT -P 8 -b 4096 -y -f $format_disks"); + } + + # check partitioning and partition + for my $device (@devices) { + my $part_num = get_partition_num($device); + if ($part_num == 0 or $OPT_FORCE) { + print("Re-partitioning disk $device.\n"); + run_cmd("$FDASD -a $device"); + } else { + # allow disk with one partition if it don't consist a file system + if ($part_num == 1) { + my ($fstype) = `$BLKID ${device}1` =~ /TYPE=\"(\w+)\"/; + if ($fstype) { + exit_with("Device ${device}1 already contains a filesystem of type $fstype.", 12); + } + } else { + exit_with("$part_num partitions detected, cannot use disk $device.", 12); + } + } + } +} + +sub setup_dasddump +{ + my @devices = @_; + + prepare_dasd(@devices); + + # create zipl device configuration file + my $md_path = "/tmp/mvdump.conf"; + + # don't create files in debug mode + unless ($OPT_DEBUG) { + open(my $file, ">", $md_path) or exit_with("Unable to access $md_path: $!.", 15); + for my $device (@devices) { + print{$file}("${device}1\n"); + } + close($file); + } + + print("Creating dump record.\n"); + run_cmd("${ZIPL} -V -n -M $md_path"); + + cleanup(); +} + +sub setup_zfcpdump +{ + my $device = shift(); + + # check partitioning + my $part_num = get_partition_num($device); + if ($part_num == 0 or $OPT_FORCE) { + print("Re-partitioning disk $device.\n"); + run_cmd("$PARTED -s -- $device mklabel gpt mkpart primary 0 -1"); + } else { + if ($part_num > 1) { + exit_with("$part_num partitions detected, cannot use disk $device.", 12); + } + } + + # install bootloader + print("Creating dump record.\n"); + run_cmd("${ZIPL} -V -d ${device}1"); + + cleanup(); +} + +sub print_version +{ + print << "EOF"; +mkdump $VERSION + +Copyright (c) 2011 SUSE LINUX Products GmbH +License GPLv2 or (at your option) any later version. + +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Written by Tim Hardeck . +EOF + exit(0); +} + +sub print_usage +{ + my $exitcode = shift(); + + print << "EOF"; +Usage: mkdump [OPTIONS] [DEVICE]... +mkdump $VERSION + +Prepare one or more volumes for use as S/390 dump device. Supported devices +are ECKD DASD and SCSI over zFCP disks, while multi-volumes are limited to DASD. + +Only whole disks can be used, no partitions! If the device is incompatible +formatted/partioned, the script will refuse to install the dump record +unless the --force switch is given. + +Disks which are in use or have mounted partitions will not be listed and can't be used. +The mentioning of "dumpdevice" after a disk indicates that it is an already usable dump device. Additionally multi-volume dump devices are indicated by the list of including DASD ids. + +Options: + -h, --help display this help and exit + -V, --version display version information and exit + + -d, --debug debug mode, do not run programs which commit changes + -v, --verbose be verbose and show command outputs + -f, --force force overwrite of the disk + + -l, --list-dump display dump disks + -D, --list-dasd display usable DASD disks (Device, Size, ID, Dump) + -Z, --list-zfcp display usable SCSI over zFCP disks (Device, Size, ID, WWPN, LUN, Dump) + +Report bugs on https://bugzilla.novell.com/ +EOF + + exit($exitcode); +} + +sub analyze_cmd_parameters +{ + #verbose, debug and force are global + my $opt_help = 0; + my $opt_version = 0; + my $opt_dump = 0; + my $opt_dasd = 0; + my $opt_zfcp = 0; + + if (@ARGV == 0) { + print_usage(14); + } + + Getopt::Long::Configure('bundling'); + GetOptions( + 'h|help' => \$opt_help, + 'V|version' => \$opt_version, + 'd|debug' => \$OPT_DEBUG, + 'v|verbose' => \$OPT_VERBOSE, + 'f|force' => \$OPT_FORCE, + 'l|list-dump' => \$opt_dump, + 'D|list-dasd' => \$opt_dasd, + 'Z|list-zfcp' => \$opt_zfcp, + ) or print_usage(14); + + if ($opt_help) { + print_usage(0); + } + + if ($opt_version) { + print_version(); + } + + # determine free dasd and zfcp devices + my ($dasd_ref, $zfcp_ref) = determine_free_disks(); + + if ($opt_dump) { + list_dump_disks(@$dasd_ref, @$zfcp_ref); + exit 0; + } + + if ($opt_dasd) { + list_free_disks(\@$dasd_ref, "dasd"); + } + + if ($opt_zfcp) { + list_free_disks(\@$zfcp_ref, "zfcp"); + } + + # allow listing of both device types at the same time + if ($opt_dasd or $opt_zfcp) { + exit 0; + } + + # check provided devices and be strict + my @devices; + for my $device (@ARGV) { + if (grep(/$device/, @devices)) { + exit_with("$device is mentioned more than once.", 14); + } + if ( $device =~ /^\/dev\/[a-z]+$/ == 0) { + exit_with("The device parameter $device is inaccurate. Only whole disks are allowed.", 14); + } + if (grep(/$device/, (@$dasd_ref, @$zfcp_ref))) { + if (is_zfcp($device) and @ARGV > 1) { + exit_with("Multi-volume dumps aren't supported with zFCP.", 14); + } + push(@devices, $device); + } else { + if (-b $device) { + exit_with("$device is in use or not a DASD/zFCP disk!", 14); + } else { + exit_with("$device does not exist!", 14); + } + } + } + + if (@devices == 0) { + exit_with("No usable devices where provided.", 14); + } + + return(@devices); +} + +sub main +{ + check_paths(); + my @devices = analyze_cmd_parameters(); + + # only one dump device is possible with zFCP which is enforced in analyze_cmd_parameters + if (is_zfcp($devices[0])) { + setup_zfcpdump($devices[0]); + } else { + setup_dasddump(@devices); + } + + print("Creating the dump device was successful.\n"); +} + +main(); diff --git a/qeth_configure b/qeth_configure new file mode 100644 index 0000000..9902567 --- /dev/null +++ b/qeth_configure @@ -0,0 +1,452 @@ +#! /bin/sh +# +# qeth_configure +# +# Configures a qeth device +# +# Usage: +# qeth_configure [-i] [-l] [-f -t ] [-o "Values"] -n -p +# +# -i Configure IP takeover +# -l Configure Layer2 support +# -f force creation of udev rules, do not check values in /sys +# -t Valid cardtypes are: qeth, hsi, osn +# -o General QETH options, separated by spaces +# -n QETH port number to use, 0 or 1. Only needed for real, not virtual devices. +# -p QETH Portname to use. Only needed if sharing a real OSA with z/OS. +# read/write/data chan = x.y.ssss where +# x is always 0 until IBM creates something that uses that number +# y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero +# ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros. +# online = 0 to take the device offline +# 1 to bring the device online +# +# Return values: +# 1 sysfs not mounted +# 2 Invalid status for +# 3 No device found for read channel +# 4 No device found for write channel +# 5 No device found for data channel +# 6 Invalid device type +# 7 Could not load module +# 8 CCW devices grouped different devices +# 9 Could not group devices +# 10 Could not set device online +# 11 Could not set device offline +# + +if [ "${DEBUG}" != "yes" ]; then + DEBUG="no" +fi + +QETH_FORCE=0 + +mesg () { + echo "$@" +} + +DATUM=$(date) + +add_channel_for_cio() { + echo "$* # $DATUM" >> /boot/zipl/active_devices.txt +} + +remove_channel_for_cio() { + [ -w /boot/zipl/active_devices.txt ] && sed -i -e "/^$1/d" /boot/zipl/active_devices.txt +} + +debug_mesg () { + case "$DEBUG" in + yes) mesg "$@" ;; + *) ;; + esac +} + +while [ $# -gt 0 ] ; do + case "$1" in + -i) + # Configure IP takeover + QETH_IPA_TAKEOVER=1 + ;; + -f) # force creation of udev rules, do not check values in /sys + QETH_FORCE=1 + ;; + -l) + # Configure Layer2 support + QETH_LAYER2_SUPPORT=1 + ;; + -n*) + # QETH port number to use + if [ "$1" = "-n" ] ; then + QETH_PORTNO=$2 + shift + else + QETH_PORTNO=${1#-n} + fi + ;; + -o) + # General QETH options, separated by spaces + QETH_OPTIONS=$2 + shift + ;; + -p*) + # QETH Portname to use + if [ "$1" = "-p" ] ; then + QETH_PORTNAME=$2 + shift + else + QETH_PORTNAME=${1#-p} + fi + ;; + -t*) # Card type. Must be provided if -f is used. + if [ "$1" = "-t" ] ; then + if [ "$2" = "qeth" -o "$2" = "hsi" -o "$2" = "osn" ]; then + QETH_CARD=$2 + shift + else + mesg "Only qeth, hsi and osn are supported." + exit 6 + fi + fi + CCW_DRV="$QETH_CARD" + ;; + *) + break; + ;; + esac + shift +done + +if [ $QETH_FORCE -eq 0 ]; then +# Get the mount point for sysfs + while read MNTPT MNTDIR MNTSYS MNTTYPE; do + if test "$MNTSYS" = "sysfs"; then + SYSFS="$MNTDIR" + break; + fi + done " + echo " -i Configure IP takeover" + echo " -l Configure Layer2 support" + echo " -f force creation of udev rules, do not check values in /sys" + echo " -t Valid cardtypes are: qeth, hsi, osn" + echo " -o General QETH options, separated by spaces" + echo " -n QETH port number to use, 0 or 1. Only needed for real, not virtual devices." + echo " -p QETH Portname to use. Only needed if sharing a real OSA with z/OS." + echo " read/write/data chan = x.y.ssss where" + echo " x is always 0 until IBM creates something that uses that number" + echo " y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero" + echo " ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros." + echo " online = 0 to take the device offline" + echo " 1 to bring the device online" + exit 1 +fi + +if [ -z "$ONLINE" ] || [ "$ONLINE" -ne "1" -a "$ONLINE" -ne "0" ]; then + mesg "Invalid device status $ONLINE" + exit 2 +fi + +if [ $QETH_FORCE -eq 0 ]; then +_ccw_dir=${SYSFS}/bus/ccw/devices + +# Convert any hexidecimal numbers to lower case +QETH_READ_CHAN=$(echo ${QETH_READ_CHAN} | tr "[A-Z]" "[a-z]") +QETH_WRITE_CHAN=$(echo ${QETH_WRITE_CHAN} | tr "[A-Z]" "[a-z]") +QETH_DATA_CHAN=$(echo ${QETH_DATA_CHAN} | tr "[A-Z]" "[a-z]") + +debug_mesg "Configuring QETH device ${QETH_READ_CHAN}/${QETH_WRITE_CHAN}/${QETH_DATA_CHAN}" + + +if test ! -d "$_ccw_dir/$QETH_READ_CHAN" ; then + mesg "No device ${QETH_READ_CHAN}" + exit 3 +fi +if test ! -d "$_ccw_dir/$QETH_WRITE_CHAN" ; then + mesg "No device ${QETH_WRITE_CHAN}" + exit 4 +fi +if test ! -d "$_ccw_dir/$QETH_DATA_CHAN" ; then + mesg "No device ${QETH_DATA_CHAN}" + exit 5 +fi + +CCW_CHAN_GROUP= +for ccw in $_ccw_dir/$QETH_READ_CHAN $_ccw_dir/$QETH_WRITE_CHAN $_ccw_dir/$QETH_DATA_CHAN; do + + read _cu_type < $ccw/cutype + read _dev_type < $ccw/devtype + + case "$_cu_type" in + 1731/01|1731/02) + # OSA/Express / Guest LAN + CCW_DRV="qeth" + QETH_CARD="qeth" + ;; + 1731/05) + # Hipersockets + CCW_DRV="qeth" + QETH_CARD="hsi" + ;; + 1731/06) + # OSA/N + CCW_DRV="qeth" + QETH_CARD="osn" + ;; + *) + CCW_DRV= + ;; + esac + + if [ -z "$CCW_DRV" ]; then + mesg "Not a valid QETH device (cu $_cutype, dev $_devtype)" + exit 6 + fi +done +fi # end QETH_FORCE + +# Portname is only required for OSA/Express +if [ -n "$QETH_PORTNAME" -a "$QETH_CARD" != "qeth" ] ; then + debug_mesg "No portname required for $QETH_CARD adapters" + QETH_PORTNAME= +fi + +if [ $QETH_FORCE -eq 0 ]; then +_ccw_groupdir=${SYSFS}/bus/ccwgroup + +# Check for modules +if test ! -d "${_ccw_groupdir}/drivers/${CCW_DRV}" ; then + /sbin/modprobe $CCW_DRV + + # Re-check whether module loading has succeeded + if test ! -d "${_ccw_groupdir}/drivers/${CCW_DRV}"; then + mesg "Could not load module ${CCW_DRV}" + exit 7 + fi +fi + +# Check for grouping +_ccwgroup_dir= +if [ -e ${_ccw_dir}/${QETH_READ_CHAN}/group_device ] ; then + _ccwgroup_dir=$(cd -P ${_ccw_dir}/${QETH_READ_CHAN}/group_device; echo $PWD) +fi +if [ -e ${_ccw_dir}/${QETH_WRITE_CHAN}/group_device ] ; then + _tmp_status_dir=$(cd -P ${_ccw_dir}/${QETH_READ_CHAN}/group_device; echo $PWD) + if [ "$_ccwgroup_dir" ] && [ "$_ccwgroup_dir" != "$_tmp_status_dir" ] ; then + mesg "CCW devices grouped to different devices" + exit 8 + fi + _ccwgroup_dir=$_tmp_status_dir +fi +if [ -e ${_ccw_dir}/${QETH_DATA_CHAN}/group_device ] ; then + _tmp_status_dir=$(cd -P ${_ccw_dir}/${QETH_DATA_CHAN}/group_device; echo $PWD) + if [ "$_ccwgroup_dir" ] && [ "$_ccwgroup_dir" != "$_tmp_status_dir" ] ; then + mesg "CCW devices grouped to different devices" + exit 8 + fi + _ccwgroup_dir=$_tmp_status_dir +fi +if [ -z "$_ccwgroup_dir" ] ; then + echo "$QETH_READ_CHAN,$QETH_WRITE_CHAN,$QETH_DATA_CHAN" > ${_ccw_groupdir}/drivers/${CCW_DRV}/group + if [ -e ${_ccw_dir}/${QETH_READ_CHAN}/group_device ] ; then + _ccwgroup_dir=$(cd -P ${_ccw_dir}/${QETH_READ_CHAN}/group_device; echo $PWD) + fi +fi + +if [ -z "$_ccwgroup_dir" -o ! -e "$_ccwgroup_dir" ] ; then + mesg "Could not group $CCW_DRV devices $QETH_READ_CHAN/$QETH_WRITE_CHAN/$QETH_DATA_CHAN" + exit 9 +fi + +CCW_CHAN_ID=${_ccwgroup_dir##*/} + +read _online < $_ccwgroup_dir/online + +if [ "$ONLINE" -eq 1 ]; then + # Check whether we need to do something + # We do not check for the value of CCW_CHAN_MODE, since we + # might want to switch back and forth between several modes + if test "$_online" -eq "0" ; then + # Set the portname + if [ "$QETH_PORTNAME" ]; then + mesg "(portname $QETH_PORTNAME) " + echo "$QETH_PORTNAME" > $_ccwgroup_dir/portname + fi + # Activate Layer2 support + if [ -w "$_ccwgroup_dir/layer2" ] ; then + if [ "$QETH_LAYER2_SUPPORT" = "1" ]; then + mesg "(Layer2) " + echo 1 > $_ccwgroup_dir/layer2 + else + echo 0 > $_ccwgroup_dir/layer2 + fi + else + QETH_LAYER2_SUPPORT= + fi + # Enable IP address takeover + if [ "$QETH_IPA_TAKEOVER" ]; then + if [ "$QETH_IPA_TAKEOVER" = "1" ]; then + mesg "(IP takeover) " + echo 1 > $_ccwgroup_dir/ipa_takeover/enable + fi + fi + # Relative port number + if [ -w "$_ccwgroup_dir/portno" ] ; then + if [ -n "$QETH_PORTNO" ]; then + mesg "(Port $QETH_PORTNO) " + # This may fail, but trial and error is the only way to tell. + echo "$QETH_PORTNO" > $_ccwgroup_dir/portno + fi + else + unset QETH_PORTNO + fi + # Set additional options + if [ "$QETH_OPTIONS" ]; then + for opt in $QETH_OPTIONS; do + set -- $(IFS='='; echo $opt) + opt_name=$1 + opt_val=$2 + case "$opt_name" in + portname|ipa_takeover|layer2) + # These options are set above + debug_mesg "Invalid option $opt_name" + ;; + *) + if [ "$opt_name" -a "$opt_val" ]; then + if [ -w "$_ccwgroup_dir/$opt_name" ]; then + mesg "($opt_name) " + echo "$opt_val" > $_ccwgroup_dir/$opt_name + if [ $? -eq 0 ] ; then + cur_opts="$cur_opts ${opt_name}=${opt_val}" + fi + else + # Skip invalid options + debug_mesg "Invalid option $opt_name" + fi + fi + ;; + esac + done + # Update options list + QETH_OPTIONS="$cur_opts" + fi + + echo "1" > $_ccwgroup_dir/online 2> /dev/null + # Re-read device status + read _ccw_dev_status < $_ccwgroup_dir/online + if [ "$_ccw_dev_status" -eq 0 ]; then + mesg "Could not set device ${CCW_CHAN_ID} online" + exit 10 + fi + else + debug_mesg "Device ${CCW_CHAN_ID} is already online" + fi +else + if [ "$_online" -eq 1 ]; then + # Set the device offline + debug_mesg "Setting device offline" + echo "$ONLINE" > $_ccwgroup_dir/online + + # Re-read to check whether we have succeeded + _online=$(cat $_ccwgroup_dir/online) + if [ "$_online" -ne "$ONLINE" ]; then + mesg "Could not set device ${CCW_CHAN_ID} offline" + exit 11 + fi + else + debug_mesg "Device ${CCW_CHAN_ID} is already offline" + fi + echo 1 > $_ccwgroup_dir/ungroup +fi +else + CCW_CHAN_ID=$QETH_READ_CHAN +fi # QETH_FORCE + +if [ $DEBUG = "no" ]; then + RULES_DIR=/etc/udev/rules.d +else + RULES_DIR=. +fi + +RULES_FILE=51-${QETH_CARD}-${CCW_CHAN_ID}.rules + +if [ -d "$RULES_DIR" ]; then + if [ -f ${RULES_DIR}/${RULES_FILE} ]; then + rm -f ${RULES_DIR}/${RULES_FILE} + fi + remove_channel_for_cio "${QETH_READ_CHAN}" + remove_channel_for_cio "${QETH_WRITE_CHAN}" + remove_channel_for_cio "${QETH_DATA_CHAN}" + + if [ "$ONLINE" -eq "1" ]; then + add_channel_for_cio "${QETH_READ_CHAN},${QETH_WRITE_CHAN},${QETH_DATA_CHAN}" + # Write a new udev rules file + cat > ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <.rules +.RE +.I /etc/udev/rules.d/51-osn-.rules +.RE +.I /etc/udev/rules.d/51-qeth-.rules +.RS +These files provide the udev rules necessary to activate a specific adapter. +.RE +.SH ENVIRONMENT +.IP DEBUG +If set to "yes" some minimal debugging information is output during execution. +.SH DIAGNOSTICS +The following messages may be issued on stdout: +.IP +.B /sysfs not present +.RS +The sysfs file system could not be found in /proc/mounts, so there's nothing the script can +do. Return code 1 is set. +.RE +.IP +.B Invalid device status ${ONLINE} +.RS +A value other than 0 or 1 was specified for the third parameter, online. Return code 2 is set. +.RE +.IP +.B No device ${QETH_READ_CHAN} +.RS +A non-existent was specified for the read_channel parameter. Remember the x.y.ssss format is necessary. Return code 3 is set. +.RE +.IP +.B No device ${QETH_WRITE_CHAN} +.RS +A non-existent was specified for the write_channel parameter. Remember the x.y.ssss format is necessary. Return code 4 is set. +.RE +.IP +.B No device ${QETH_DATA_CHAN} +.RS +A non-existent was specified for the data_channel parameter. Remember the x.y.ssss format is necessary. Return code 4 is set.. Return code 5 is st. +.RE +.IP +.B Only qeth, hsi and osn are supported. +.RS +The device type specified by the -t option is not one of the supported types. Return code 6 is set. +.RE +.IP +.B Not a valid QETH device (cu $_cutype, dev $_devtype) +.RS +The device number specified does not correspond to a valid QETH device type. Return code 6 is set. +.RE +.IP +.B Could not load module ${CCW_DRV} +.RS +The kernel module for the device type failed to load. Try "dmesg" to see if there is any indication why. Return code 7 is set. +.RE +.IP +.B CCW devices grouped to different devices +.RS +Two or more of the read, write and channels are already grouped, but not within the same interface. Try again with different devices. Return code 8 is set. +.RE +.IP +.B Could not group $CCW_DRV devices $QETH_READ_CHAN/$QETH_WRITE_CHAN/$QETH_DATA_CHAN +.RS +The attempt to group the read, write and data channels into an interface failed. Try "dmesg" to see if there is any indication why. Return code 9 is set. +.RE +.IP +.B Could not set device ${CCW_CHAN_ID} online +.RS +The attempt to bring the grouped devices online failed. Try "dmesg" to see if there is any indication why. Return code 10 is set. +.RE +.IP +.B Could not set device ${CCW_CHAN_ID} offline +.RS +The attempt to take the grouped devices offline failed. Try "dmesg" to see if there is any indication why. Return code 11 is set. +.RE + +If environment variable DEBUG is set to "yes," the following messages may be issued on stdout: +.IP +.B +Configuring QETH device ${QETH_READ_CHAN}/${QETH_WRITE_CHAN}/${QETH_DATA_CHAN} +.RS +Just a little bit of verbosity, since it just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B No portname required for $QETH_CARD adapters +.RS +If a QETH_CARD type other than "qeth" is specified or detected, a portname is not used, so using the -p option is unnecessary. +.RE +.IP +.B Invalid option $opt_name +.RS +Either portname, ipa_takeover, layer2, or a completely unknown QETH parameter was specified via the -o parameter. For portname, ipa_takeover, and layer2, use the -p, -i, or -l options, respectively. +.RE +.IP +.B Device ${CCW_CHAN_ID} is already online +.RS +An attempt was made to bring the adapter online when it was already online. +.RE +.IP +.B Setting device offline +.RS +Just a little bit of verbosity. +.RE +.IP +.B Device ${CCW_CHAN_ID} is already offline +.RS +An attempt was made to take the adapter offline when it was already offline. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. diff --git a/read_values.8 b/read_values.8 new file mode 100644 index 0000000..a308d97 --- /dev/null +++ b/read_values.8 @@ -0,0 +1,50 @@ +.TH read_values "8" "March 2015" "s390-tools" +.SH NAME +read_values \- Read information from the /sys and /proc filesystems for SUSE Customer Center (SCC) and the like. +.SH SYNOPSIS +.B read_values [-s] [-u] [-c] [-a Attribute] [-L Keyword] [-d debug] [-h] +.SH DESCRIPTION +.B read_values +is intended to make it easy to read values from the /sys and /proc filesystems. Those values may be at different places depending on the machine type and the kernel version. +.SH PARAMETERS +.IP -s +Outputs the values needed by the SCC (SUSE Customer Center) +.IP -u +Creates a uuid for this system +.IP -c +Prints the CPU type of the current system +.IP -a Attribute +Prints the value of the +.B Attribute +.IP -L Keyword +The +.B Keyword +may be +.B Attribute +or +.B Recognised. +With this option you get a list of all +.B Attributes +the programm can accept ( +.B Attribute +) or a list of attributes which in turn can be used for the option -L ( +.B Recognised +). +.SH FILES +.I /sys and /proc +.SH DIAGNOSTICS +The following messages may be issued on stderr: +.IP +.B Unable to open /proc/sysinfo +or +.B Unable to open sysinfo.zvm +.RS +The named file cannot be opened. This means the tool can't do anything useful. Return code 99 is set. +.RE +.IP +.B Only one of the options a, c, L, s or u can be specified. +.RS +Only one of the options a, c, L, s or u can be specified at a time. Return code 1 is set. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. diff --git a/read_values.c b/read_values.c new file mode 100644 index 0000000..ca4fadc --- /dev/null +++ b/read_values.c @@ -0,0 +1,426 @@ +/********************************************************************************/ +/* */ +/* Copyright (C) 2014-2015, SUSE LLC */ +/* */ +/* All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Data types + */ +enum datatypes { + integer, + string, + floatingpoint +}; + +#define WITHOUT_KEY 0 +#define WITH_KEY 1 + +static char *versionstring = "Version 1.0 2015-10-12 13:31"; + +static char *version = "1.0.0"; + +void *configuration_handle = NULL; +int layers = -1; + +/* + * List of machine types + */ +struct machinetype { + char *typenumber; + char *fullname; + } machinetypes[] = { + { "2064", "2064 = z900 IBM eServer zSeries 900" }, + { "2066", "2066 = z800 IBM eServer zSeries 800" }, + { "2084", "2084 = z990 IBM eServer zSeries 990" }, + { "2086", "2086 = z890 IBM eServer zSeries 890" }, + { "2094", "2094 = z9-EC IBM System z9 Enterprise Class" }, + { "2096", "2096 = z9-BC IBM System z9 Business Class" }, + { "2097", "2097 = z10-EC IBM System z10 Enterprise Class" }, + { "2098", "2098 = z10-BC IBM System z10 Business Class" }, + { "2817", "2817 = z196 IBM zEnterprise 196" }, + { "2818", "2818 = z114 IBM zEnterprise 114" }, + { "2827", "2827 = z12-EC IBM zEnterprise EC12" }, + { "2828", "2828 = z12-BC IBM zEnterprise BC12" }, + { "2964", "2964 = z13 IBM z13" }, + }; + +int debug = 0; + +/******************************************************************************/ +/* */ +/* */ +/* */ +/******************************************************************************/ +void print_version() +{ +printf("Version: %s\n", version); +} +/******************************************************************************/ +/* */ +/* Look for one attribute and print it */ +/* */ +/******************************************************************************/ +void print_attribute(char *user_string, int level, enum qc_attr_id attribute, enum datatypes type, int print_key) +{ +int erg = 0; +const char *result_string = NULL; +int result_int = 0; +float result_float = 0.0; + + switch (type) + { + case integer: + erg = qc_get_attribute_int(configuration_handle, attribute, level, &result_int); + break; + case string: + erg = qc_get_attribute_string(configuration_handle, attribute, level, &result_string); + break; + case floatingpoint: + erg = qc_get_attribute_float(configuration_handle, attribute, level, &result_float); + break; + default: + break; + } + if (erg == 1) { + if (print_key == WITH_KEY) { + printf("%s: ",(user_string == NULL? "NULL": user_string)); + } /* endif */ + switch (type) + { + case integer: + printf("%d\n",result_int); + break; + case string: + printf("%s\n", result_string); + break; + case floatingpoint: + printf("%f\n",result_float); + break; + default: + break; + } + } /* endif */ + else { + printf("Fehler: erg = %d, result_string = %s \n", erg, (result_string == NULL? "NULL": result_string)); + /* TODO qc_get_attribute_string returned error */ + } +} /* print_attribute */ + +/********************************************************************************/ +/* */ +/* Open the lib and get the handle */ +/* */ +/********************************************************************************/ +int read_sysinfo() +{ +int return_code; + + configuration_handle = qc_open(&return_code); + if (return_code < 0) { + printf("Error: Unable to open configuration, return_code =%d\n", return_code); + return -1; + } /* endif */ + if (return_code > 0) { + printf("Warning: Unable to read configuration completely, return_code =%d\n", return_code); + return -2; + } /* endif */ + if (configuration_handle == NULL) { + printf("Error: Unable to open configuration, return_code =%d\n", return_code); + return -3; + } /* endif */ + layers = qc_get_num_layers(configuration_handle, &return_code); + if (layers < 0) { + printf("Error: Unable to retrieve number of layers, return_code =%d\n", return_code); + return -4; + } /* endif */ + return 0; +} /* read_sysinfo */ + +/********************************************************************************/ +/* */ +/* Look at the type of machine we're running on and print out a user */ +/* friendly string */ +/* */ +/********************************************************************************/ +void print_cputype() +{ +int i, search; +int erg; +const char *cpu_type = NULL; + + erg = qc_get_attribute_string(configuration_handle, qc_type, 0, &cpu_type); + if (erg == 1 && cpu_type != NULL) { + for (i = 0, search = 1; (i < sizeof(machinetypes) / sizeof(struct machinetype)) && search ; i++) + { + if (strcmp(cpu_type, machinetypes[i].typenumber) == 0) { + printf("%s\n", machinetypes[i].fullname); + search = 0; + } /* endif */ + } /* endfor */ + if (search != 0) { + printf("An unknown machine type was reported: %s\n\ +Please file a bug report with this output:\n" , cpu_type); +/* TODO output of /proc/sysinfo */ + } /* endif */ + } /* endif */ + return; +} /* print_cputype */ + +/********************************************************************************/ +/* */ +/* Print out the values for SCC */ +/* */ +/* To uniquely identify a machine the following information is used: */ +/* */ +/* Type */ +/* Sequence code */ +/* CPUs total */ +/* CPUs IFL */ +/* LPAR Number */ +/* LPAR Characteristics: */ +/* LPAR CPUs */ +/* LPAR IFLs */ +/* */ +/* Optional: */ +/* */ +/* VM00 Name */ +/* VM00 Control Programm */ +/* VM00 CPUs */ +/* */ +/********************************************************************************/ +void print_scc() +{ +print_version(); +print_attribute("Type", 0, qc_type, string, WITH_KEY); +print_attribute("Sequence Code", 0, qc_sequence_code, string, WITH_KEY); +print_attribute("CPUs Total", 0, qc_num_cpu_total, integer, WITH_KEY); +print_attribute("CPUs IFL", 0, qc_num_cpu_total, integer, WITH_KEY); +print_attribute("LPAR Number", 1, qc_partition_number, integer, WITH_KEY); +print_attribute("LPAR Name", 1, qc_layer_name, string, WITH_KEY); +print_attribute("LPAR Characteristics", 1, qc_partition_char, string, WITH_KEY); +print_attribute("LPAR CPUs Total", 1, qc_num_cpu_total, integer, WITH_KEY); +print_attribute("LPAR CPUs IFL", 1, qc_num_cpu_total, integer, WITH_KEY); +if (layers > 2) { +/* + * This means, that eather zKVM or z/Vm is running + */ + print_attribute("VM00 Name", 3, qc_layer_name, string, WITH_KEY); + print_attribute("VM00 Control Program", 2, qc_control_program_id, string, WITH_KEY); + print_attribute("VM00 CPUs Total", 3, qc_num_cpu_total, integer, WITH_KEY); + print_attribute("VM00 IFLs", 3, qc_num_cpu_total, integer, WITH_KEY); +} /* endif */ +return; +} /* print_scc */ + +/******************************************************************************/ +/* */ +/* print out the uuid for this machine */ +/* */ +/* TODO! */ +/* */ +/******************************************************************************/ +void print_uuid() +{ +return; +} /* print_uuid */ + +/******************************************************************************/ +/* */ +/* print out the list of valid / found symbols */ +/* */ +/******************************************************************************/ +void list(char * list_attribute_param) +{ +return; +} /* list */ + +/******************************************************************************/ +/* */ +/* print out the requested attribute */ +/* */ +/******************************************************************************/ +void print_user_attribute(char *key, char *attribute_param, int layer) +{ +return; +} /* print_uuid */ + + +/******************************************************************************/ +/* */ +/* Help Function */ +/* */ +/******************************************************************************/ +void help() +{ +puts("help:\n\ +\n\ +-a List the value of the named attribute\n\ +-c Print the cputype of this machine\n\ +-d Debug Level\n\ +-h this help\n\ +-L List the requested list (Attribute, Recognised)\n\ +-s create Info for SCC\n\ +-u create uuid\n\ +-V print version string\n\ +"); +#if 0 +if (debug != 0) { + puts("\n\ +Valid values for debug:\n\ + 4 - read sysinfo.zvm from current directory instead of /proc/sysinfo\n\ + 8 - printout lines read in from source (see debug == 4)\n\ + 16 - printf found keys in store_value\n\ + 32 - Search expression in show attribute\n\ +"); +} /* endif */ +#endif +} /* help */ + +/******************************************************************************/ +/* */ +/* Main */ +/* */ +/******************************************************************************/ +int main(int argc, char **argv, char **envp) +{ +int opt; +int read_sysinfo_opt; +int print_attr; +int print_cpu; +int print_help; +int list_attr; +int create_scc; +int create_uuid; +int erg; +int return_code; +char *print_attribute_param = NULL; +char *list_attribute_param = NULL; +void *configuration_handle_tmp = NULL; + + read_sysinfo_opt = + print_attr = + print_cpu = + print_help = + list_attr = + create_scc = + create_uuid = + return_code = + erg = 0; + if (strcmp(argv[0],"cputype") == 0) { + read_sysinfo_opt++; + print_cpu++; + } /* endif */ + else { + while ((opt = getopt(argc, argv, "a:cd:hL:suV")) != -1) { + switch (opt) + { + case 'a': + read_sysinfo_opt++; + print_attr++; + print_attribute_param = strdup(optarg); + break; + case 'c': + read_sysinfo_opt++; + print_cpu++; + break; + case 'd': + debug = atoi(optarg); + if ((debug & 1) == 1) { + setenv("QC_DEBUG", "1", 1); + } /* endif */ + if ((debug & 2) == 2) { + setenv("QC_AUTODUMP", "1", 1); + } /* endif */ + debug = debug >> 2; + break; + case 'L': + read_sysinfo_opt++; + list_attr++; + list_attribute_param = strdup(optarg); + break; + case 's': /* create unique string for scc */ + read_sysinfo_opt++; + create_scc++; + break; + case 'u': /* create UUID */ + read_sysinfo_opt++; + create_uuid++; + break; + case 'V': + printf("%s\n",versionstring); + return 0; + break; + case 'h': + default: + print_help++; + break; + } /* endswitch */ + } /* while */ + } /* endlse */ + if (print_help != 0) { + help(); + return 0; + } /* endif */ + if (read_sysinfo_opt != 0) { + if ((erg = read_sysinfo()) != 0) { + return -erg; + } /* endif */ + } /* endif */ + if ((print_attr + print_cpu + list_attr + create_scc + create_uuid) > 1) { + fputs("Only one of the options a, c, L, s or u can be specified.",stderr); + return 1; + } /* endif */ + /* still not im[plemented thatfore set to zero */ + create_uuid = list_attr = print_attr = 0; + if (print_attr != 0) { + print_user_attribute(NULL, print_attribute_param, layers); + goto main_exit; + } /* endif */ + if (print_cpu != 0) { + print_cputype(); + goto main_exit; + } /* endif */ + if (list_attr != 0) { + list(list_attribute_param); + goto main_exit; + } /* endif */ + if (create_scc != 0) { + print_scc(); + goto main_exit; + } /* endif */ + if (create_uuid != 0) { + print_uuid(); + goto main_exit; + } /* endif */ + help(); +main_exit: + if (configuration_handle != NULL) { + configuration_handle_tmp = qc_open(&return_code); + qc_close(configuration_handle); + setenv("QC_DEBUG", "0", 1); + setenv("QC_AUTODUMP", "0", 1); + qc_close(configuration_handle_tmp); + } /* endif */ +return 0; +} /* end main */ diff --git a/rules.hw_random b/rules.hw_random new file mode 100644 index 0000000..9a4d3d6 --- /dev/null +++ b/rules.hw_random @@ -0,0 +1,2 @@ +# Rules to add hw_random node to maintain SLES11-SP1 backward compatibility +KERNEL=="hwrng", SYMLINK+="hw_random" diff --git a/rules.xpram b/rules.xpram new file mode 100644 index 0000000..0ba0962 --- /dev/null +++ b/rules.xpram @@ -0,0 +1,2 @@ +# Rules to add xpram* nodes to maintain SLES11-SP1 backward compatibility +KERNEL=="sl*[0-9]", SYMLINK+="xpram%n" diff --git a/s390-tools-1.34.0.tar.bz2 b/s390-tools-1.34.0.tar.bz2 new file mode 100644 index 0000000..9092dfa --- /dev/null +++ b/s390-tools-1.34.0.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6f4e9d6f27cfad77ff84ac7a332a7fb2e17b620b3c2da4fc2ba47d2c77c94287 +size 814967 diff --git a/s390-tools-rpmlintrc b/s390-tools-rpmlintrc new file mode 100644 index 0000000..1371e04 --- /dev/null +++ b/s390-tools-rpmlintrc @@ -0,0 +1,3 @@ +addFilter("statically-linked-binary /usr/lib/s390-tools/.*") +addFilter("statically-linked-binary /usr/bin/read_values") +addFilter("systemd-service-without-service_.* *@.service") diff --git a/s390-tools-sles12-create-filesystem-links.patch b/s390-tools-sles12-create-filesystem-links.patch new file mode 100644 index 0000000..c3a4620 --- /dev/null +++ b/s390-tools-sles12-create-filesystem-links.patch @@ -0,0 +1,26 @@ +--- a/etc/udev/rules.d/59-dasd.rules 2016-03-17 06:15:01.000000000 -0400 ++++ b/etc/udev/rules.d/59-dasd.rules 2016-03-23 17:36:26.000000000 -0400 +@@ -15,7 +15,7 @@ + + LABEL="dasd_block_end" + +-ACTION!="change|add", GOTO="dasd_symlinks_end" ++ACTION!="change|add", GOTO="dasd_partition_end" + + # for partitions import parent information + KERNEL=="dasd*[0-9]", IMPORT{parent}=="ID_*" +@@ -24,6 +24,14 @@ + KERNEL=="dasd*[0-9]", ENV{ID_UID}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_UID}-part%n" + KERNEL=="dasd*[0-9]", ENV{ID_XUID}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_XUID}-part%n" + ++LABEL="dasd_partition_end" ++ ++ENV{ID_SERIAL}!="?*", GOTO="dasd_symlinks_end" ++# by-label/by-uuid (filesystem properties) ++IMPORT{builtin}="blkid" ++ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID}" ++ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_SAFE}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_SAFE}" ++ + LABEL="dasd_symlinks_end" + + # on device add set request queue scheduler to deadline diff --git a/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch b/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch new file mode 100644 index 0000000..72c85e2 --- /dev/null +++ b/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch @@ -0,0 +1,57 @@ +From d0c2ffc90b9ee0e7b741d1c4b644cdf79f1d922b Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 20 May 2015 11:57:11 +0200 +Subject: [PATCH] fdasd: skip partition check and BLKRRPART ioctl for emulated + devices + +If 'fdasd -f' is called we cannot rely on the partition detection +via a simple check of the minor number, so the check should be +suppressed. +Similarly, not every emulated device supports the BLKRRPART ioctl, +so we should be suppressing the error message for these devices, too. + +Signed-off-by: Hannes Reinecke +--- + fdasd/fdasd.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/fdasd/fdasd.c b/fdasd/fdasd.c +index 4503d3e..f04dc3d 100644 +--- a/fdasd/fdasd.c ++++ b/fdasd/fdasd.c +@@ -826,7 +826,7 @@ fdasd_check_conffile_input (fdasd_anchor_t *anc, + * Verifies the specified block device. + */ + static void +-fdasd_verify_device (fdasd_anchor_t *anc, char *name) ++fdasd_verify_device (fdasd_anchor_t *anc, char *name) + { + struct stat dst; + char err_str[ERROR_STRING_SIZE]; +@@ -847,7 +847,7 @@ fdasd_verify_device (fdasd_anchor_t *anc, char *name) + fdasd_error(anc, device_verification_failed, err_str); + } + +- if (minor (dst.st_rdev) & PARTN_MASK) { ++ if (!anc->force_virtual && minor (dst.st_rdev) & PARTN_MASK) { + snprintf(err_str, ERROR_STRING_SIZE, + "Partition '%s' (%d/%d) detected where device is " + "required\n", name, +@@ -1156,9 +1156,12 @@ fdasd_reread_partition_table (fdasd_anchor_t *anc) + } + + if (ioctl(fd, BLKRRPART, NULL) != 0) { +- close(fd); +- fdasd_error(anc, unable_to_ioctl, "Error while rereading " +- "partition table.\nPlease reboot!"); ++ if (errno == EINVAL && !anc->force_virtual) { ++ close(fd); ++ fdasd_error(anc, unable_to_ioctl, ++ "Error while rereading " ++ "partition table.\nPlease reboot!"); ++ } + } + close(fd); + } +-- +1.8.5.2 diff --git a/s390-tools-sles12-pardasdfmt.patch b/s390-tools-sles12-pardasdfmt.patch new file mode 100644 index 0000000..c0a4b14 --- /dev/null +++ b/s390-tools-sles12-pardasdfmt.patch @@ -0,0 +1,526 @@ +--- s390-tools-1.34.0/dasdfmt/dasdfmt.8 2016-04-14 16:43:51.000000000 -0400 ++++ s390-tools-1.34.0/dasdfmt/dasdfmt.8 2016-04-14 16:35:01.000000000 -0400 +@@ -3,11 +3,11 @@ + dasdfmt \- formatting of DASD (ECKD) disk drives. + + .SH SYNOPSIS +-\fBdasdfmt\fR [-h] [-t] [-v] [-y] [-p] [-P] [-m \fIstep\fR] ++\fBdasdfmt\fR [-h] [-t] [-v] [-y] [-p] [-Q] [-m \fIstep\fR] + .br +- [-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR] ++ [-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR] [-P maxpar] + .br +- [-L] [-V] [-F] [-k] [-C] \fIdevice\fR ++ [-L] [-V] [-F] [-k] [-C] \fIdevice\fR ... + + .SH DESCRIPTION + \fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it +@@ -91,7 +91,7 @@ + running in background or redirecting the output to a file. + + .TP +-\fB-P\fR or \fB--percentage\fR ++\fB-Q\fR or \fB--percentage\fR + Print one line for each formatted cylinder showing the number of the + cylinder and percentage of formatting process. + Intended to be used by higher level interfaces. +@@ -123,6 +123,20 @@ + and always be a power of two. The recommended blocksize is 4096 bytes. + + .TP ++\fB-P\fR \fInumdisks\fR or \fB--max_parallel\fR=\fInumdisks\fR ++Specify the number of disks to be formatted in ++parallel. \FInumdisks\fR specifies the number of formatting processes ++which is independent of the overall number of disks to be formatted as ++specified on the commandline. The maximum value for \fInumdisks\fR is ++1024. Default is 1. ++.br ++Using this option can ++decrease overall processing time when formatting several disks. ++Please note that the I/O throughput will dramatically increase when ++using this option. Use with care. ++.br ++ ++.TP + \fB-l\fR \fIvolser\fR or \fB--label\fR=\fIvolser\fR + Specify the volume serial number or volume identifier to be written + to disk after formatting. If no label is specified, a sensible default +--- s390-tools-1.34.0/dasdfmt/dasdfmt.h 2016-04-14 16:43:51.000000000 -0400 ++++ s390-tools-1.34.0/dasdfmt/dasdfmt.h 2016-04-14 16:35:01.000000000 -0400 +@@ -195,6 +195,7 @@ + #define LABEL_LENGTH 14 + #define VLABEL_CHARS 84 + #define LINE_LENGTH 80 ++#define MAX_DEVICES 1024 + #define ERR_LENGTH 90 + + #define DEFAULT_BLOCKSIZE 4096 +@@ -214,7 +215,7 @@ + if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ + "is in invalid format\n",prog_name);} + +-#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpPLtyvVFkC" ++#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpQLtyvVFkCYP:" + + static struct option dasdfmt_getopt_long_options[]= + { +@@ -225,12 +226,14 @@ + { "force", 0, 0, 'F'}, + { "progressbar", 0, 0, 'p'}, + { "hashmarks", 1, 0, 'm'}, +- { "percentage", 0, 0, 'P'}, ++ { "percentage", 0, 0, 'Q'}, + { "label", 1, 0, 'l'}, + { "device", 1, 0, 'f'}, + { "blocksize", 1, 0, 'b'}, + { "requestsize", 1, 0, 'r'}, + { "help", 0, 0, 'h'}, ++ { "max_parallel",1, 0, 'P'}, ++ { "yast_mode", 0, 0, 'Y'}, + { "keep_volser", 0, 0, 'k'}, + { "norecordzero", 0, 0, 'z'}, + { "check_host_count", 0, 0, 'C'}, +@@ -267,6 +270,8 @@ + int device_id; + int keep_volser; + int force_host; ++ int yast_mode; ++ int procnum; + } dasdfmt_info_t; + + +--- s390-tools-1.34.0/dasdfmt/dasdfmt.c 2016-04-14 16:43:51.000000000 -0400 ++++ s390-tools-1.34.0/dasdfmt/dasdfmt.c 2016-04-14 16:35:01.000000000 -0400 +@@ -17,6 +17,7 @@ + #include "vtoc.h" + #include "util_proc.h" + #include "dasd_sys.h" ++#include + + #define BUSIDSIZE 8 + +@@ -48,7 +49,7 @@ + */ + static void exit_usage(int exitcode) + { +- printf("Usage: %s [-htvypPLVFkC]\n" ++ printf("Usage: %s [-htvypQLVFkC]\n" + " [-l | --label=]\n" + " [-b | --blocksize=]\n" + " [-d | --disk_layout=]\n" +@@ -59,7 +60,7 @@ + " -V or --version means print version\n" + " -L or --no_label means don't write disk label\n" + " -p or --progressbar means show a progress bar\n" +- " -P or --percentage means show a progress in percent\n" ++ " -Q or --percentage means show a progress in percent\n" + " -m x or --hashmarks=x means show a hashmark every x " + "cylinders\n" + " -r x or --requestsize=x means use x cylinders in one " +@@ -143,22 +144,33 @@ + /* + * check given device name for blanks and some special characters + */ +-static void get_device_name(dasdfmt_info_t *info, char *name, int argc, char * argv[]) ++static char* getdev(char* sysfs_path) + { +- struct util_proc_dev_entry dev_entry; +- struct stat dev_stat; +- +- if (info->node_specified && (info->device_id < argc)) +- ERRMSG_EXIT(EXIT_MISUSE,"%s: Device can only specified once!\n", +- prog_name); ++ DIR* d; ++ struct dirent* de; ++ ++ d = opendir(sysfs_path); ++ if(!d) ERRMSG_EXIT(EXIT_FAILURE,"%s: Could not open directory %s.\n",prog_name,sysfs_path); ++ while((de = readdir(d))) ++ { ++ if(strncmp(de->d_name,"block:",6) == 0) ++ { ++ closedir(d); ++ return de->d_name+6; ++ } ++ } ++ return 0; ++} + +- if (!info->node_specified && (info->device_id >= argc)) +- ERRMSG_EXIT(EXIT_MISUSE,"%s: No device specified!\n", +- prog_name); ++static void get_device_name(dasdfmt_info_t *info, char *name) ++{ ++ struct util_proc_dev_entry dev_entry; ++ struct stat dev_stat; ++ char buf[PATH_MAX]; ++ char devno[9]; ++ char* device; ++ int i; + +- if (info->device_id < argc) { +- strcpy(info->devname, argv[info->device_id]); +- } else { + if ((strchr(name, ' ') != NULL)||(strchr(name, '#') != NULL)|| + (strchr(name, '[') != NULL)||(strchr(name, ']') != NULL)|| + (strchr(name, '!') != NULL)||(strchr(name, '>') != NULL)|| +@@ -169,9 +181,38 @@ + "blanks or special characters!\n", + prog_name); + +- strncpy(info->devname, name, PATH_MAX - 1); ++ if (isxdigit(name[0]) && name[1] == '.' && isxdigit(name[2]) && name[3] == '.' && strlen(name) == 8) ++ { /* x.x.xxxx format */ ++ for(i=0; i<8; i++) ++ devno[i] = tolower(name[i]); ++ devno[8] = 0; ++ sprintf(buf,"/sys/bus/ccw/devices/%s",devno); ++ device = getdev(buf); ++ if(device) ++ { ++ strcpy(info->devname,"/dev/"); ++ strcat(info->devname,device); ++ } ++ else ERRMSG_EXIT(EXIT_FAILURE,"%s: Could not find device file for device no. %s\n",prog_name,name); ++ } ++ else if (isxdigit(name[0]) && isxdigit(name[1]) && isxdigit(name[2]) && isxdigit(name[3])) ++ { /* xxxx format */ ++ for(i=0; i<4; i++) ++ devno[i] = tolower(name[i]); ++ devno[4] = 0; ++ sprintf(buf,"/sys/bus/ccw/devices/0.0.%s",devno); ++ device = getdev(buf); ++ if(device) ++ { ++ strcpy(info->devname,"/dev/"); ++ strcat(info->devname,device); ++ } ++ else ERRMSG_EXIT(EXIT_FAILURE,"%s: Could not find device file for device no. %s\n",prog_name,name); ++ } ++ else ++ strncpy(info->devname, name, PATH_MAX - 1); ++ + info->devname[PATH_MAX - 1] = '\0'; +- } + + if (stat(info->devname, &dev_stat) != 0) + ERRMSG_EXIT(EXIT_MISUSE, +@@ -217,8 +258,9 @@ + info->reqsize_specified = 0; + info->node_specified = 0; + info->device_id = 0; +- info->keep_volser = 0; ++ info->keep_volser = 0; + info->force_host = 0; ++ info->yast_mode = 0; + } + + +@@ -271,7 +313,6 @@ + } + + +- + /* + * check the volume serial for special + * characters and move blanks to the end +@@ -640,7 +681,7 @@ + info->hashstep = 10; + } + +- printf("Printing hashmark every %d cylinders.\n", ++ if(!info->yast_mode) printf("Printing hashmark every %d cylinders.\n", + info->hashstep); + } + +@@ -649,7 +690,7 @@ + + k = 0; + cyl = 1; +- if (info->print_progressbar || info->print_hashmarks) ++ if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) + printf("\n"); + + while (1) { +@@ -688,7 +729,7 @@ + + if (info->print_hashmarks) + if ((cyl / info->hashstep - hashcount) != 0) { +- printf("#"); ++ printf("%d|",info->procnum); + fflush(stdout); + hashcount++; + } +@@ -709,7 +750,7 @@ + break; + } + +- if (info->print_progressbar || info->print_hashmarks) ++ if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) + printf("\n\n"); + } + +@@ -884,17 +925,21 @@ + + dasdfmt_prepare_and_format(info, cylinders, heads, p); + +- printf("Finished formatting the device.\n"); ++ if (!info->yast_mode) ++ printf("Finished formatting the device.\n"); + + if (!info->writenolabel) + dasdfmt_write_labels(info, vlabel, cylinders, heads); + +- printf("Rereading the partition table... "); ++ if (!info->yast_mode) ++ printf("Rereading the partition table... "); + if (reread_partition_table()) { + ERRMSG("%s: error during rereading the partition " + "table: %s.\n", prog_name, strerror(errno)); +- } else +- printf("ok\n"); ++ } else { ++ if (!info->yast_mode) ++ printf("ok\n"); ++ } + } + } + +@@ -905,7 +950,8 @@ + volume_label_t vlabel; + char old_volser[7]; + +- char dev_filename[PATH_MAX]; ++ char* dev_filename[MAX_DEVICES]; ++ int dev_count=0; + char str[ERR_LENGTH]; + char buf[7]; + +@@ -913,7 +959,10 @@ + char *reqsize_param_str = NULL; + char *hashstep_str = NULL; + +- int rc, index; ++ int rc, index, i; ++ ++ int max_parallel=1; ++ int running=0; + + /* Establish a handler for interrupt signals. */ + signal (SIGTERM, program_interrupt_signal); +@@ -990,7 +1039,7 @@ + } + break; + +- case 'P': ++ case 'Q': + if (!(info.print_hashmarks || info.print_progressbar)) + info.print_percentage = 1; + break; +@@ -1034,9 +1083,18 @@ + info.reqsize_specified = 1; + break; + case 'f' : +- strncpy(dev_filename, optarg, PATH_MAX); ++ if(dev_count>=MAX_DEVICES) ++ ERRMSG_EXIT(EXIT_MISUSE,"%s: too many devices specified.\n", ++ prog_name); ++ dev_filename[dev_count++]=strdup(optarg); + info.node_specified=1; + break; ++ case 'Y' : /* YaST mode */ ++ info.yast_mode=1; ++ break; ++ case 'P' : /* max parallel formatting processes */ ++ max_parallel=atoi(optarg); ++ break; + case 'k' : + info.keep_volser=1; + break; +@@ -1059,58 +1117,147 @@ + CHECK_SPEC_MAX_ONCE(info.labelspec, "label"); + CHECK_SPEC_MAX_ONCE(info.writenolabel, "omit-label-writing flag"); + +- if (info.blksize_specified) +- PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10, +- "blocksize"); +- if (info.reqsize_specified) { +- PARSE_PARAM_INTO(reqsize, reqsize_param_str, 10, "requestsize"); +- if (reqsize < 1 || reqsize > 255) +- ERRMSG_EXIT(EXIT_FAILURE, +- "invalid requestsize %d specified\n", +- reqsize); +- } else +- reqsize = DEFAULT_REQUESTSIZE; +- if (info.print_hashmarks) +- PARSE_PARAM_INTO(info.hashstep, hashstep_str,10,"hashstep"); +- +- get_device_name(&info, dev_filename, argc, argv); ++ while(info.device_id < argc) { /* devices specified at the end of cmdline */ ++ if(dev_count>=MAX_DEVICES) ++ ERRMSG_EXIT(EXIT_MISUSE,"%s: too many devices specified.\n", ++ prog_name); ++ dev_filename[dev_count++]=strdup(argv[info.device_id]); ++ info.node_specified=1; ++ info.device_id++; ++ } + +- if (!info.blksize_specified) +- format_params = ask_user_for_blksize(format_params); ++ if (info.node_specified == 0) ++ ERRMSG_EXIT(EXIT_MISUSE,"%s: No device specified!\n", ++ prog_name); + + if (info.keep_volser) { + if(info.labelspec) { + ERRMSG_EXIT(EXIT_MISUSE,"%s: The -k and -l options are mutually exclusive\n", + prog_name); + } +- if(!(format_params.intensity & DASD_FMT_INT_COMPAT)) { +- printf("WARNING: VOLSER cannot be kept " \ +- "when using the ldl format!\n"); +- exit(1); ++ } ++ ++ if (info.labelspec && max_parallel > 1) { ++ ERRMSG_EXIT(EXIT_MISUSE,"%s: The -l option cannot be used with parallel formatting\n", ++ prog_name); ++ } ++ ++ if(info.yast_mode) { ++ for(i=0;ino_cyl == LV_COMPAT_CYL && ++ characteristics->long_no_cyl) ++ cylinders = characteristics->long_no_cyl; ++ else ++ cylinders = characteristics->no_cyl; ++ ++ printf("%d\n", cylinders); ++ close(filedes); + } +- +- if(dasdfmt_get_volser(info.devname, old_volser) == 0) +- vtoc_volume_label_set_volser(&vlabel, old_volser); +- else +- ERRMSG_EXIT(EXIT_FAILURE,"%s: VOLSER not found on device %s\n", +- prog_name, info.devname); +- ++ fflush(stdout); + } + +- if ((filedes = open(info.devname, O_RDWR)) == -1) +- ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n", +- prog_name, info.devname, strerror(errno)); ++ /* fork one formatting process for each device */ ++ rc = 0; ++ for(i=0;i 255) ++ ERRMSG_EXIT(EXIT_FAILURE, ++ "invalid requestsize %d specified\n", ++ reqsize); ++ } else ++ reqsize = DEFAULT_REQUESTSIZE; ++ if (info.print_hashmarks) ++ PARSE_PARAM_INTO(info.hashstep, hashstep_str,10,"hashstep"); ++ ++ get_device_name(&info, dev_filename[i]); ++ ++ if (!info.blksize_specified) ++ format_params = ask_user_for_blksize(format_params); ++ ++ if (info.keep_volser) { ++ if(format_params.intensity == 0x00) { ++ printf("WARNING: VOLSER cannot be kept " \ ++ "when using the ldl format!\n"); ++ exit(1); ++ } + +- if (close(filedes) != 0) +- ERRMSG("%s: error during close: %s\ncontinuing...\n", +- prog_name, strerror(errno)); ++ if(dasdfmt_get_volser(info.devname, old_volser) == 0) ++ vtoc_volume_label_set_volser(&vlabel, old_volser); ++ else ++ ERRMSG_EXIT(EXIT_FAILURE,"%s: VOLSER not found on device %s\n", ++ prog_name, info.devname); + +- return 0; ++ } ++ ++ if ((filedes = open(info.devname, O_RDWR)) == -1) ++ ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n", ++ prog_name, info.devname, strerror(errno)); ++ ++ check_disk(&info); ++ ++ if (check_param(str, ERR_LENGTH, &format_params) < 0) ++ ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str); ++ ++ do_format_dasd(&info, &format_params, &vlabel); ++ ++ if (close(filedes) != 0) ++ ERRMSG("%s: error during close: %s\ncontinuing...\n", ++ prog_name, strerror(errno)); ++ ++ exit(0); ++ } else { ++ running++; ++ if(running>=max_parallel) { ++ if(wait(&tmp) > 0 && WEXITSTATUS(tmp)) ++ rc = WEXITSTATUS(tmp); ++ running--; ++ } ++ } ++ } ++ ++ /* wait until all formatting children have finished */ ++ while(wait(&i) > 0) ++ if (WEXITSTATUS(i)) rc = WEXITSTATUS(i); ++ ++ return rc; + } diff --git a/s390-tools-sles12-sysconfig-compatible-dumpconf.patch b/s390-tools-sles12-sysconfig-compatible-dumpconf.patch new file mode 100644 index 0000000..124a8b7 --- /dev/null +++ b/s390-tools-sles12-sysconfig-compatible-dumpconf.patch @@ -0,0 +1,175 @@ +From c261ec990a8259f2540089827309b918e1c31590 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Fri, 22 Nov 2013 15:34:22 +0100 +Subject: [PATCH 5/8] dumpconf: Use compatible sysconfig layout + +SUSE is quite restrictive on how the sysconfig +should look like. + +Signed-off-by: Hannes Reinecke +--- + etc/sysconfig/dumpconf | 134 ++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 93 insertions(+), 41 deletions(-) + +diff --git a/etc/sysconfig/dumpconf b/etc/sysconfig/dumpconf +index a3639cf..76f9040 100644 +--- a/etc/sysconfig/dumpconf ++++ b/etc/sysconfig/dumpconf +@@ -1,61 +1,113 @@ ++## Path: System/Dumpconf ++## Description: Configures the actions which should be performed after a kernel panic ++## Type: list(stop,dump,vmcmd,reipl,dump_reipl) ++## Default: "stop" ++## ServiceRestart: dumpconf + # +-# s390 dump config +-# +-# Configures the actions which should be performed after a kernel panic +-# and on PSW restart. ++# Define the action that should be taken if a panic happens. + # + # The following actions are supported: + # +-# * stop: Stop Linux (default) +-# * dump: Dump Linux with stand-alone dump tool +-# * vmcmd: Issue z/VM CP commands +-# * reipl: Re-IPL Linux using setting under /sys/firmware/reipl +-# * dump_reipl: First dump Linux with stand-alone dump tool, then re-IPL Linux +-# using setting under /sys/firmware/reipl ++# * stop: Stop Linux (default) ++# * dump: Dump Linux ++# * vmcmd: Issue z/VM CP commands ++# * reipl: Re-IPL Linux using setting under /sys/firmware/reipl ++# * dump_reipl: First dump Linux, then re-IPL Linux using setting under ++# /sys/firmware/reipl + # ++ON_PANIC="stop" + +-# For the actions "reipl" and "dump_reipl" the DELAY_MINUTES keyword may +-# be used to delay the activation of dumpconf. +-# Thus potential reipl loops caused by kernel panics +-# which persistently occur early in the boot process can be prevented. ++## Type: integer(0:300) ++## Default: 5 ++## ServiceRestart: dumpconf ++# ++# Using reipl or dump_reipl actions with ON_PANIC can lead to the system ++# looping with alternating IPLs and crashes. Use DELAY_MINUTES to prevent ++# such a loop. DELAY_MINUTES delays activating the specified panic action ++# for a newly started system. When the specified time has elapsed, dumpconf ++# activates the specified panic action. This action is taken should the ++# system subsequently crash. If the system crashes before the time has ++# elapsed the previously defined action is taken. If no previous action has ++# been defined the default action (STOP) is performed. ++# ++DELAY_MINUTES="5" + +-# Dump on CCW device (DASD) and re-IPL after dump is complete. +-# The re-IPL device, as specified under "/sys/firmware/reipl", is used. +-# The activation of dumpconf is delayed by 5 minutes. ++## Type: list(ccw,fcp) ++## Default: "" ++## ServiceRestart: dumpconf ++# ++# Define the type, ccw for DASD and fcp for zFCP. + # +-# ON_PANIC=dump_reipl +-# DUMP_TYPE=ccw +-# DEVICE=0.0.4e13 +-# DELAY_MINUTES=5 ++DUMP_TYPE="" + ++## Type: string ++## Default: "" ++## ServiceRestart: dumpconf + # +-# Dump on fcp device (SCSI Disk) ++# Define the device id for a DASD or SCSI over zFCP dump device. + # +-# ON_PANIC=dump +-# DUMP_TYPE=fcp +-# DEVICE=0.0.4711 +-# WWPN=0x5005076303004711 +-# LUN=0x4711000000000000 +-# BOOTPROG=0 +-# BR_LBA=0 ++# For example (DASD and SCSI over zFCP have the same structure): DEVICE=0.0.4711 ++# ++DEVICE="" + ++## Type: string ++## Default: "" ++## ServiceRestart: dumpconf ++# ++# Define the WWPN for a zFCP dump device. + # +-# Use VMDUMP ++# For example: WWPN=0x5005076303004711 + # +-# ON_PANIC=vmcmd +-# VMCMD_1="MESSAGE * Starting VMDUMP" +-# VMCMD_2="VMDUMP" +-# VMCMD_3="IPL 4711" ++WWPN="" + ++## Type: string ++## Default: "" ++## ServiceRestart: dumpconf ++# ++# Define the LUN for a zFCP dump device. ++# ++# For example: LUN=0x4711000000000000 ++# ++LUN="" ++ ++## Type: integer(0:30) ++## Default: "0" ++## ServiceRestart: dumpconf ++# ++# Define the Boot program selector for a zFCP dump device. ++# ++# A decimal value between 0 and 30 specifying the program to be loaded from ++# the FCP-I/O device. ++# ++BOOTPROG="0" ++ ++## Type: string ++## Default: "0" ++## ServiceRestart: dumpconf ++# ++# Define the Boot record logical block address for a zFCP dump device. + # +-# Stop Linux (default) ++# The hexadecimal digits designating the logical-block address of the boot record of the FCP-I/O device. ++# It must be a value from 0-FFFFFFFF FFFFFFFF. For values longer than 8 hex characters at least one separator ++# blank is required after the 8th character. + # +-# ON_PANIC=stop ++BR_LBA="0" + ++## Type: string ++## Default: "" ++## ServiceRestart: dumpconf + # +-# Re-IPL Linux +-# The re-IPL device, as specified under "/sys/firmware/reipl", is used. +-# Since the DELAY_MINUTES keyword is omitted, there is no delay and +-# dumpconf becomes active immediately during system startup. ++# VMCMD_ ++# Specifies a CP command, is a number from one to eight. You can ++# specify up to eight CP commands that are executed in case of a kernel ++# panic. Note that VM commands, device adresses, and VM guest names ++# must be uppercase. + # +-# ON_PANIC=reipl ++VMCMD_1="" ++VMCMD_2="" ++VMCMD_3="" ++VMCMD_4="" ++VMCMD_5="" ++VMCMD_6="" ++VMCMD_7="" ++VMCMD_8="" +-- +1.8.1.4 + diff --git a/s390-tools-sles12-update-by_id-links-on-change-and-add-action.patch b/s390-tools-sles12-update-by_id-links-on-change-and-add-action.patch new file mode 100644 index 0000000..61f162c --- /dev/null +++ b/s390-tools-sles12-update-by_id-links-on-change-and-add-action.patch @@ -0,0 +1,31 @@ +From f7a0f391f2c4e8acc96b21ab5de54a178aa60088 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Fri, 22 Nov 2013 15:39:38 +0100 +Subject: [PATCH 8/8] 59-dasd.rules: generate by-id links on 'change' and 'add' + +The by-id rules need to be triggered on both, 'change' and 'add', +to work correctly during restarting udev. + +References: bnc#808042 + +Signed-off-by: Robert Milasan +--- + etc/udev/rules.d/59-dasd.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/etc/udev/rules.d/59-dasd.rules b/etc/udev/rules.d/59-dasd.rules +index 2b1435c..a08cb7c 100644 +--- a/etc/udev/rules.d/59-dasd.rules ++++ b/etc/udev/rules.d/59-dasd.rules +@@ -6,7 +6,7 @@ + SUBSYSTEM!="block", GOTO="dasd_symlinks_end" + KERNEL!="dasd*", GOTO="dasd_symlinks_end" + +-ACTION!="change", GOTO="dasd_block_end" ++ACTION!="change|add", GOTO="dasd_block_end" + # by-id (hardware serial number) + KERNEL=="dasd*[!0-9]", ATTRS{status}=="online", IMPORT{program}="/sbin/dasdinfo -a -e -b $kernel" + KERNEL=="dasd*[!0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}" +-- +1.8.1.4 + diff --git a/s390-tools-sles12-zipl_boot_msg.patch b/s390-tools-sles12-zipl_boot_msg.patch new file mode 100644 index 0000000..b933842 --- /dev/null +++ b/s390-tools-sles12-zipl_boot_msg.patch @@ -0,0 +1,13 @@ +--- s390-tools-1.24.1/zipl/boot/menu.c 2013-12-18 11:11:45.000000000 -0500 ++++ s390-tools-1.24.1/zipl/boot/menu.c 2013-12-18 11:59:18.000000000 -0500 +@@ -166,7 +166,9 @@ + menu_list(); + + if (is_zvm()) +- printf("Note: VM users please use '#cp vi vmsg '\n"); ++ printf(" \n"); ++ printf("Note: VM users please use '#cp vi vmsg '\n"); ++ printf(" \n"); + + value = menu_read(); + diff --git a/s390-tools-sles12sp2-chiucvallow-verify.patch b/s390-tools-sles12sp2-chiucvallow-verify.patch new file mode 100644 index 0000000..4cb9479 --- /dev/null +++ b/s390-tools-sles12sp2-chiucvallow-verify.patch @@ -0,0 +1,35 @@ +Subject: [PATCH] [BZ 141695] chiucvallow: correct verification return code +From: Hendrik Brueckner + +Description: chiucvallow: correct verification return code +Symptom: When running test_chiucvallow.sh, the script is + failing to validate filter files with special + characters. + because the chiucvallow.in -V is +Problem: The chiucvallow -V is returning code 2 and for + this reason, the script gives an error message, + but the filter file is validated successfully + manually. +Solution: Correct the return code of chiucvallow to handle + verification failures correctly. +Reproduction: See Symptom. +Upstream-ID: - +Problem-ID: 141695 + +Signed-off-by: Hendrik Brueckner +--- + iucvterm/bin/chiucvallow.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/iucvterm/bin/chiucvallow.in ++++ b/iucvterm/bin/chiucvallow.in +@@ -115,7 +115,8 @@ verify_filter(){ + + printf "\n$PRG: Verification summary: verified=%d failed=%d size=%d bytes\n" \ + $count $failed $fsize +- return 2 ++ ++ test $failed -eq 0 || return 2 + } + + # diff --git a/s390-tools-sles12sp2-chreipl-virtio.patch b/s390-tools-sles12sp2-chreipl-virtio.patch new file mode 100644 index 0000000..6684311 --- /dev/null +++ b/s390-tools-sles12sp2-chreipl-virtio.patch @@ -0,0 +1,49 @@ +Subject: [PATCH] [BZ 143839] chreipl/virtio: fix chreipl node for virtio-blk disks +From: Christian Borntraeger + +Description: chreipl/virtio: fix chreipl node for virtio-blk disks +Symptom: chreipl node for a virtio-blk disk fails: + Could not find DASD CCW device "virtio1" +Problem: The sysfs walking code to resolve the device is not + handling virtio devices correctly. +Solution: Use the realpath of the device to get the busid for all + supported devices. +Reproduction: Run chreipl node with virtio-blk devices as + backing for mount point. +Upstream-ID: - +Problem-ID: 143839 + +Signed-off-by: Christian Borntraeger +--- + ipl_tools/ccw.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/ipl_tools/ccw.c ++++ b/ipl_tools/ccw.c +@@ -76,21 +76,19 @@ out_fclose: + static int ccw_busid_get_sysfs_new(const char *device, char *busid) + { + char path[PATH_MAX], buf[4096]; +- char *ptr; + + memset(buf, 0, sizeof(buf)); + snprintf(path, sizeof(path), "/sys/block/%s/device", device); +- if (readlink(path, buf, sizeof(buf) - 1) == -1) ++ if (realpath(path, buf) == NULL) + return -1; + + /* + * The output has the following format: +- * ../../../0.0.4e13 ++ * /sys/devices/css0/0.0.0119/0.0.3f19/block/dasda ++ * /sys/devices/css0/0.0.0000/0.0.0000/virtio0/block/vda + */ +- ptr = strrchr(buf, '/'); +- if (!ptr) +- ERR_EXIT("Could not read \"%s\"", path); +- strncpy(busid, ptr + 1, 9); ++ if (sscanf(buf, "/sys/devices/css0/%*[0-9a-f.]/%[0-9a-f.]", busid) != 1) ++ return -1; + return 0; + } + diff --git a/s390-tools-sles12sp2-chzdev-disable-root-update.patch b/s390-tools-sles12sp2-chzdev-disable-root-update.patch new file mode 100644 index 0000000..405e9be --- /dev/null +++ b/s390-tools-sles12sp2-chzdev-disable-root-update.patch @@ -0,0 +1,32 @@ +Subject: [PATCH] [BZ 147113] chzdev: Disable root device update mechanism +From: Peter Oberparleiter + +Description: chzdev: Disable root device update mechanism +Symptom: chzdev reports problems updating /etc/zipl.conf and running + zipl. +Problem: When chzdev changes the root device persistent configuration, + it performs additional steps to ensure that these changes are + correctly applied. Example for such steps are: updating the + initial RAM disk, modifying the zipl.conf configuration file + and running zipl. As these steps are incompatible with the target + distribution, they fail. +Solution: Suppress chzdev's root device update mechanism. +Reproduction: chzdev --enable --persistent --by-path / +Upstream-ID: - +Problem-ID: 147113 + +Signed-off-by: Peter Oberparleiter +--- + zdev/src/chzdev.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/zdev/src/chzdev.c ++++ b/zdev/src/chzdev.c +@@ -233,6 +233,7 @@ static void init_options(struct options + opts->settings = strlist_new(); + opts->remove = strlist_new(); + opts->base = strlist_new(); ++ opts->no_root_check = 1; + } + + /* Release memory used in options data structure. */ diff --git a/s390-tools-sles12sp2-feat-01-dasd-query-host.patch b/s390-tools-sles12sp2-feat-01-dasd-query-host.patch new file mode 100644 index 0000000..b9bc686 --- /dev/null +++ b/s390-tools-sles12sp2-feat-01-dasd-query-host.patch @@ -0,0 +1,744 @@ +Subject: [PATCH] [FEAT LS1213] dasd: add query host access to volume support +From: Stefan Haberland + +Summary: dasd: add query host access to volume support +Description: With this feature, applications can query if a DASD volume is + online to another operating system instances by checking the + online status of all attached hosts from the storage server. +Upstream-ID: - +Problem-ID: LS1213 + +Signed-off-by: Stefan Haberland +--- + dasdfmt/dasdfmt.8 | 7 ++ + dasdfmt/dasdfmt.c | 38 ++++++++++++-- + dasdfmt/dasdfmt.h | 4 + + fdasd/fdasd.8 | 9 ++- + fdasd/fdasd.c | 32 ++++++++++++ + fdasd/fdasd.h | 28 +++++----- + include/libzds.h | 1 + include/u2s.h | 5 + + libu2s/u2s.c | 43 ++++++++++++++++ + libzds/Makefile | 2 + libzds/libzds.c | 46 +++++++++++++++-- + zconf/lsdasd | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + zconf/lsdasd.8 | 5 + + zdsfs/zdsfs.1 | 4 + + zdsfs/zdsfs.c | 18 ++++++ + 15 files changed, 345 insertions(+), 36 deletions(-) + +--- a/dasdfmt/dasdfmt.8 ++++ b/dasdfmt/dasdfmt.8 +@@ -7,7 +7,7 @@ dasdfmt \- formatting of DASD (ECKD) dis + .br + [-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR] + .br +- [-L] [-V] [-F] [-k] \fIdevice\fR ++ [-L] [-V] [-F] [-k] [-C] \fIdevice\fR + + .SH DESCRIPTION + \fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it +@@ -70,6 +70,11 @@ Print version number and exit. + Formats the device without checking, if the device is in use. + + .TP ++\fB-C\fR or \fB--check_host_count\fR ++Force dasdfmt to check the host access open count to ensure the device ++is not online on another operating system instance ++ ++.TP + \fB-d\fR \fIlayout\fR or \fB--disk_layout\fR=\fIlayout\fR + Formats the device with compatible disk layout or linux disk layout. + \fIlayout\fR is either \fIcdl\fR for the compatible disk layout +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -18,6 +18,8 @@ + #include "util_proc.h" + #include "dasd_sys.h" + ++#define BUSIDSIZE 8 ++ + /* Full tool name */ + static const char tool_name[] = "dasdfmt: zSeries DASD format program"; + +@@ -46,7 +48,7 @@ print_version (void) + */ + static void exit_usage(int exitcode) + { +- printf("Usage: %s [-htvypPLVFk]\n" ++ printf("Usage: %s [-htvypPLVFkC]\n" + " [-l | --label=]\n" + " [-b | --blocksize=]\n" + " [-d | --disk_layout=]\n" +@@ -65,6 +67,9 @@ static void exit_usage(int exitcode) + " -v means verbose mode\n" + " -F means don't check if the device is in use\n" + " -k means keep volume serial\n" ++ " -C or --check_host_count means force dasdfmt to check\n" ++ " the host access open count to ensure the device\n" ++ " is not online on another operating system instance\n" + " --norecordzero prevent storage server from modifying" + " record 0\n\n" + " is the volume identifier, which is converted\n" +@@ -190,7 +195,6 @@ static void get_device_name(dasdfmt_info + } + } + +- + /* + * initialize the dasdfmt info structure + */ +@@ -214,6 +218,7 @@ static void init_info(dasdfmt_info_t *in + info->node_specified = 0; + info->device_id = 0; + info->keep_volser = 0; ++ info->force_host = 0; + } + + +@@ -776,6 +781,7 @@ static void do_format_dasd(dasdfmt_info_ + dasd_information_t dasd_info; + struct dasd_eckd_characteristics *characteristics; + unsigned int cylinders, heads; ++ int count; + + if (info->verbosity > 0) printf("Retrieving disk geometry...\n"); + +@@ -835,6 +841,27 @@ static void do_format_dasd(dasdfmt_info_ + if ((info->verbosity > 0) || (!info->withoutprompt)) + dasdfmt_print_info(info, vlabel, cylinders, heads, p); + ++ count = u2s_get_host_access_count(info->devname); ++ if (info->force_host) { ++ if (count > 1) { ++ ERRMSG_EXIT(EXIT_FAILURE, ++ "\n%s: Disk %s is online on OS instances in %d different LPARs.\n" ++ "Note: Your installation might include z/VM systems that are configured to\n" ++ "automatically vary on disks, regardless of whether they are subsequently used.\n\n", ++ prog_name, info->devname, count); ++ } else if (count < 0) { ++ ERRMSG("\nHosts access information not available for disk %s.\n\n", ++ info->devname); ++ return; ++ } ++ } else if (count > 1) ++ ERRMSG("\nWARNING:\n" ++ "Disk %s is online on operating system instances in %d different LPARs.\n" ++ "Ensure that the disk is not being used by a system outside your LPAR.\n" ++ "Note: Your installation might include z/VM systems that are configured to\n" ++ "automatically vary on disks, regardless of whether they are subsequently used.\n", ++ info->devname, count); ++ + if (!info->testmode) { + if (!info->withoutprompt) { + printf("\n--->> ATTENTION! <<---\n"); +@@ -916,10 +943,6 @@ int main(int argc,char *argv[]) + info.force=1; + break; + +- case 'C': +- format_params.intensity |= DASD_FMT_INT_COMPAT; +- break; +- + case 'd' : + if (strncmp(optarg,"cdl",3)==0) + { +@@ -1017,6 +1040,9 @@ int main(int argc,char *argv[]) + case 'k' : + info.keep_volser=1; + break; ++ case 'C': ++ info.force_host = 1; ++ break; + case -1: + /* End of options string - start of devices list */ + info.device_id = optind; +--- a/dasdfmt/dasdfmt.h ++++ b/dasdfmt/dasdfmt.h +@@ -214,7 +214,7 @@ typedef struct format_data_t { + if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ + "is in invalid format\n",prog_name);} + +-#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpPLtyvVFk" ++#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpPLtyvVFkC" + + static struct option dasdfmt_getopt_long_options[]= + { +@@ -233,6 +233,7 @@ static struct option dasdfmt_getopt_long + { "help", 0, 0, 'h'}, + { "keep_volser", 0, 0, 'k'}, + { "norecordzero", 0, 0, 'z'}, ++ { "check_host_count", 0, 0, 'C'}, + {0, 0, 0, 0} + }; + +@@ -265,6 +266,7 @@ typedef struct dasdfmt_info { + int node_specified; + int device_id; + int keep_volser; ++ int force_host; + } dasdfmt_info_t; + + +--- a/fdasd/fdasd.8 ++++ b/fdasd/fdasd.8 +@@ -4,11 +4,11 @@ fdasd \- partitioning tool. + .SH SYNOPSIS + interactive mode: + .br +- \fBfdasd\fR [-s] [-r] \fIdevice\fR ++ \fBfdasd\fR [-s] [-r] [-C] \fIdevice\fR + .br + command line mode: + .br +- \fBfdasd\fR [-s] [-r] {-a[-k|-l \fIvolser\fR]|-i|-p|-c \fIconf_file\fR} ++ \fBfdasd\fR [-s] [-r] [-C] {-a[-k|-l \fIvolser\fR]|-i|-p|-c \fIconf_file\fR} + [-f \fI[type,blocksize]\fR] \fIdevice\fR + .br + help: +@@ -131,6 +131,11 @@ In combination with the -s option fdasd + partition table. + + .TP ++\fB-C\fR or \fB--check_host_count\fR ++Force fdasd to check the host access open count to ensure the device ++is not online on another operating system instance ++ ++.TP + \fB-f\fR \fI[type,blocksize]\fR or \fB--force\fR \fI[type,blocksize]\fR + Force fdasd to work on non DASD devices. + .br +--- a/fdasd/fdasd.c ++++ b/fdasd/fdasd.c +@@ -369,7 +369,10 @@ fdasd_usage (void) + " found in CONFIGFILE\n" + "-i, --volser Print volume serial\n" + "-p, --table Print partition table\n" +- "-f, --force Force fdasd to work on non DASD devices\n"); ++ "-f, --force Force fdasd to work on non DASD devices\n" ++ "-C, --check_host_count Force fdasd to check the host access\n" ++ " open count to ensure the device is not\n" ++ " online on another operating system instance\n"); + } + + +@@ -572,6 +575,9 @@ fdasd_parse_options (fdasd_anchor_t *anc + anc->force_virtual++; + fdasd_parse_force_options(anc, optarg); + break; ++ case 'C': ++ anc->force_host++; ++ break; + case -1: + /* End of options string - start of devices list */ + break; +@@ -824,6 +830,7 @@ fdasd_verify_device (fdasd_anchor_t *anc + { + struct stat dst; + char err_str[ERROR_STRING_SIZE]; ++ int count; + + if ((stat(name, &dst)) < 0 ) { + snprintf(err_str, ERROR_STRING_SIZE, +@@ -856,6 +863,29 @@ fdasd_verify_device (fdasd_anchor_t *anc + fdasd_error(anc, device_verification_failed, err_str); + } + ++ count = u2s_get_host_access_count(name); ++ if (anc->force_host) { ++ if (count > 1) { ++ snprintf(err_str, ERROR_STRING_SIZE, ++ "Disk %s is online on operating system instances in %d different LPARs.\n" ++ "Note: Your installation might include z/VM systems that are configured to\n" ++ "automatically vary on disks, regardless of whether they are subsequently used.\n", ++ name, count); ++ fdasd_error(anc, device_verification_failed, err_str); ++ } else if (count < 0) { ++ snprintf(err_str, ERROR_STRING_SIZE, ++ "Hosts access information not available for disk %s.\n", ++ name); ++ fdasd_error(anc, device_verification_failed, err_str); ++ } ++ } else if (count > 1) ++ printf("\nWARNING:\n" ++ "Disk %s is online on operating system instances in %d different LPARs.\n" ++ "Ensure that the disk is not being used by a system outside your LPAR.\n" ++ "Note: Your installation might include z/VM systems that are configured to\n" ++ "automatically vary on disks, regardless of whether they are subsequently used.\n\n", ++ name, count); ++ + if (anc->verbose) + printf("Verification successful for '%s' (%d/%d)\n", name, + (unsigned short) major(dst.st_rdev), +--- a/fdasd/fdasd.h ++++ b/fdasd/fdasd.h +@@ -157,22 +157,23 @@ struct dasd_eckd_characteristics { + #define PARTITION_GPFS 5 + + static struct option fdasd_long_options[] = { +- { "version", no_argument, NULL, 'v'}, +- { "auto", no_argument, NULL, 'a'}, +- { "silent", no_argument, NULL, 's'}, +- { "verbose", no_argument, NULL, 'r'}, +- { "label", required_argument, NULL, 'l'}, +- { "config", required_argument, NULL, 'c'}, +- { "help", no_argument, NULL, 'h'}, +- { "table", no_argument, NULL, 'p'}, +- { "volser", no_argument, NULL, 'i'}, +- { "keep_volser", no_argument, NULL, 'k'}, +- { "force", optional_argument, NULL, 'f'}, +- { 0, 0, 0, 0 } ++ { "version", no_argument, NULL, 'v'}, ++ { "auto", no_argument, NULL, 'a'}, ++ { "silent", no_argument, NULL, 's'}, ++ { "verbose", no_argument, NULL, 'r'}, ++ { "label", required_argument, NULL, 'l'}, ++ { "config", required_argument, NULL, 'c'}, ++ { "help", no_argument, NULL, 'h'}, ++ { "table", no_argument, NULL, 'p'}, ++ { "volser", no_argument, NULL, 'i'}, ++ { "keep_volser", no_argument, NULL, 'k'}, ++ { "force", optional_argument, NULL, 'f'}, ++ { "check_host_count", no_argument, NULL, 'C'}, ++ { 0, 0, 0, 0 } + }; + + /* Command line option abbreviations */ +-static const char option_string[] = "vasrl:c:hpikf::"; ++static const char option_string[] = "vasrl:c:hpikf::C"; + + struct fdasd_options { + char *device; +@@ -214,6 +215,7 @@ typedef struct fdasd_anchor { + int print_volser; + int keep_volser; + int force_virtual; ++ int force_host; + int big_disk; + int silent; + int verbose; +--- a/include/libzds.h ++++ b/include/libzds.h +@@ -803,6 +803,7 @@ int lzds_zdsroot_extract_datasets_from_d + void lzds_DS1RECFM_to_recfm(char DS1RECFM, char *buffer); + + ++int lzds_analyse_open_count(struct zdsroot *root, int warn); + + /** @} */ /* end of group libzds_functions_helper */ + +--- a/include/u2s.h ++++ b/include/u2s.h +@@ -13,7 +13,8 @@ + + #define U2S_BUS_ID_SIZE 32 + +-int +-u2s_getbusid(char * devicenode, char * busid); ++int u2s_getbusid(char *, char *); ++int u2s_read_attribute(char *, char *, char *, size_t); ++int u2s_get_host_access_count(char *); + + #endif /* U2S_H */ +--- a/libu2s/u2s.c ++++ b/libu2s/u2s.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include "u2s.h" + +@@ -282,3 +283,45 @@ int u2s_getbusid(char *devicenode, char + + return rc; + } ++ ++/* ++ * Attempts to find the sysfs entry for the given busid and reads ++ * the contents of a specified attribute to the buffer ++ */ ++int u2s_read_attribute(char *busid, char *attribute, char *buffer, ++ size_t count) ++{ ++ char path[100]; ++ int rc, fd; ++ ssize_t rcount; ++ ++ rc = 0; ++ snprintf(path, sizeof(path), "/sys/bus/ccw/devices/%s/%s", ++ busid, attribute); ++ fd = open(path, O_RDONLY); ++ if (fd < 0) ++ return errno; ++ rcount = read(fd, buffer, count); ++ if (rcount < 0) ++ rc = errno; ++ close(fd); ++ return rc; ++} ++ ++int u2s_get_host_access_count(char *devicenode) ++{ ++ char busid[BUSIDSIZE]; ++ unsigned long value; ++ char buffer[10]; ++ char *endp; ++ ++ u2s_getbusid(devicenode, busid); ++ u2s_read_attribute(busid, "host_access_count", buffer, sizeof(buffer)); ++ ++ value = strtoul(buffer, &endp, 0); ++ ++ if (endp == buffer) ++ return -EINVAL; ++ ++ return value; ++} +--- a/libzds/Makefile ++++ b/libzds/Makefile +@@ -8,7 +8,7 @@ CFLAGS += -D_FILE_OFFSET_BITS=64 + + all: libzds.a + +-libzds.a: libzds.o $(rootdir)/libutil/util_list.o $(rootdir)/libvtoc/vtoc.o ++libzds.a: libzds.o $(rootdir)/libutil/util_list.o $(rootdir)/libvtoc/vtoc.o $(rootdir)/libu2s/u2s.o + + libzds.o: ../include/libzds.h + +--- a/libzds/libzds.c ++++ b/libzds/libzds.c +@@ -29,6 +29,7 @@ + #include "libzds.h" + + #include "util.h" ++#include "u2s.h" + + #include + #include +@@ -72,6 +73,8 @@ struct errorlog { + */ + #define ERRORMSG 240 + ++#define BUSIDSIZE 8 ++ + /** + * @brief An internal structure that represents an entry in the error log. + */ +@@ -3760,15 +3763,46 @@ void lzds_DS1RECFM_to_recfm(char DS1RECF + */ + } + ++int lzds_analyse_open_count(struct zdsroot *root, int warn) ++{ ++ struct dasd *dasd; ++ int value; ++ int rc = 0; + ++ util_list_iterate(root->dasdlist, dasd) { ++ value = u2s_get_host_access_count(dasd->device); + ++ if (value < 0) { ++ fprintf(stderr, ++ "Hosts access information not available for disk %s.\n", ++ dasd->device); ++ rc = value; ++ continue; ++ } + ++ if (value == 1) ++ continue; + ++ if (warn) ++ fprintf(stderr, ++ "\nWARNING:\n" ++ "Disk %s is online on operating system instances in %d different LPARs.\n" ++ "Ensure that the disk is not being used by a system outside your LPAR.\n" ++ "Note: Your installation might include z/VM systems that are configured to\n" ++ "automatically vary on disks, regardless of whether they are subsequently used.\n", ++ dasd->device, value); ++ else { ++ fprintf(stderr, ++ "\nERROR:\n" ++ "Disk %s is online on operating system instances in %d different LPARs.\n" ++ "Ensure that the disk is not being used by a system outside your LPAR.\n" ++ "Note: Your installation might include z/VM systems that are configured to\n" ++ "automatically vary on disks, regardless of whether they are subsequently used.\n", ++ dasd->device, value); ++ rc = -EACCES; ++ } ++ } + +- +- +- +- +- +- ++ return rc; ++} + +--- a/zconf/lsdasd ++++ b/zconf/lsdasd +@@ -30,6 +30,8 @@ function PrintUsage() { + Print old version of lsdasd output. + -l|--long + Print extended information about DASDs. ++ -H|--host-access-list ++ Print information about hosts accessing DASDs. + -v|--verbose + For compatibility/future use. Currently ignored. + --version +@@ -115,6 +117,33 @@ function listDASDDeviceDirectories() { + } + + #------------------------------------------------------------------------------ ++# find dasd directory in debugfs ++#------------------------------------------------------------------------------ ++function findDASDDebugfsDirectorie() { ++ local mntentries ++ ++ while read -a mntentries ++ do ++ if [[ "${mntentries[2]}" == "debugfs" ]] ++ then ++ DASD_DBF_DIR="${mntentries[1]}" ++ break; ++ fi ++ done < /etc/mtab ++ if [[ "$DASD_DBF_DIR" == "" ]] ++ then ++ echo "$CMD: No debugfs mount point found" >&2 ++ exit 1 ++ fi ++ DASD_DBF_DIR="$DASD_DBF_DIR/dasd" ++ if [[ ! -d "$DASD_DBF_DIR" ]] ++ then ++ echo "$CMD: Default DASD debugfs directory $DASD_DBF_DIR does not exist" >&2 ++ exit 1 ++ fi ++} ++ ++#------------------------------------------------------------------------------ + # gather device data and call appropriate output function + #------------------------------------------------------------------------------ + function gatherDeviceData() { +@@ -197,6 +226,8 @@ function gatherDeviceData() { + extended + elif [[ "$PRINTUID" == "true" ]]; then + uid ++ elif [[ "$OUTPUT" == "host" ]]; then ++ host + else + newoutput + fi +@@ -527,6 +558,104 @@ function extended() + "${HPF_PATHS[@]}" ; + } + ++function host() ++{ ++findDASDDebugfsDirectorie ++ ++if [[ ! -f "$DASD_DBF_DIR/$BUSID/host_access_list" ]] ++then ++ printf "\n%s: hosts access information not available\n" "$BUSID" ++ return ++fi ++ ++local temp=`mktemp /tmp/lsdasd.XXXXXX` ++if test -w $temp ; then :; else ++ printf "\nCreating temporary file failed\n" ++ return ++fi ++ ++cat $DASD_DBF_DIR/$BUSID/host_access_list > $temp 2> /dev/null ++ret=$? ++if [[ $ret -ne 0 ]] ++then ++ printf "%s: hosts access information not available\n" "$BUSID" ++ rm -f $temp ++ return $ret ++fi ++ ++unset index ++unset array ++declare -a array ++ ++index=(pgid status_flags sysplex_name supported_cylinder timestamp) ++ ++for element in ${index[@]} ++do ++ count=0 ++ ++ declare -a $element ++ OLDIFS=$IFS ++ IFS=$'\n' ++ for value in `grep $element $temp` ++ do ++ (( ++count )) ++ value=$(echo -e $value | cut -d ' ' -f2) ++ eval $element[$count]=$value ++ done ++ IFS=$OLDIFS ++done ++ ++printf "Host information for %s\n" "$BUSID"; ++printf "Path-Group-ID LPAR CPU FL Status Sysplex Max_Cyls Time\n"; ++printf "================================================================================\n"; ++ ++# mask bits for online and reserved state ++online_reserved_mask=0xE0 ++ ++# print name value lists ++for i in `seq 1 $count`; ++do ++ # get flags field ++ value=${status_flags[$i]} ++ # mark as hex value ++ value=0x$value ++ # mask online and reserved bits ++ value=$(($value & $online_reserved_mask)) ++ ++ case $value in ++ 0 ) # 0x00 ++ STATE="OFF" ++ ;; ++ 32 ) # 0x20 ++ STATE="OFF-RSV" ++ ;; ++ 64 ) # 0x40 ++ STATE="ON" ++ ;; ++ 96 ) # 0x60 ++ STATE="ON-RSV" ++ ;; ++ * ) ++ STATE="-" ++ ;; ++ esac ++ ++ printf "%22s %02s %07s %02s %-6s %-8s %11u %10lu\n" \ ++ "${pgid[$i]}" \ ++ "${pgid[$i]:4:2}" \ ++ "${pgid[$i]:6:4}" \ ++ "${status_flags[$i]}" \ ++ "$STATE" \ ++ "${sysplex_name[$i]}" \ ++ "${supported_cylinder[$i]}" \ ++ "${timestamp[$i]}" \ ++ ; ++done ++printf "\n"; ++ ++rm -f $temp ++} ++ + function uid() + { + #-------------------------------------------# +@@ -586,6 +715,9 @@ while [ $# -gt 0 ]; do + --long|-l) + OUTPUT="extended" + ;; ++ --host-access-list|-H) ++ OUTPUT="host" ++ ;; + --version) + PrintVersion + exit 0 +@@ -626,8 +758,13 @@ fi + + # gather information on devices in list + PROCESSING=" $PROCESSING | gatherDeviceData " ++ + # sort resulting list +-PROCESSING=" $PROCESSING | sort -t: -k1n -k2 | cut -d: -f3- " ++if [[ "$OUTPUT" == "host" ]]; then ++ PROCESSING=" $PROCESSING" ++else ++ PROCESSING=" $PROCESSING | sort -t: -k1n -k2 | cut -d: -f3- " ++fi + + if [[ "$PRINTUID" == "true" ]] && [[ "$OUTPUT" != "old" ]]; then + printf "Bus-ID Name UID\n" +--- a/zconf/lsdasd.8 ++++ b/zconf/lsdasd.8 +@@ -40,11 +40,14 @@ Include only base devices. + Old output of lsdasd for compatibility. + .TP + .BR -l | --long +-Extended output of lsdasd including UID, attributes and path information. ++Extended output of lsdasd including UID and attributes. + .TP + .BR -u | --uid + Output includes and is sorted by UID. + .TP ++.BR -H | --host-acces ++Show information about all hosts using this device. ++.TP + .BR -v | --verbose + Only for compatibility (and maybe future) use. This option currently does + nothing. +--- a/zdsfs/zdsfs.1 ++++ b/zdsfs/zdsfs.1 +@@ -150,6 +150,10 @@ If \fI\fR is set to 0, no seek histor + case `seek' is still supported, but a `seek' operation might result in a + read from the beginning of the data set. + ++.TP ++\fB\-o\fR check_host_count ++Stop processing if the device is used by another operating system instance. ++ + .SS "Applicable FUSE options (version 2.8):" + This is a selected subset of all FUSE options. Use the zdsfs + \fB\--help\fR option to print a full list. +--- a/zdsfs/zdsfs.c ++++ b/zdsfs/zdsfs.c +@@ -39,6 +39,7 @@ struct zdsfs_info { + int devcount; + int allow_inclomplete_multi_volume; + int keepRDW; ++ int host_count; + unsigned int tracks_per_frame; + unsigned long long seek_buffer_size; + struct zdsroot *zdsroot; +@@ -765,6 +766,7 @@ static const struct fuse_opt zdsfs_opts[ + FUSE_OPT_KEY("seekbuffer=", KEY_SEEKBUFFER), + ZDSFS_OPT("rdw", keepRDW, 1), + ZDSFS_OPT("ignore_incomplete", allow_inclomplete_multi_volume, 1), ++ ZDSFS_OPT("check_host_count", host_count, 1), + FUSE_OPT_END + }; + +@@ -790,7 +792,10 @@ static void usage(const char *progname) + " data set are missing\n" + " -o tracks=N Size of the track buffer in tracks (default 128)\n" + " -o seekbuffer=S Upper limit in bytes for the seek history buffer\n" +-" size (default 1048576)\n", progname); ++" size (default 1048576)\n" ++" -o check_host_count Stop processing if the device is used by another\n" ++" operating system instance\n" ++ , progname); + } + + static void zdsfs_process_device(const char *device) +@@ -1014,6 +1019,17 @@ int main(int argc, char *argv[]) + argv[0]); + exit(1); + } ++ ++ if (zdsfsinfo.host_count) { ++ /* check, print error and exit if multiple online */ ++ rc = lzds_analyse_open_count(zdsfsinfo.zdsroot, 0); ++ if (rc == -EACCES) ++ goto cleanup; ++ } else { ++ /* check, print warning if multiple online */ ++ lzds_analyse_open_count(zdsfsinfo.zdsroot, 1); ++ } ++ + rc = zdsfs_verify_datasets(); + if (rc) + goto cleanup; diff --git a/s390-tools-sles12sp2-libu2s-Fix-busid-parsing.patch b/s390-tools-sles12sp2-libu2s-Fix-busid-parsing.patch new file mode 100644 index 0000000..5283fe9 --- /dev/null +++ b/s390-tools-sles12sp2-libu2s-Fix-busid-parsing.patch @@ -0,0 +1,37 @@ +Subject: [PATCH] [BZ 140500] libu2s: Fix busid parsing +From: Jan Höppner + +Description: libu2s: Fix busid parsing +Symptom: dasdview displays a wrong busid and shows the error message + "Error: dasdview: Could not retrieve raw_track_access mode + information.", which is wrong as well. +Problem: dasdview retrieves the busid information from libu2s. Whenever + an FBA DASD is listed prior to the target DASD in + /proc/dasd/devices, the parsing will fail due to an additional + whitespace character. For example, an entry for ECKD devices + starts with "0.0.5e30(ECKD)...", while an entry for FBA starts + with "0.0.8000(FBA )...". +Solution: Change the busid parsing in libu2s by explicitly looking for the + closing bracket. +Reproduction: Add an FBA device and then an ECKD device to the system and use + dasdview to display information about the ECKD device. + # dasdview -i /dev/dasdX +Upstream-ID: - +Problem-ID: 140500 + +Signed-off-by: Jan Höppner +--- + libu2s/u2s.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/libu2s/u2s.c ++++ b/libu2s/u2s.c +@@ -237,7 +237,7 @@ static int find_busid_in_proc(int maja, + filp = fopen("/proc/dasd/devices", "r"); + if (!filp) + return rc; +- while (fscanf(filp, "%[^(] %*s at ( %d : %d %*[^\n]\n", ++ while (fscanf(filp, "%[^(] %*[^)] ) at ( %d : %d %*[^\n]\n", + bus, &majb, &minb) != EOF) { + if ((maja == majb) && (mina == minb)) { + strncpy(busid, bus, BUSIDSIZE + 1); diff --git a/s390-tools-sles12sp2-lscss-allow-to-specify-devices-from-ssid-3.patch b/s390-tools-sles12sp2-lscss-allow-to-specify-devices-from-ssid-3.patch new file mode 100644 index 0000000..9677209 --- /dev/null +++ b/s390-tools-sles12sp2-lscss-allow-to-specify-devices-from-ssid-3.patch @@ -0,0 +1,37 @@ +Subject: lscss: allow to specify devices from ssid > 2 +From: Sebastian Ott + +Description: lscss: allow to specify devices from ssid > 2 +Symptom: Specifying devices with ssid > 2 results in: + "Syntax error: 0.3.0000" +Problem: SSIDs > 2 are disallowed +Solution: allow SSIDs > 2 +Reproduction: lscss 0.3.0000 +Upstream-ID: - +Problem-ID: 150872 + +Signed-off-by: Sebastian Ott +--- + zconf/lscss | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/zconf/lscss ++++ b/zconf/lscss +@@ -61,7 +61,7 @@ SUBCHANNEL_TYPE_IO=0 + SUBCHANNEL_TYPE_CHSC=1 + SUBCHANNEL_TYPE_EADM=3 + +-IDFORMAT=[[:xdigit:]]*.[0-3].[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]] ++IDFORMAT=[[:xdigit:]]*.[[:xdigit:]].[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]] + + unset SCH_IO SCH_CHSC SCH_EADM SHOW_AVAIL UPPERCASE SHORTID DEVTYPES DEVRANGE + unset RANGE SHOW_VPM +@@ -81,7 +81,7 @@ function check_id() #return 0 if $1 has + fi + ;; + 3) +- if [ ${#__ID[2]} != 4 -o ${#__ID[1]} != 1 -o "${__ID[1]//[012]/}" \ ++ if [ ${#__ID[2]} != 4 -o ${#__ID[1]} != 1 \ + -o \( ${#__ID[0]} != 2 -a ${#__ID[0]} != 1 \) ] ;then + return 1 + fi diff --git a/s390-tools-sles12sp2-zipl-fix-failed-start-subchannel.patch b/s390-tools-sles12sp2-zipl-fix-failed-start-subchannel.patch new file mode 100644 index 0000000..68f199c --- /dev/null +++ b/s390-tools-sles12sp2-zipl-fix-failed-start-subchannel.patch @@ -0,0 +1,35 @@ +Subject: [PATCH] [BZ 143050] zipl/boot: fix failed start subchannel in FBA loader +From: Stefan Haberland + +Description: zipl/boot: fix failed start subchannel in FBA loader +Symptom: IPL of a FBA device fails with: + Start subchannel failed + disabled wait PSW 00020000 80000000 00000000 00004502 +Problem: The FBA loader has only a limited amount of memory to build CCW + requests. Therefore larger I/O requests need to be split. + This splitting was off by one leading to the fact that one CCW + request uses memory of another data structure which in turn leads + to corrupted data. +Solution: Fix by correcting the split rule. +Reproduction: IPL a FBA device. + The error might occur randomly depending on the size of the + kernel image and offsets within it. +Upstream-ID: - +Problem-ID: 143050 + +Signed-off-by: Stefan Haberland +--- + zipl/boot/fba2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/zipl/boot/fba2.c ++++ b/zipl/boot/fba2.c +@@ -59,7 +59,7 @@ restart: + memset(irb, 0, sizeof(struct irb)); + memset(&orb, 0, sizeof(struct orb)); + +- if (blockptr->blockct > MAX_BLOCKCT) { ++ if (blockptr->blockct >= MAX_BLOCKCT) { + record_number = MAX_BLOCKCT - 1; + blockptr->blockct -= MAX_BLOCKCT; + } else { diff --git a/s390-tools-sles12sp3-dasdfmt-01-Fix-behaviour-of-t-combined-with-y.patch b/s390-tools-sles12sp3-dasdfmt-01-Fix-behaviour-of-t-combined-with-y.patch new file mode 100644 index 0000000..f05316c --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-01-Fix-behaviour-of-t-combined-with-y.patch @@ -0,0 +1,42 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: 9e49066f5c779e6591b06d2276add744ea8ca4d0 +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Fix behaviour of -t combined with -y + + When -t (testmode) is being combined with -y (noprompt), the + informations about what dasdfmt *would* do, is not being displayed. + + Simply fix this by checking whether testmode is set. + + Signed-off-by: Jan Höppner + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -894,7 +894,7 @@ static void do_format_dasd(dasdfmt_info_ + vtoc_volume_label_set_label(vlabel, "LNX1"); + } + +- if ((info->verbosity > 0) || (!info->withoutprompt)) ++ if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) + dasdfmt_print_info(info, vlabel, cylinders, heads, p); + + count = u2s_get_host_access_count(info->devname); diff --git a/s390-tools-sles12sp3-dasdfmt-02-Fix-trailing-whitespace.patch b/s390-tools-sles12sp3-dasdfmt-02-Fix-trailing-whitespace.patch new file mode 100644 index 0000000..73f49ff --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-02-Fix-trailing-whitespace.patch @@ -0,0 +1,250 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Fix trailing whitespace + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 58 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 29 insertions(+), 29 deletions(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -133,7 +133,7 @@ static void program_interrupt_signal (in + + rc = close(filedes); + if (rc) +- ERRMSG("%s: (signal handler) Unable to close device (%s)\n", ++ ERRMSG("%s: (signal handler) Unable to close device (%s)\n", + prog_name, strerror(errno)); + + signal (sig, SIG_DFL); +@@ -329,7 +329,7 @@ retry: + + + /* +- * check the volume serial for special ++ * check the volume serial for special + * characters and move blanks to the end + */ + static int check_volser(char *s, int devno) +@@ -345,7 +345,7 @@ static int check_volser(char *s, int dev + s[i] = ' '; + s[i] = toupper(s[i]); + } +- s[6] = 0x00; ++ s[6] = 0x00; + + for (i=0; i<6; i++) { + if (s[i] == ' ') +@@ -416,16 +416,16 @@ static format_data_t ask_user_for_blksiz + break; + + rc = sscanf(buffer,"%d%c", ¶ms.blksize, &c); +- if ((rc == 2) && (c == '\n')) ++ if ((rc == 2) && (c == '\n')) + rc = 1; +- if (rc == -1) ++ if (rc == -1) + rc = 1; /* this happens, if enter is pressed */ +- if (rc != 1) ++ if (rc != 1) + printf(" -- wrong input, try again.\n"); + + if (check_param(str, ERR_LENGTH, ¶ms) < 0) { +- printf(" -- %s\n",str); +- rc = 0; ++ printf(" -- %s\n",str); ++ rc = 0; + } + } while (rc != 1); + +@@ -479,7 +479,7 @@ static int dasdfmt_get_volser(char * dev + volume_label_t vlabel; + + if ((f = open(devname, O_RDONLY)) == -1) +- ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n", ++ ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n", + prog_name, devname, strerror(errno)); + + if (ioctl(f, BIODASDINFO, &dasd_info) != 0) +@@ -491,7 +491,7 @@ static int dasdfmt_get_volser(char * dev + "failed (%s).\n", prog_name, strerror(errno)); + + if (close(f) != 0) +- ERRMSG("%s: error during close: %s\ncontinuing...\n", ++ ERRMSG("%s: error during close: %s\ncontinuing...\n", + prog_name, strerror(errno)); + + if ((strncmp(dasd_info.type, "ECKD", 4) == 0) && +@@ -505,7 +505,7 @@ static int dasdfmt_get_volser(char * dev + return -1; + } + } +- ++ + /* + * do all the labeling (volume label and initial VTOC) + */ +@@ -577,7 +577,7 @@ static void dasdfmt_write_labels(dasdfmt + rc = lseek(filedes, label_position, SEEK_SET); + if (rc != label_position) + ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed " +- "(%s).\n", prog_name, label_position, ++ "(%s).\n", prog_name, label_position, + strerror(errno)); + + rc = write(filedes, ipl2_record, ipl2_record_len); +@@ -633,9 +633,9 @@ static void dasdfmt_write_labels(dasdfmt + rc = lseek(filedes, label_position, SEEK_SET); + if (rc != label_position) + ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed " +- "(%s).\n", prog_name, label_position, ++ "(%s).\n", prog_name, label_position, + strerror(errno)); +- ++ + /* write VTOC FMT4 DSCB */ + rc = write(filedes, &f4, sizeof(format4_label_t)); + if (rc != sizeof(format4_label_t)) +@@ -695,21 +695,21 @@ static void dasdfmt_format(dasdfmt_info_ + "using the default.\n"); + info->hashstep = 10; + } +- ++ + if(!info->yast_mode) printf("Printing hashmark every %d cylinders.\n", + info->hashstep); + } + + format_step.blksize = format_params->blksize; + format_step.intensity = format_params->intensity; +- ++ + k = 0; + cyl = 1; + if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) + printf("\n"); + + while (1) { +- p1 = -1; ++ p1 = -1; + p2 = 0; + if (k + heads * reqsize >= format_params->stop_unit) + reqsize = 1; +@@ -734,7 +734,7 @@ static void dasdfmt_format(dasdfmt_info_ + tmp = cyl*50/cylinders; + for (j=1; j<=tmp; j++) + printf("#"); +- for (j=tmp+1; j<=50; j++) ++ for (j=tmp+1; j<=50; j++) + printf("-"); + printf("|%3d%%", p1); + } +@@ -758,15 +758,15 @@ static void dasdfmt_format(dasdfmt_info_ + k += reqsize * heads; + cyl += reqsize; + } +- else ++ else + k += format_params->stop_unit % heads; + +- if (k > format_params->stop_unit) ++ if (k > format_params->stop_unit) + break; + } + + if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) +- printf("\n\n"); ++ printf("\n\n"); + } + + +@@ -790,7 +790,7 @@ static void dasdfmt_prepare_and_format ( + + if (ioctl(filedes, BIODASDDISABLE, p) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " +- "BIODASDDISABLE failed. (%s)\n", prog_name, ++ "BIODASDDISABLE failed. (%s)\n", prog_name, + strerror(errno)); + disk_disabled = 1; + +@@ -798,7 +798,7 @@ static void dasdfmt_prepare_and_format ( + + if (ioctl(filedes, BIODASDFMT, &temp) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (invalidate first track) IOCTL " +- "BIODASDFMT failed. (%s)\n", prog_name, ++ "BIODASDFMT failed. (%s)\n", prog_name, + strerror(errno)); + + /* except track 0 from standard formatting procss */ +@@ -814,14 +814,14 @@ static void dasdfmt_prepare_and_format ( + + if (ioctl(filedes, BIODASDFMT, &temp) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (re-validate first track) IOCTL" +- " BIODASDFMT failed (%s)\n", prog_name, ++ " BIODASDFMT failed (%s)\n", prog_name, + strerror(errno)); + + if (info->verbosity > 0) printf("Re-accessing the device...\n"); + + if (ioctl(filedes, BIODASDENABLE, p) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " +- "BIODASDENABLE failed. (%s)\n", prog_name, ++ "BIODASDENABLE failed. (%s)\n", prog_name, + strerror(errno)); + disk_disabled = 0; + } +@@ -830,7 +830,7 @@ static void dasdfmt_prepare_and_format ( + /* + * + */ +-static void do_format_dasd(dasdfmt_info_t *info, format_data_t *p, ++static void do_format_dasd(dasdfmt_info_t *info, format_data_t *p, + volume_label_t *vlabel) + { + char inp_buffer[5]; +@@ -943,7 +943,7 @@ static void do_format_dasd(dasdfmt_info_ + if (!info->yast_mode) + printf("Finished formatting the device.\n"); + +- if (!info->writenolabel) ++ if (!info->writenolabel) + dasdfmt_write_labels(info, vlabel, cylinders, heads); + + if (!info->yast_mode) +@@ -959,7 +959,7 @@ static void do_format_dasd(dasdfmt_info_ + } + + +-int main(int argc,char *argv[]) ++int main(int argc,char *argv[]) + { + dasdfmt_info_t info; + volume_label_t vlabel; +@@ -1001,7 +1001,7 @@ int main(int argc,char *argv[]) + rc=getopt_long(argc, argv, dasdfmt_getopt_string, + dasdfmt_getopt_long_options, &index); + +- switch (rc) ++ switch (rc) + { + case 'F': + info.force=1; diff --git a/s390-tools-sles12sp3-dasdfmt-03-Apply-coding-convention.patch b/s390-tools-sles12sp3-dasdfmt-03-Apply-coding-convention.patch new file mode 100644 index 0000000..bda753a --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-03-Apply-coding-convention.patch @@ -0,0 +1,892 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Apply coding convention + + Improve the overall readability of the code by applying the Kernel + coding convention. + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 362 +++++++++++++++++++++++++----------------------------- + 1 file changed, 171 insertions(+), 191 deletions(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -37,11 +37,10 @@ int reqsize; + /* + * Print version information. + */ +-static void +-print_version (void) ++static void print_version(void) + { +- printf ("%s version %s\n", tool_name, RELEASE_STRING); +- printf ("%s\n", copyright_notice); ++ printf("%s version %s\n", tool_name, RELEASE_STRING); ++ printf("%s\n", copyright_notice); + } + + /* +@@ -54,7 +53,7 @@ static void exit_usage(int exitcode) + " [-b | --blocksize=]\n" + " [-d | --disk_layout=]\n" + " [-r | --requestsize=]\n" +- " \n\n",prog_name); ++ " \n\n", prog_name); + + printf(" -t or --test means testmode\n" + " -V or --version means print version\n" +@@ -71,13 +70,13 @@ static void exit_usage(int exitcode) + " -C or --check_host_count means force dasdfmt to check\n" + " the host access open count to ensure the device\n" + " is not online on another operating system instance\n" +- " --norecordzero prevent storage server from modifying" +- " record 0\n\n" ++ " --norecordzero prevent storage server from modifying" ++ " record 0\n\n" + " is the volume identifier, which is converted\n" +- " to EBCDIC and written to disk. \n" ++ " to EBCDIC and written to disk.\n" + " (6 characters, e.g. LNX001\n" + " has to be power of 2 and at least 512\n" +- " is either \n" ++ " is either\n" + " 'cdl' for compatible disk layout (default) or\n" + " 'ldl' for linux disk layout\n" + " device node of the device to format\n"); +@@ -106,38 +105,39 @@ static int reread_partition_table(void) + * signal handler: + * enables the disk again in case of SIGTERM, SIGINT and SIGQUIT + */ +-static void program_interrupt_signal (int sig) ++static void program_interrupt_signal(int sig) + { + int rc; + + if (program_interrupt_in_progress) +- raise (sig); ++ raise(sig); + program_interrupt_in_progress = 1; + + if (disk_disabled) { +- printf("Re-accessing the device... \n"); ++ printf("Re-accessing the device...\n"); + rc = ioctl(filedes, BIODASDENABLE, &format_params); + if (rc) +- ERRMSG_EXIT(EXIT_FAILURE, +- "%s: (signal handler) IOCTL BIODASDENABLE " +- "failed (%s)\n",prog_name,strerror(errno)); ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: (signal handler) IOCTL " ++ "BIODASDENABLE failed (%s)\n", prog_name, ++ strerror(errno)); + } + +- printf("Rereading the partition table... \n"); ++ printf("Rereading the partition table...\n"); + rc = reread_partition_table(); + if (rc) { + ERRMSG("%s: (signal handler) Re-reading partition table " + "failed. (%s)\n", prog_name, strerror(errno)); +- } else ++ } else { + printf("Exiting...\n"); ++ } + + rc = close(filedes); + if (rc) + ERRMSG("%s: (signal handler) Unable to close device (%s)\n", + prog_name, strerror(errno)); + +- signal (sig, SIG_DFL); +- raise (sig); ++ signal(sig, SIG_DFL); ++ raise(sig); + } + + +@@ -171,13 +171,13 @@ static void get_device_name(dasdfmt_info + char* device; + int i; + +- if ((strchr(name, ' ') != NULL)||(strchr(name, '#') != NULL)|| +- (strchr(name, '[') != NULL)||(strchr(name, ']') != NULL)|| +- (strchr(name, '!') != NULL)||(strchr(name, '>') != NULL)|| +- (strchr(name, '(') != NULL)||(strchr(name, '<') != NULL)|| +- (strchr(name, ')') != NULL)||(strchr(name, ':') != NULL)|| +- (strchr(name, '&') != NULL)||(strchr(name, ';') != NULL)) +- ERRMSG_EXIT(EXIT_MISUSE,"%s: Your filename contains " ++ if ((strchr(name, ' ') != NULL) || (strchr(name, '#') != NULL) || ++ (strchr(name, '[') != NULL) || (strchr(name, ']') != NULL) || ++ (strchr(name, '!') != NULL) || (strchr(name, '>') != NULL) || ++ (strchr(name, '(') != NULL) || (strchr(name, '<') != NULL) || ++ (strchr(name, ')') != NULL) || (strchr(name, ':') != NULL) || ++ (strchr(name, '&') != NULL) || (strchr(name, ';') != NULL)) ++ ERRMSG_EXIT(EXIT_MISUSE, "%s: Your filename contains " + "blanks or special characters!\n", + prog_name); + +@@ -215,14 +215,14 @@ static void get_device_name(dasdfmt_info + info->devname[PATH_MAX - 1] = '\0'; + + if (stat(info->devname, &dev_stat) != 0) +- ERRMSG_EXIT(EXIT_MISUSE, +- "%s: Could not get information for device node %s: %s\n", +- prog_name, info->devname, strerror(errno)); ++ ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for " ++ "device node %s: %s\n", prog_name, info->devname, ++ strerror(errno)); + + if (minor(dev_stat.st_rdev) & PARTN_MASK) { +- ERRMSG_EXIT(EXIT_MISUSE, +- "%s: Unable to format partition %s. Please specify a device.\n", +- prog_name, info->devname); ++ ERRMSG_EXIT(EXIT_MISUSE, "%s: Unable to format partition %s. " ++ "Please specify a device.\n", prog_name, ++ info->devname); + } + + if (util_proc_dev_get_entry(dev_stat.st_rdev, 1, &dev_entry) == 0) { +@@ -253,7 +253,7 @@ static void init_info(dasdfmt_info_t *in + info->force = 0; + info->writenolabel = 0; + info->labelspec = 0; +- info->cdl_format = 0; ++ info->cdl_format = 0; + info->blksize_specified = 0; + info->reqsize_specified = 0; + info->node_specified = 0; +@@ -263,7 +263,6 @@ static void init_info(dasdfmt_info_t *in + info->yast_mode = 0; + } + +- + /* + * check for disk type and set some variables (e.g. usage count) + */ +@@ -280,9 +279,9 @@ static void check_disk(dasdfmt_info_t *i + "status information failed (%s)\n", + prog_name, strerror(errno_save)); + } +- if (ro) { ++ if (ro) + ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n"); +- } ++ + retry: + if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) { + errno_save = errno; +@@ -314,7 +313,7 @@ retry: + + info->usage_count = dasd_info.open_count; + info->devno = dasd_info.devno; +- if (strncmp(dasd_info.type, "ECKD",4) != 0) { ++ if (strncmp(dasd_info.type, "ECKD", 4) != 0) { + ERRMSG_EXIT(EXIT_FAILURE, + "%s: Unsupported disk type\n%s is not an " + "ECKD disk!\n", prog_name, info->devname); +@@ -327,29 +326,28 @@ retry: + } + } + +- + /* + * check the volume serial for special + * characters and move blanks to the end + */ + static int check_volser(char *s, int devno) + { +- int i,j; ++ int i, j; + +- for (i=0; i<6; i++) { ++ for (i = 0; i < 6; i++) { + if ((s[i] < 0x20) || (s[i] > 0x7a) || +- ((s[i] >= 0x21)&&(s[i] <= 0x22)) || /* !" */ +- ((s[i] >= 0x26)&&(s[i] <= 0x2f)) || /* &'()*+,-./ */ +- ((s[i] >= 0x3a)&&(s[i] <= 0x3f)) || /* :;<=>? */ +- ((s[i] >= 0x5b)&&(s[i] <= 0x60))) /* \]^_` */ ++ ((s[i] >= 0x21) && (s[i] <= 0x22)) || /* !" */ ++ ((s[i] >= 0x26) && (s[i] <= 0x2f)) || /* &'()*+,-./ */ ++ ((s[i] >= 0x3a) && (s[i] <= 0x3f)) || /* :;<=>? */ ++ ((s[i] >= 0x5b) && (s[i] <= 0x60))) /* \]^_` */ + s[i] = ' '; + s[i] = toupper(s[i]); + } + s[6] = 0x00; + +- for (i=0; i<6; i++) { ++ for (i = 0; i < 6; i++) { + if (s[i] == ' ') +- for (j=i; j<6; j++) ++ for (j = i; j < 6; j++) + if (s[j] != ' ') { + s[i] = s[j]; + s[j] = ' '; +@@ -360,7 +358,7 @@ static int check_volser(char *s, int dev + if (s[0] == ' ') { + printf("Usage error, switching to default.\n"); + sprintf(s, "0X%04x", devno); +- for (i=0; i<6; i++) ++ for (i = 0; i < 6; i++) + s[i] = toupper(s[i]); + return -1; + } +@@ -368,7 +366,6 @@ static int check_volser(char *s, int dev + return 0; + } + +- + /* + * do some blocksize checks + */ +@@ -377,7 +374,7 @@ static int check_param(char *s, size_t b + int tmp = data->blksize; + + if ((tmp < 512) || (tmp > 4096)) { +- strncpy(s,"Blocksize must be one of the following positive " ++ strncpy(s, "Blocksize must be one of the following positive " + "integers:\n512, 1024, 2048, 4096.", buffsize); + if (buffsize > 0) + s[buffsize - 1] = '\0'; +@@ -386,7 +383,7 @@ static int check_param(char *s, size_t b + + while (tmp > 0) { + if ((tmp % 2) && (tmp != 1)) { +- strncpy(s,"Blocksize must be a power of 2.", buffsize); ++ strncpy(s, "Blocksize must be a power of 2.", buffsize); + if (buffsize > 0) + s[buffsize - 1] = '\0'; + return -1; +@@ -397,7 +394,6 @@ static int check_param(char *s, size_t b + return 0; + } + +- + /* + * ask the user to specify a blocksize + */ +@@ -415,7 +411,7 @@ static format_data_t ask_user_for_blksiz + if (fgets(buffer, sizeof(buffer), stdin) == NULL) + break; + +- rc = sscanf(buffer,"%d%c", ¶ms.blksize, &c); ++ rc = sscanf(buffer, "%d%c", ¶ms.blksize, &c); + if ((rc == 2) && (c == '\n')) + rc = 1; + if (rc == -1) +@@ -424,7 +420,7 @@ static format_data_t ask_user_for_blksiz + printf(" -- wrong input, try again.\n"); + + if (check_param(str, ERR_LENGTH, ¶ms) < 0) { +- printf(" -- %s\n",str); ++ printf(" -- %s\n", str); + rc = 0; + } + } while (rc != 1); +@@ -432,7 +428,6 @@ static format_data_t ask_user_for_blksiz + return params; + } + +- + /* + * print all information needed to format the device + */ +@@ -449,7 +444,7 @@ static void dasdfmt_print_info(dasdfmt_i + printf("%s in the following way:\n", info->devname); + printf(" Device number of device : 0x%x\n", info->devno); + printf(" Labelling device : %s\n", +- (info->writenolabel)?"no":"yes"); ++ (info->writenolabel) ? "no" : "yes"); + + if (!info->writenolabel) { + vtoc_volume_label_get_label(vlabel, vollbl); +@@ -460,31 +455,31 @@ static void dasdfmt_print_info(dasdfmt_i + printf(" Extent start (trk no) : %u\n", p->start_unit); + printf(" Extent end (trk no) : %u\n", p->stop_unit); + printf(" Compatible Disk Layout : %s\n", +- (p->intensity & DASD_FMT_INT_COMPAT)?"yes":"no"); ++ (p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no"); + printf(" Blocksize : %d\n", p->blksize); + + if (info->testmode) + printf("Test mode active, omitting ioctl.\n"); + } + +- + /* + * get volser + */ +-static int dasdfmt_get_volser(char * devname, char * volser) ++static int dasdfmt_get_volser(char *devname, char *volser) + { +- dasd_information_t dasd_info; ++ dasd_information_t dasd_info; + int blksize; + int f; + volume_label_t vlabel; + +- if ((f = open(devname, O_RDONLY)) == -1) +- ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n", ++ f = open(devname, O_RDONLY); ++ if (f == -1) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", + prog_name, devname, strerror(errno)); + + if (ioctl(f, BIODASDINFO, &dasd_info) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (label pos) IOCTL BIODASD" +- "INFO failed (%s).\n",prog_name, strerror(errno)); ++ "INFO failed (%s).\n", prog_name, strerror(errno)); + + if (ioctl(f, BLKSSZGET, &blksize) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (label pos) IOCTL BLKSSZGET " +@@ -500,8 +495,7 @@ static int dasdfmt_get_volser(char * dev + vtoc_read_volume_label(devname, dasd_info.label_block * blksize, &vlabel); + vtoc_volume_label_get_volser(&vlabel, volser); + return 0; +- } +- else { ++ } else { + return -1; + } + } +@@ -512,22 +506,24 @@ static int dasdfmt_get_volser(char * dev + static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel, + unsigned int cylinders, unsigned int heads) + { +- int label_position; +- dasd_information_t dasd_info; +- struct hd_geometry geo; +- format4_label_t f4; +- format5_label_t f5; +- format7_label_t f7; ++ int label_position; ++ dasd_information_t dasd_info; ++ struct hd_geometry geo; ++ format4_label_t f4; ++ format5_label_t f5; ++ format7_label_t f7; + int rc, blksize; + void *ipl1_record, *ipl2_record; + int ipl1_record_len, ipl2_record_len; + + +- if (info->verbosity > 0) printf("Retrieving dasd information... "); ++ if (info->verbosity > 0) ++ printf("Retrieving dasd information... "); + + if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL BIODASD" +- "INFO failed (%s).\n",prog_name, strerror(errno)); ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL " ++ "BIODASDINFO failed (%s).\n", ++ prog_name, strerror(errno)); + + if (ioctl(filedes, BLKSSZGET, &blksize) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL BLKSSZGET " +@@ -539,13 +535,16 @@ static void dasdfmt_write_labels(dasdfmt + * vary depending on the format. + */ + if (ioctl(filedes, HDIO_GETGEO, &geo) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL HDIO_GET" +- "GEO failed (%s).\n", prog_name, strerror(errno)); ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL " ++ "HDIO_GETGEO failed (%s).\n", ++ prog_name, strerror(errno)); + +- if (info->verbosity > 0) printf("ok\n"); ++ if (info->verbosity > 0) ++ printf("ok\n"); + + /* write empty bootstrap (initial IPL records) */ +- if (info->verbosity > 0) printf("Writing empty bootstrap...\n"); ++ if (info->verbosity > 0) ++ printf("Writing empty bootstrap...\n"); + + /* + * Note: ldl labels do not contain the key field +@@ -596,7 +595,8 @@ static void dasdfmt_write_labels(dasdfmt + + label_position = dasd_info.label_block * blksize; + +- if (info->verbosity > 0) printf("Writing label...\n"); ++ if (info->verbosity > 0) ++ printf("Writing label...\n"); + + rc = lseek(filedes, label_position, SEEK_SET); + if (rc != label_position) +@@ -608,10 +608,10 @@ static void dasdfmt_write_labels(dasdfmt + * Note: cdl volume labels do not contain the 'formatted_blocks' part + * and ldl labels do not contain the key field + */ +- if (info->cdl_format) ++ if (info->cdl_format) { + rc = write(filedes, vlabel, (sizeof(*vlabel) - + sizeof(vlabel->formatted_blocks))); +- else { ++ } else { + vlabel->ldl_version = 0xf2; /* EBCDIC '2' */ + vlabel->formatted_blocks = cylinders * heads * geo.sectors; + rc = write(filedes, &vlabel->vollbl, (sizeof(*vlabel) +@@ -625,7 +625,8 @@ static void dasdfmt_write_labels(dasdfmt + ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing volume label " + "(%d).\n", prog_name, rc); + +- if (info->verbosity > 0) printf("Writing VTOC... "); ++ if (info->verbosity > 0) ++ printf("Writing VTOC... "); + + label_position = (VTOC_START_CC * heads + VTOC_START_HH) * + geo.sectors * blksize; +@@ -673,10 +674,10 @@ static void dasdfmt_write_labels(dasdfmt + + fsync(filedes); + +- if (info->verbosity > 0) printf("ok\n"); ++ if (info->verbosity > 0) ++ printf("ok\n"); + } + +- + /* + * formats the disk cylinderwise + */ +@@ -720,21 +721,20 @@ static void dasdfmt_format(dasdfmt_info_ + format_step.start_unit += 1; + + if (ioctl(filedes, BIODASDFMT, &format_step) != 0) +- ERRMSG_EXIT(EXIT_FAILURE,"%s: (format cylinder) IOCTL " ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: (format cylinder) IOCTL " + "BIODASDFMT failed. (%s)\n", + prog_name, strerror(errno)); + + if (info->print_progressbar) { + printf("cyl %7d of %7d |", cyl, cylinders); + p2 = p1; +- p1 = cyl*100/cylinders; +- if (p1 != p2) +- { ++ p1 = cyl * 100 / cylinders; ++ if (p1 != p2) { + /* percent value has changed */ +- tmp = cyl*50/cylinders; +- for (j=1; j<=tmp; j++) ++ tmp = cyl * 50 / cylinders; ++ for (j = 1; j <= tmp; j++) + printf("#"); +- for (j=tmp+1; j<=50; j++) ++ for (j = tmp + 1; j <= 50; j++) + printf("-"); + printf("|%3d%%", p1); + } +@@ -748,6 +748,7 @@ static void dasdfmt_format(dasdfmt_info_ + fflush(stdout); + hashcount++; + } ++ + if (info->print_percentage) { + printf("cyl %7d of %7d |%3d%%\n", cyl, cylinders, + cyl*100/cylinders); +@@ -757,9 +758,9 @@ static void dasdfmt_format(dasdfmt_info_ + if (k % heads == 0) { + k += reqsize * heads; + cyl += reqsize; +- } +- else ++ } else { + k += format_params->stop_unit % heads; ++ } + + if (k > format_params->stop_unit) + break; +@@ -769,14 +770,9 @@ static void dasdfmt_format(dasdfmt_info_ + printf("\n\n"); + } + +- +-/* +- * +- */ +-static void dasdfmt_prepare_and_format (dasdfmt_info_t *info, +- unsigned int cylinders, +- unsigned int heads, +- format_data_t *p) ++static void dasdfmt_prepare_and_format(dasdfmt_info_t *info, ++ unsigned int cylinders, ++ unsigned int heads, format_data_t *p) + { + format_data_t temp = { + start_unit: 0, +@@ -786,7 +782,8 @@ static void dasdfmt_prepare_and_format ( + | DASD_FMT_INT_INVAL) + }; + +- if (info->verbosity > 0) printf("Detaching the device...\n"); ++ if (info->verbosity > 0) ++ printf("Detaching the device...\n"); + + if (ioctl(filedes, BIODASDDISABLE, p) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " +@@ -794,7 +791,8 @@ static void dasdfmt_prepare_and_format ( + strerror(errno)); + disk_disabled = 1; + +- if (info->verbosity > 0) printf("Invalidate first track...\n"); ++ if (info->verbosity > 0) ++ printf("Invalidate first track...\n"); + + if (ioctl(filedes, BIODASDFMT, &temp) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (invalidate first track) IOCTL " +@@ -806,18 +804,21 @@ static void dasdfmt_prepare_and_format ( + + dasdfmt_format(info, cylinders, heads, p); + +- if (info->verbosity > 0) printf("formatting tracks complete...\n"); ++ if (info->verbosity > 0) ++ printf("formatting tracks complete...\n"); + + temp.intensity = p->intensity; + +- if (info->verbosity > 0) printf("Revalidate first track...\n"); ++ if (info->verbosity > 0) ++ printf("Revalidate first track...\n"); + + if (ioctl(filedes, BIODASDFMT, &temp) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (re-validate first track) IOCTL" + " BIODASDFMT failed (%s)\n", prog_name, + strerror(errno)); + +- if (info->verbosity > 0) printf("Re-accessing the device...\n"); ++ if (info->verbosity > 0) ++ printf("Re-accessing the device...\n"); + + if (ioctl(filedes, BIODASDENABLE, p) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " +@@ -826,20 +827,17 @@ static void dasdfmt_prepare_and_format ( + disk_disabled = 0; + } + +- +-/* +- * +- */ + static void do_format_dasd(dasdfmt_info_t *info, format_data_t *p, + volume_label_t *vlabel) + { +- char inp_buffer[5]; ++ char inp_buffer[5]; + dasd_information_t dasd_info; + struct dasd_eckd_characteristics *characteristics; + unsigned int cylinders, heads; + int count; + +- if (info->verbosity > 0) printf("Retrieving disk geometry...\n"); ++ if (info->verbosity > 0) ++ printf("Retrieving disk geometry...\n"); + + if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (retrieving disk information) " +@@ -877,22 +875,23 @@ static void do_format_dasd(dasdfmt_info_ + } + } + } else { +- if (!info->labelspec && !info->keep_volser) { ++ if (!info->labelspec && !info->keep_volser) { + char buf[7]; + +- sprintf(buf, "0X%04x", info->devno); ++ sprintf(buf, "0X%04x", info->devno); + check_volser(buf, info->devno); + vtoc_volume_label_set_volser(vlabel, buf); + } + +- if (p->intensity & DASD_FMT_INT_COMPAT) { ++ if (p->intensity & DASD_FMT_INT_COMPAT) { + info->cdl_format = 1; + vtoc_volume_label_set_label(vlabel, "VOL1"); + vtoc_volume_label_set_key(vlabel, "VOL1"); + vtoc_set_cchhb(&vlabel->vtoc, 0x0000, 0x0001, 0x01); +- } else ++ } else { + vtoc_volume_label_set_label(vlabel, "LNX1"); +- } ++ } ++ } + + if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) + dasdfmt_print_info(info, vlabel, cylinders, heads, p); +@@ -926,15 +925,15 @@ static void do_format_dasd(dasdfmt_info_ + "untouched: "); + if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL) + return; +- if (strcasecmp(inp_buffer,"yes") && +- strcasecmp(inp_buffer,"yes\n")) { ++ if (strcasecmp(inp_buffer, "yes") && ++ strcasecmp(inp_buffer, "yes\n")) { + printf("Omitting ioctl call (disk will " + "NOT be formatted).\n"); + return; + } + } + +- if (!((info->withoutprompt)&&(info->verbosity<1))) ++ if (!((info->withoutprompt) && (info->verbosity < 1))) + printf("Formatting the device. This may take a " + "while (get yourself a coffee).\n"); + +@@ -954,12 +953,11 @@ static void do_format_dasd(dasdfmt_info_ + } else { + if (!info->yast_mode) + printf("ok\n"); +- } ++ } + } + } + +- +-int main(int argc,char *argv[]) ++int main(int argc, char *argv[]) + { + dasdfmt_info_t info; + volume_label_t vlabel; +@@ -980,9 +978,9 @@ int main(int argc,char *argv[]) + int running=0; + + /* Establish a handler for interrupt signals. */ +- signal (SIGTERM, program_interrupt_signal); +- signal (SIGINT, program_interrupt_signal); +- signal (SIGQUIT, program_interrupt_signal); ++ signal(SIGTERM, program_interrupt_signal); ++ signal(SIGINT, program_interrupt_signal); ++ signal(SIGQUIT, program_interrupt_signal); + + /******************* initialization ********************/ + prog_name = argv[0]; +@@ -996,102 +994,81 @@ int main(int argc,char *argv[]) + + /*************** parse parameters **********************/ + +- while (1) +- { +- rc=getopt_long(argc, argv, dasdfmt_getopt_string, +- dasdfmt_getopt_long_options, &index); ++ while (1) { ++ rc = getopt_long(argc, argv, dasdfmt_getopt_string, ++ dasdfmt_getopt_long_options, &index); + +- switch (rc) +- { ++ switch (rc) { + case 'F': +- info.force=1; ++ info.force = 1; + break; +- +- case 'd' : +- if (strncmp(optarg,"cdl",3)==0) +- { ++ case 'd': ++ if (strncmp(optarg, "cdl", 3) == 0) { + format_params.intensity |= DASD_FMT_INT_COMPAT; +- if (info.writenolabel) +- { +- printf("WARNING: using the cdl " \ +- "format without writing a " \ +- "label doesn't make much " \ ++ if (info.writenolabel) { ++ printf("WARNING: using the cdl " ++ "format without writing a " ++ "label doesn't make much " + "sense!\n"); + exit(1); + } +- } +- else if (strncmp(optarg,"ldl",3)==0) ++ } else if (strncmp(optarg, "ldl", 3) == 0) { + format_params.intensity &= ~DASD_FMT_INT_COMPAT; +- else +- { ++ } else { + printf("%s is not a valid option!\n", optarg); + exit(1); + } +- break; +- ++ break; + case 'y': +- info.withoutprompt=1; ++ info.withoutprompt = 1; + break; +- + case 'z': +- format_params.intensity |= DASD_FMT_INT_FMT_NOR0; ++ format_params.intensity |= DASD_FMT_INT_FMT_NOR0; + break; +- + case 't': +- info.testmode=1; ++ info.testmode = 1; + break; +- + case 'p': + if (!(info.print_hashmarks || info.print_percentage)) + info.print_progressbar = 1; + break; +- + case 'm': +- if (!(info.print_progressbar || info.print_percentage)) +- { +- hashstep_str=optarg; +- info.print_hashmarks=1; ++ if (!(info.print_progressbar || info.print_percentage)) { ++ hashstep_str = optarg; ++ info.print_hashmarks = 1; + } + break; +- + case 'Q': + if (!(info.print_hashmarks || info.print_progressbar)) + info.print_percentage = 1; + break; +- + case 'v': +- info.verbosity=1; ++ info.verbosity = 1; + break; +- + case 'h': + exit_usage(0); +- + case 'V': + print_version(); + exit(0); +- + case 'l': +- strncpy(buf, optarg, 6); ++ strncpy(buf, optarg, 6); + if (check_volser(buf, 0) < 0) + break; +- vtoc_volume_label_set_volser(&vlabel,buf); +- info.labelspec=1; ++ vtoc_volume_label_set_volser(&vlabel, buf); ++ info.labelspec = 1; + break; +- + case 'L': +- if (format_params.intensity & DASD_FMT_INT_COMPAT) +- { +- printf("WARNING: using the cdl format " \ +- "without writing a label doesn't " \ ++ if (format_params.intensity & DASD_FMT_INT_COMPAT) { ++ printf("WARNING: using the cdl format " ++ "without writing a label doesn't " + "make much sense!\n"); + exit(1); + } +- info.writenolabel=1; ++ info.writenolabel = 1; + break; +- +- case 'b' : +- blksize_param_str=optarg; +- info.blksize_specified=1; ++ case 'b': ++ blksize_param_str = optarg; ++ info.blksize_specified = 1; + break; + case 'r': + reqsize_param_str = optarg; +@@ -1102,7 +1079,7 @@ int main(int argc,char *argv[]) + ERRMSG_EXIT(EXIT_MISUSE,"%s: too many devices specified.\n", + prog_name); + dev_filename[dev_count++]=strdup(optarg); +- info.node_specified=1; ++ info.node_specified = 1; + break; + case 'Y' : /* YaST mode */ + info.yast_mode=1; +@@ -1110,8 +1087,8 @@ int main(int argc,char *argv[]) + case 'P' : /* max parallel formatting processes */ + max_parallel=atoi(optarg); + break; +- case 'k' : +- info.keep_volser=1; ++ case 'k': ++ info.keep_volser = 1; + break; + case 'C': + info.force_host = 1; +@@ -1121,11 +1098,12 @@ int main(int argc,char *argv[]) + info.device_id = optind; + break; + default: +- ERRMSG_EXIT(EXIT_MISUSE, +- "Try '%s --help' for more" +- " information.\n",prog_name); ++ ERRMSG_EXIT(EXIT_MISUSE, "Try '%s --help' for more" ++ " information.\n", prog_name); + } +- if (rc==-1) break; // exit loop if finished ++ ++ if (rc == -1) ++ break; /* exit loop if finished */ + } + + CHECK_SPEC_MAX_ONCE(info.blksize_specified, "blocksize"); +@@ -1222,7 +1200,7 @@ int main(int argc,char *argv[]) + } else + reqsize = DEFAULT_REQUESTSIZE; + if (info.print_hashmarks) +- PARSE_PARAM_INTO(info.hashstep, hashstep_str,10,"hashstep"); ++ PARSE_PARAM_INTO(info.hashstep, hashstep_str, 10, "hashstep"); + + get_device_name(&info, dev_filename[i]); + +@@ -1230,22 +1208,24 @@ int main(int argc,char *argv[]) + format_params = ask_user_for_blksize(format_params); + + if (info.keep_volser) { +- if(format_params.intensity == 0x00) { +- printf("WARNING: VOLSER cannot be kept " \ ++ if (format_params.intensity == 0x00) { ++ printf("WARNING: VOLSER cannot be kept " + "when using the ldl format!\n"); + exit(1); + } + +- if(dasdfmt_get_volser(info.devname, old_volser) == 0) ++ if (dasdfmt_get_volser(info.devname, old_volser) == 0) + vtoc_volume_label_set_volser(&vlabel, old_volser); + else +- ERRMSG_EXIT(EXIT_FAILURE,"%s: VOLSER not found on device %s\n", ++ ERRMSG_EXIT(EXIT_FAILURE, ++ "%s: VOLSER not found on device %s\n", + prog_name, info.devname); + + } + +- if ((filedes = open(info.devname, O_RDWR)) == -1) +- ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n", ++ filedes = open(info.devname, O_RDWR); ++ if (filedes == -1) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", + prog_name, info.devname, strerror(errno)); + + check_disk(&info); diff --git a/s390-tools-sles12sp3-dasdfmt-04-Use-enhanced-DASD-information.patch b/s390-tools-sles12sp3-dasdfmt-04-Use-enhanced-DASD-information.patch new file mode 100644 index 0000000..1116f55 --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-04-Use-enhanced-DASD-information.patch @@ -0,0 +1,399 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Use enhanced DASD information + + Currently dasdfmt uses BIODASDINFO as the IOCTL command to retrieve + information about a DASD and stores them in dasd_information_t. + However, BIODASDINFO2 offers a few more useful information (which are + then stored in dasd_information2_t). + + - Replace dasd_information_t with dasd_information2_t. + - Make the corresponding variable part of dasdfmt_info_t, since it is + used in several functions anyway and we can save a few parameters and + IOCTL calls. + - Change the initialization of dasdfmt_info_t. A separate function isn't + necessary for that. + - Put the BIODASDINFO2 IOCTL call in a separate function which is then + called only once. + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 132 ++++++++++++++++++------------------------------------ + dasdfmt/dasdfmt.h | 21 ++++++-- + 2 files changed, 61 insertions(+), 92 deletions(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -237,30 +237,18 @@ static void get_device_name(dasdfmt_info + } + + /* +- * initialize the dasdfmt info structure ++ * Retrieve DASD information + */ +-static void init_info(dasdfmt_info_t *info) ++static void get_device_info(dasdfmt_info_t *info) + { +- info->devno = 0x0; +- info->usage_count = 0; +- info->testmode = 0; +- info->verbosity = 0; +- info->withoutprompt = 0; +- info->print_progressbar = 0; +- info->print_hashmarks = 0; +- info->print_percentage = 0; +- info->hashstep = 0; +- info->force = 0; +- info->writenolabel = 0; +- info->labelspec = 0; +- info->cdl_format = 0; +- info->blksize_specified = 0; +- info->reqsize_specified = 0; +- info->node_specified = 0; +- info->device_id = 0; +- info->keep_volser = 0; +- info->force_host = 0; +- info->yast_mode = 0; ++ dasd_information2_t dasd_info; ++ ++ if (ioctl(filedes, BIODASDINFO2, &dasd_info)) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve " ++ "device information failed (%s).\n", ++ prog_name, strerror(errno)); ++ ++ info->dasd_info = dasd_info; + } + + /* +@@ -268,7 +256,6 @@ static void init_info(dasdfmt_info_t *in + */ + static void check_disk(dasdfmt_info_t *info) + { +- dasd_information_t dasd_info; + int ro, errno_save, i = 0; + + if (ioctl(filedes, BLKROGET, &ro) != 0) { +@@ -283,15 +270,6 @@ static void check_disk(dasdfmt_info_t *i + ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n"); + + retry: +- if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) { +- errno_save = errno; +- close(filedes); +- ERRMSG_EXIT(EXIT_FAILURE, +- "%s: the ioctl call to retrieve device " +- "information failed (%s)\n", +- prog_name, strerror(errno_save)); +- } +- + if (!info->force) + /* + * udev strikes again. +@@ -302,7 +280,7 @@ retry: + * And confusing the hell out ouf anyone else. + * Bah. + */ +- if (dasd_info.open_count > 1) { ++ if (info->dasd_info.open_count > 1) { + if (i < 5) { + ++i; + sleep(1); +@@ -311,9 +289,7 @@ retry: + ERRMSG_EXIT(EXIT_BUSY, "Disk in use!\n"); + } + +- info->usage_count = dasd_info.open_count; +- info->devno = dasd_info.devno; +- if (strncmp(dasd_info.type, "ECKD", 4) != 0) { ++ if (strncmp(info->dasd_info.type, "ECKD", 4) != 0) { + ERRMSG_EXIT(EXIT_FAILURE, + "%s: Unsupported disk type\n%s is not an " + "ECKD disk!\n", prog_name, info->devname); +@@ -442,7 +418,7 @@ static void dasdfmt_print_info(dasdfmt_i + + printf("\nI am going to format the device "); + printf("%s in the following way:\n", info->devname); +- printf(" Device number of device : 0x%x\n", info->devno); ++ printf(" Device number of device : 0x%x\n", info->dasd_info.devno); + printf(" Labelling device : %s\n", + (info->writenolabel) ? "no" : "yes"); + +@@ -465,21 +441,16 @@ static void dasdfmt_print_info(dasdfmt_i + /* + * get volser + */ +-static int dasdfmt_get_volser(char *devname, char *volser) ++static int dasdfmt_get_volser(dasdfmt_info_t *info, char *volser) + { +- dasd_information_t dasd_info; + int blksize; + int f; + volume_label_t vlabel; + +- f = open(devname, O_RDONLY); ++ f = open(info->devname, O_RDONLY); + if (f == -1) + ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", +- prog_name, devname, strerror(errno)); +- +- if (ioctl(f, BIODASDINFO, &dasd_info) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (label pos) IOCTL BIODASD" +- "INFO failed (%s).\n", prog_name, strerror(errno)); ++ prog_name, info->devname, strerror(errno)); + + if (ioctl(f, BLKSSZGET, &blksize) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (label pos) IOCTL BLKSSZGET " +@@ -489,10 +460,12 @@ static int dasdfmt_get_volser(char *devn + ERRMSG("%s: error during close: %s\ncontinuing...\n", + prog_name, strerror(errno)); + +- if ((strncmp(dasd_info.type, "ECKD", 4) == 0) && +- (!dasd_info.FBA_layout)) { ++ if ((strncmp(info->dasd_info.type, "ECKD", 4) == 0) && ++ (!info->dasd_info.FBA_layout)) { + /* OS/390 and zOS compatible disk layout */ +- vtoc_read_volume_label(devname, dasd_info.label_block * blksize, &vlabel); ++ vtoc_read_volume_label(info->devname, ++ info->dasd_info.label_block * blksize, ++ &vlabel); + vtoc_volume_label_get_volser(&vlabel, volser); + return 0; + } else { +@@ -507,7 +480,6 @@ static void dasdfmt_write_labels(dasdfmt + unsigned int cylinders, unsigned int heads) + { + int label_position; +- dasd_information_t dasd_info; + struct hd_geometry geo; + format4_label_t f4; + format5_label_t f5; +@@ -520,11 +492,6 @@ static void dasdfmt_write_labels(dasdfmt + if (info->verbosity > 0) + printf("Retrieving dasd information... "); + +- if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL " +- "BIODASDINFO failed (%s).\n", +- prog_name, strerror(errno)); +- + if (ioctl(filedes, BLKSSZGET, &blksize) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL BLKSSZGET " + "failed (%s).\n", prog_name, strerror(errno)); +@@ -586,14 +553,14 @@ static void dasdfmt_write_labels(dasdfmt + + /* write VTOC */ + vtoc_init_format4_label(&f4, geo.cylinders, cylinders, heads, +- geo.sectors, blksize, dasd_info.dev_type); ++ geo.sectors, blksize, info->dasd_info.dev_type); + + vtoc_init_format5_label(&f5); + vtoc_init_format7_label(&f7); + vtoc_set_freespace(&f4, &f5, &f7, '+', 0, FIRST_USABLE_TRK, + (cylinders * heads - 1), cylinders, heads); + +- label_position = dasd_info.label_block * blksize; ++ label_position = info->dasd_info.label_block * blksize; + + if (info->verbosity > 0) + printf("Writing label...\n"); +@@ -831,7 +798,6 @@ static void do_format_dasd(dasdfmt_info_ + volume_label_t *vlabel) + { + char inp_buffer[5]; +- dasd_information_t dasd_info; + struct dasd_eckd_characteristics *characteristics; + unsigned int cylinders, heads; + int count; +@@ -839,13 +805,9 @@ static void do_format_dasd(dasdfmt_info_ + if (info->verbosity > 0) + printf("Retrieving disk geometry...\n"); + +- if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (retrieving disk information) " +- "IOCTL BIODASDINFO failed (%s).\n", +- prog_name, strerror(errno)); +- + characteristics = +- (struct dasd_eckd_characteristics *) &dasd_info.characteristics; ++ (struct dasd_eckd_characteristics *) ++ &info->dasd_info.characteristics; + if (characteristics->no_cyl == LV_COMPAT_CYL && + characteristics->long_no_cyl) + cylinders = characteristics->long_no_cyl; +@@ -878,8 +840,8 @@ static void do_format_dasd(dasdfmt_info_ + if (!info->labelspec && !info->keep_volser) { + char buf[7]; + +- sprintf(buf, "0X%04x", info->devno); +- check_volser(buf, info->devno); ++ sprintf(buf, "0X%04x", info->dasd_info.devno); ++ check_volser(buf, info->dasd_info.devno); + vtoc_volume_label_set_volser(vlabel, buf); + } + +@@ -959,7 +921,10 @@ static void do_format_dasd(dasdfmt_info_ + + int main(int argc, char *argv[]) + { +- dasdfmt_info_t info; ++ dasdfmt_info_t info = { ++ .dasd_info = {0}, ++ {0} ++ }; + volume_label_t vlabel; + char old_volser[7]; + +@@ -986,7 +951,6 @@ int main(int argc, char *argv[]) + prog_name = argv[0]; + + /* set default values */ +- init_info(&info); + vtoc_volume_label_init(&vlabel); + + format_params.blksize = DEFAULT_BLOCKSIZE; +@@ -1137,30 +1101,24 @@ int main(int argc, char *argv[]) + + if(info.yast_mode) { + for(i=0;ino_cyl == LV_COMPAT_CYL && + characteristics->long_no_cyl) + cylinders = characteristics->long_no_cyl; +@@ -1204,6 +1162,13 @@ int main(int argc, char *argv[]) + + get_device_name(&info, dev_filename[i]); + ++ filedes = open(info.devname, O_RDWR); ++ if (filedes == -1) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", ++ prog_name, info.devname, strerror(errno)); ++ ++ get_device_info(&info); ++ + if (!info.blksize_specified) + format_params = ask_user_for_blksize(format_params); + +@@ -1214,7 +1179,7 @@ int main(int argc, char *argv[]) + exit(1); + } + +- if (dasdfmt_get_volser(info.devname, old_volser) == 0) ++ if (dasdfmt_get_volser(&info, old_volser) == 0) + vtoc_volume_label_set_volser(&vlabel, old_volser); + else + ERRMSG_EXIT(EXIT_FAILURE, +@@ -1223,11 +1188,6 @@ int main(int argc, char *argv[]) + + } + +- filedes = open(info.devname, O_RDWR); +- if (filedes == -1) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", +- prog_name, info.devname, strerror(errno)); +- + check_disk(&info); + + if (check_param(str, ERR_LENGTH, &format_params) < 0) +--- a/dasdfmt/dasdfmt.h ++++ b/dasdfmt/dasdfmt.h +@@ -32,11 +32,11 @@ + #define DASD_IOCTL_LETTER 'D' + + /* +- * struct dasd_information_t ++ * struct dasd_information2_t + * represents any data about the device, which is visible to userspace. + * including format and features. + */ +-typedef struct dasd_information_t { ++typedef struct dasd_information2_t { + unsigned int devno; /* S/390 devno */ + unsigned int real_devno; /* for aliases */ + unsigned int schid; /* S/390 subchannel identifier */ +@@ -56,7 +56,17 @@ typedef struct dasd_information_t { + unsigned int confdata_size; + char characteristics[64]; /* from read_device_characteristics */ + char configuration_data[256]; /* from read_configuration_data */ +-} dasd_information_t; ++ unsigned int format; /* format info like formatted/cdl/ldl/... */ ++ unsigned int features; /* dasd features like 'ro',... */ ++ unsigned int reserved0; /* reserved for further use ,... */ ++ unsigned int reserved1; /* reserved for further use ,... */ ++ unsigned int reserved2; /* reserved for further use ,... */ ++ unsigned int reserved3; /* reserved for further use ,... */ ++ unsigned int reserved4; /* reserved for further use ,... */ ++ unsigned int reserved5; /* reserved for further use ,... */ ++ unsigned int reserved6; /* reserved for further use ,... */ ++ unsigned int reserved7; /* reserved for further use ,... */ ++} dasd_information2_t; + + + struct dasd_eckd_characteristics { +@@ -165,7 +175,7 @@ typedef struct format_data_t { + #define BIODASDENABLE _IO(DASD_IOCTL_LETTER,1) + + /* Get information on a dasd device (enhanced) */ +-#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t) ++#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t) + + /* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ + #define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t) +@@ -251,9 +261,8 @@ typedef struct bootstrap2 { + } __attribute__ ((packed)) bootstrap2_t; + + typedef struct dasdfmt_info { +- int devno; ++ dasd_information2_t dasd_info; + char devname[PATH_MAX]; +- int usage_count; + int verbosity; + int testmode; + int withoutprompt; diff --git a/s390-tools-sles12sp3-dasdfmt-05-Refactor-do_format_dasd.patch b/s390-tools-sles12sp3-dasdfmt-05-Refactor-do_format_dasd.patch new file mode 100644 index 0000000..46f6372 --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-05-Refactor-do_format_dasd.patch @@ -0,0 +1,210 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Refactor do_format_dasd + + In order to allow for new features to be integrated properly in the + existing code, certain parts of do_format_dasd() must be moved to + separate functions. This applies to setting VTOC information and + geometrical information. + + Therefore, move the relevant bits to set_geo() and set_label(). + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 132 +++++++++++++++++++++++++++++++----------------------- + 1 file changed, 76 insertions(+), 56 deletions(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -371,6 +371,73 @@ static int check_param(char *s, size_t b + } + + /* ++ * Retrieve disk information and set cylinders and heads accordingly. ++ */ ++static void set_geo(dasdfmt_info_t *info, unsigned int *cylinders, ++ unsigned int *heads) ++{ ++ struct dasd_eckd_characteristics *characteristics; ++ ++ if (info->verbosity > 0) ++ printf("Retrieving disk geometry...\n"); ++ ++ characteristics = (struct dasd_eckd_characteristics *) ++ &info->dasd_info.characteristics; ++ if (characteristics->no_cyl == LV_COMPAT_CYL && ++ characteristics->long_no_cyl) ++ *cylinders = characteristics->long_no_cyl; ++ else ++ *cylinders = characteristics->no_cyl; ++ *heads = characteristics->trk_per_cyl; ++} ++ ++/* ++ * Set VTOC label information ++ */ ++static void set_label(dasdfmt_info_t *info, volume_label_t *vlabel, ++ format_data_t *p, unsigned int cylinders) ++{ ++ char inp_buffer[5]; ++ ++ if (info->writenolabel) { ++ if (cylinders > LV_COMPAT_CYL && !info->withoutprompt) { ++ printf("\n--->> ATTENTION! <<---\n"); ++ printf("You specified to write no labels to a" ++ " volume with more then %u cylinders.\n" ++ "Cylinders above this limit will not be" ++ " accessible as a linux partition!\n" ++ "Type \"yes\" to continue, no will leave" ++ " the disk untouched: ", LV_COMPAT_CYL); ++ if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL) ++ return; ++ if (strcasecmp(inp_buffer, "yes") && ++ strcasecmp(inp_buffer, "yes\n")) { ++ printf("Omitting ioctl call (disk will " ++ "NOT be formatted).\n"); ++ return; ++ } ++ } ++ } else { ++ if (!info->labelspec && !info->keep_volser) { ++ char buf[7]; ++ ++ sprintf(buf, "0X%04x", info->dasd_info.devno); ++ check_volser(buf, info->dasd_info.devno); ++ vtoc_volume_label_set_volser(vlabel, buf); ++ } ++ ++ if (p->intensity & DASD_FMT_INT_COMPAT) { ++ info->cdl_format = 1; ++ vtoc_volume_label_set_label(vlabel, "VOL1"); ++ vtoc_volume_label_set_key(vlabel, "VOL1"); ++ vtoc_set_cchhb(&vlabel->vtoc, 0x0000, 0x0001, 0x01); ++ } else { ++ vtoc_volume_label_set_label(vlabel, "LNX1"); ++ } ++ } ++} ++ ++/* + * ask the user to specify a blocksize + */ + static format_data_t ask_user_for_blksize(format_data_t params) +@@ -452,7 +519,7 @@ static int dasdfmt_get_volser(dasdfmt_in + ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", + prog_name, info->devname, strerror(errno)); + +- if (ioctl(f, BLKSSZGET, &blksize) != 0) ++ if (ioctl(filedes, BLKSSZGET, &blksize) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (label pos) IOCTL BLKSSZGET " + "failed (%s).\n", prog_name, strerror(errno)); + +@@ -794,67 +861,16 @@ static void dasdfmt_prepare_and_format(d + disk_disabled = 0; + } + +-static void do_format_dasd(dasdfmt_info_t *info, format_data_t *p, +- volume_label_t *vlabel) ++static void do_format_dasd(dasdfmt_info_t *info, volume_label_t *vlabel, ++ format_data_t *p, unsigned int cylinders, ++ unsigned int heads) + { + char inp_buffer[5]; +- struct dasd_eckd_characteristics *characteristics; +- unsigned int cylinders, heads; + int count; + +- if (info->verbosity > 0) +- printf("Retrieving disk geometry...\n"); +- +- characteristics = +- (struct dasd_eckd_characteristics *) +- &info->dasd_info.characteristics; +- if (characteristics->no_cyl == LV_COMPAT_CYL && +- characteristics->long_no_cyl) +- cylinders = characteristics->long_no_cyl; +- else +- cylinders = characteristics->no_cyl; +- heads = characteristics->trk_per_cyl; +- + p->start_unit = 0; + p->stop_unit = (cylinders * heads) - 1; + +- if (info->writenolabel) { +- if (cylinders > LV_COMPAT_CYL && !info->withoutprompt) { +- printf("\n--->> ATTENTION! <<---\n"); +- printf("You specified to write no labels to a" +- " volume with more then %u cylinders.\n" +- "Cylinders above this limit will not be" +- " accessible as a linux partition!\n" +- "Type \"yes\" to continue, no will leave" +- " the disk untouched: ", LV_COMPAT_CYL); +- if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL) +- return; +- if (strcasecmp(inp_buffer, "yes") && +- strcasecmp(inp_buffer, "yes\n")) { +- printf("Omitting ioctl call (disk will " +- "NOT be formatted).\n"); +- return; +- } +- } +- } else { +- if (!info->labelspec && !info->keep_volser) { +- char buf[7]; +- +- sprintf(buf, "0X%04x", info->dasd_info.devno); +- check_volser(buf, info->dasd_info.devno); +- vtoc_volume_label_set_volser(vlabel, buf); +- } +- +- if (p->intensity & DASD_FMT_INT_COMPAT) { +- info->cdl_format = 1; +- vtoc_volume_label_set_label(vlabel, "VOL1"); +- vtoc_volume_label_set_key(vlabel, "VOL1"); +- vtoc_set_cchhb(&vlabel->vtoc, 0x0000, 0x0001, 0x01); +- } else { +- vtoc_volume_label_set_label(vlabel, "LNX1"); +- } +- } +- + if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) + dasdfmt_print_info(info, vlabel, cylinders, heads, p); + +@@ -938,6 +954,7 @@ int main(int argc, char *argv[]) + char *hashstep_str = NULL; + + int rc, index, i; ++ unsigned int cylinders, heads; + + int max_parallel=1; + int running=0; +@@ -1193,7 +1210,10 @@ int main(int argc, char *argv[]) + if (check_param(str, ERR_LENGTH, &format_params) < 0) + ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str); + +- do_format_dasd(&info, &format_params, &vlabel); ++ set_geo(&info, &cylinders, &heads); ++ set_label(&info, &vlabel, &format_params, cylinders); ++ do_format_dasd(&info, &vlabel, &format_params, ++ cylinders, heads); + + if (close(filedes) != 0) + ERRMSG("%s: error during close: %s\ncontinuing...\n", diff --git a/s390-tools-sles12sp3-dasdfmt-06-Make-the-IOCTL-BLKSSZGET-reusable.patch b/s390-tools-sles12sp3-dasdfmt-06-Make-the-IOCTL-BLKSSZGET-reusable.patch new file mode 100644 index 0000000..b078fcf --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-06-Make-the-IOCTL-BLKSSZGET-reusable.patch @@ -0,0 +1,93 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Make the IOCTL BLKSSZGET reusable + + The IOCTL BLKSSZGET is used to get blocksize information of a device. + Since it is used several times already and could be used for new + features as well, move the call to a separate function and make it + reusable. + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -252,6 +252,17 @@ static void get_device_info(dasdfmt_info + } + + /* ++ * Retrieve blocksize of device ++ */ ++static void get_blocksize(unsigned int *blksize) ++{ ++ if (ioctl(filedes, BLKSSZGET, blksize) != 0) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to get the blocksize " ++ "of the device failed (%s).\n", prog_name, ++ strerror(errno)); ++} ++ ++/* + * check for disk type and set some variables (e.g. usage count) + */ + static void check_disk(dasdfmt_info_t *info) +@@ -510,7 +521,7 @@ static void dasdfmt_print_info(dasdfmt_i + */ + static int dasdfmt_get_volser(dasdfmt_info_t *info, char *volser) + { +- int blksize; ++ unsigned int blksize; + int f; + volume_label_t vlabel; + +@@ -519,9 +530,7 @@ static int dasdfmt_get_volser(dasdfmt_in + ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", + prog_name, info->devname, strerror(errno)); + +- if (ioctl(filedes, BLKSSZGET, &blksize) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (label pos) IOCTL BLKSSZGET " +- "failed (%s).\n", prog_name, strerror(errno)); ++ get_blocksize(&blksize); + + if (close(f) != 0) + ERRMSG("%s: error during close: %s\ncontinuing...\n", +@@ -551,7 +560,8 @@ static void dasdfmt_write_labels(dasdfmt + format4_label_t f4; + format5_label_t f5; + format7_label_t f7; +- int rc, blksize; ++ unsigned int blksize; ++ int rc; + void *ipl1_record, *ipl2_record; + int ipl1_record_len, ipl2_record_len; + +@@ -559,9 +569,7 @@ static void dasdfmt_write_labels(dasdfmt + if (info->verbosity > 0) + printf("Retrieving dasd information... "); + +- if (ioctl(filedes, BLKSSZGET, &blksize) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL BLKSSZGET " +- "failed (%s).\n", prog_name, strerror(errno)); ++ get_blocksize(&blksize); + + /* + * Don't rely on the cylinders returned by HDIO_GETGEO, they might be diff --git a/s390-tools-sles12sp3-dasdfmt-07-Add-quick-format-support.patch b/s390-tools-sles12sp3-dasdfmt-07-Add-quick-format-support.patch new file mode 100644 index 0000000..555f4d2 --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-07-Add-quick-format-support.patch @@ -0,0 +1,555 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Add quick format support + + On occasion, a DASD device might have been formatted earlier and could + potentially be re-initialized very easily. For device initalization it + is necessary to write disk information (i.e. volume label (CDL or LDL) + and VTOC) to the first two tracks. Currently you'd need to format the + entire disk, which can take a long time and is totally unnecessary. + + Therefore, add a quick format mode which formats only the first two + tracks and fills them with data accordingly. + Before any formatting is done, several checks regarding the + expected device format are performed. + + The mode can be specified with the new command line switch -M (--mode) + . Where 'mode' can be either 'full' (default) or 'quick'. + + Document the switch -M (--mode) and its options full and quick in the + man page. + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.8 | 15 ++ + dasdfmt/dasdfmt.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- + dasdfmt/dasdfmt.h | 51 +++++++++ + 3 files changed, 344 insertions(+), 12 deletions(-) + +--- a/dasdfmt/dasdfmt.8 ++++ b/dasdfmt/dasdfmt.8 +@@ -67,7 +67,7 @@ Print version number and exit. + + .TP + \fB-F\fR or \fB--force\fR +-Formats the device without checking, if the device is in use. ++Formats the device without performing sanity checking. + + .TP + \fB-C\fR or \fB--check_host_count\fR +@@ -108,6 +108,19 @@ The value will be at least as big as the + .br + + .TP ++\fB-M\fR \fImode\fR or \fB--mode\fR=\fImode\fR ++Specify the \fImode\fR to be used to format the device. Valid modes are: ++.RS ++.IP full ++Format the entire disk with the specified blocksize. (default) ++.IP quick ++Format the first two tracks and write label and partition information. Only use ++this option if you are sure that the target DASD already contains a regular ++format with the specified blocksize. A blocksize can optionally be specified ++using \fB-b\fR (\fB--blocksize\fR). ++.RE ++ ++.TP + \fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR + Number of cylinders to be processed in one formatting step. + The value must be an integer in the range 1 - 255. +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -30,6 +30,7 @@ static const char copyright_notice[] = " + static int filedes; + static int disk_disabled; + static format_data_t format_params; ++static format_mode_t mode; + char *prog_name; + volatile sig_atomic_t program_interrupt_in_progress; + int reqsize; +@@ -53,6 +54,7 @@ static void exit_usage(int exitcode) + " [-b | --blocksize=]\n" + " [-d | --disk_layout=]\n" + " [-r | --requestsize=]\n" ++ " [-M | --mode=]\n" + " \n\n", prog_name); + + printf(" -t or --test means testmode\n" +@@ -65,7 +67,7 @@ static void exit_usage(int exitcode) + " -r x or --requestsize=x means use x cylinders in one " + "format step\n" + " -v means verbose mode\n" +- " -F means don't check if the device is in use\n" ++ " -F means format without performing sanity checking\n" + " -k means keep volume serial\n" + " -C or --check_host_count means force dasdfmt to check\n" + " the host access open count to ensure the device\n" +@@ -79,7 +81,10 @@ static void exit_usage(int exitcode) + " is either\n" + " 'cdl' for compatible disk layout (default) or\n" + " 'ldl' for linux disk layout\n" +- " device node of the device to format\n"); ++ " device node of the device to format\n" ++ " is either\n" ++ " 'full' to fully format the device (default)\n" ++ " 'quick' to format only the first two tracks\n"); + exit(exitcode); + } + +@@ -102,6 +107,131 @@ static int reread_partition_table(void) + } + + /* ++ * Helper function for recs_per_track. ++ */ ++static inline unsigned int ceil_quot(unsigned int d1, unsigned int d2) ++{ ++ return (d1 + (d2 - 1)) / d2; ++} ++ ++/* ++ * Calculate records per track depending on the device characteristics. ++ */ ++static unsigned int recs_per_track(struct dasd_eckd_characteristics *rdc, ++ unsigned int kl, unsigned int dl) ++{ ++ int dn, kn; ++ ++ switch (rdc->dev_type) { ++ case 0x3380: ++ if (kl) ++ return 1499 / (15 + 7 + ceil_quot(kl + 12, 32) + ++ ceil_quot(dl + 12, 32)); ++ else ++ return 1499 / (15 + ceil_quot(dl + 12, 32)); ++ case 0x3390: ++ dn = ceil_quot(dl + 6, 232) + 1; ++ if (kl) { ++ kn = ceil_quot(kl + 6, 232) + 1; ++ return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) + ++ 9 + ceil_quot(dl + 6 * dn, 34)); ++ } else ++ return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34)); ++ case 0x9345: ++ dn = ceil_quot(dl + 6, 232) + 1; ++ if (kl) { ++ kn = ceil_quot(kl + 6, 232) + 1; ++ return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) + ++ ceil_quot(dl + 6 * dn, 34)); ++ } else ++ return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34)); ++ } ++ return 0; ++} ++ ++/* ++ * Evaluate errors recognized by format checks and print appropriate error ++ * messages depending on the content of cdata. ++ */ ++static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata, ++ unsigned int heads) ++{ ++ struct dasd_eckd_characteristics *rdc; ++ /* Special blocksize values of the first 3 records of trk 0 of cyl 0 */ ++ const int blksizes_trk0[] = { 24, 144, 80 }; ++ /* Special blocksize value of trk 1 cyl 0 */ ++ const int blksize_trk1 = 96; ++ unsigned int cyl; ++ unsigned int head; ++ unsigned int rpt; ++ unsigned int kl = 0; ++ int blksize = cdata->expect.blksize; ++ ++ /* ++ * Reading record zero will never happen. If the record in error is 0 ++ * nonetheless, the device is not formatted at all! ++ */ ++ if (cdata->rec == 0) { ++ ERRMSG("WARNING: The specified device is not " ++ "formatted at all.\n"); ++ return; ++ } ++ ++ cyl = cdata->unit / heads; ++ head = cyl >> 16; ++ head <<= 4; ++ head |= cdata->unit % heads; ++ ++ /* ++ * Set special expected values for the first 3 records of trk 0 of cyl 0 ++ * and trk 1 of cyl 0 when checking a CDL formatted device. ++ */ ++ if ((cdata->expect.intensity & DASD_FMT_INT_COMPAT) && ++ cyl == 0 && head == 0 && cdata->rec < 4) { ++ kl = 4; ++ blksize = blksizes_trk0[cdata->rec - 1]; ++ } ++ if ((cdata->expect.intensity & DASD_FMT_INT_COMPAT) && ++ cyl == 0 && head == 1) { ++ kl = 44; ++ blksize = blksize_trk1; ++ } ++ ++ rdc = (struct dasd_eckd_characteristics *) ++ &info->dasd_info.characteristics; ++ ++ rpt = recs_per_track(rdc, kl, cdata->expect.blksize); ++ ++ ERRMSG("WARNING: The specified device is not formatted as expected.\n"); ++ switch (cdata->result) { ++ case DASD_FMT_ERR_TOO_FEW_RECORDS: ++ ERRMSG("Too few records (found %d, expected %d) " ++ "at cyl: %d trk: %d rec: %d.\n", ++ cdata->num_records, rpt, cyl, head, cdata->rec); ++ break; ++ case DASD_FMT_ERR_TOO_MANY_RECORDS: ++ ERRMSG("Too many records (found %d, expected %d) " ++ "at cyl: %d trk: %d rec: %d.\n", ++ cdata->num_records, rpt, cyl, head, cdata->rec); ++ break; ++ case DASD_FMT_ERR_BLKSIZE: ++ ERRMSG("Invalid blocksize (found %d, expected %d) " ++ "at cyl: %d trk: %d rec: %d.\n", ++ cdata->blksize, blksize, cyl, head, cdata->rec); ++ break; ++ case DASD_FMT_ERR_RECORD_ID: ++ ERRMSG("Invalid record ID at cyl: %d trk: %d rec: %d.\n", ++ cyl, head, cdata->rec); ++ break; ++ case DASD_FMT_ERR_KEY_LENGTH: ++ ERRMSG("Invalid key length (found %d, expected %d) " ++ "at cyl: %d trk: %d rec: %d.\n", ++ cdata->key_length, kl, cyl, head, cdata->rec); ++ break; ++ } ++} ++ ++/* + * signal handler: + * enables the disk again in case of SIGTERM, SIGINT and SIGQUIT + */ +@@ -263,6 +393,25 @@ static void get_blocksize(unsigned int * + } + + /* ++ * Check whether a specified blocksize matches the blocksize of the device ++ */ ++static void check_blocksize(dasdfmt_info_t *info, unsigned int blksize) ++{ ++ unsigned int dev_blksize; ++ ++ if (!info->blksize_specified || ++ info->dasd_info.format == DASD_FORMAT_NONE) ++ return; ++ ++ get_blocksize(&dev_blksize); ++ if (dev_blksize != blksize) { ++ ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a " ++ "different blocksize (%d).\nUse --mode=full to " ++ "perform a clean format.\n", dev_blksize); ++ } ++} ++ ++/* + * check for disk type and set some variables (e.g. usage count) + */ + static void check_disk(dasdfmt_info_t *info) +@@ -449,6 +598,35 @@ static void set_label(dasdfmt_info_t *in + } + + /* ++ * This function checks whether a range of tracks is in regular format ++ * with the specified block size. ++ */ ++static format_check_t check_track_format(format_data_t *p) ++{ ++ format_check_t cdata = { ++ .expect = { ++ .blksize = p->blksize, ++ .intensity = p->intensity, ++ .start_unit = p->start_unit, ++ .stop_unit = p->stop_unit ++ }, 0 ++ }; ++ ++ if (ioctl(filedes, BIODASDCHECKFMT, &cdata)) { ++ if (errno == ENOTTY) { ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: Missing kernel support " ++ "for format checking (--force to " ++ "override)\n", prog_name); ++ } ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n", ++ prog_name, strerror(errno)); ++ } ++ ++ return cdata; ++} ++ ++ ++/* + * ask the user to specify a blocksize + */ + static format_data_t ask_user_for_blksize(format_data_t params) +@@ -511,6 +689,8 @@ static void dasdfmt_print_info(dasdfmt_i + printf(" Compatible Disk Layout : %s\n", + (p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no"); + printf(" Blocksize : %d\n", p->blksize); ++ printf(" Mode : %s\n", ++ (mode == FULL) ? "Full" : "Quick"); + + if (info->testmode) + printf("Test mode active, omitting ioctl.\n"); +@@ -869,6 +1049,62 @@ static void dasdfmt_prepare_and_format(d + disk_disabled = 0; + } + ++/* ++ * This function will only format the first two tracks of a DASD. ++ * The rest of the DASD is untouched and left as is. ++ */ ++static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders, ++ unsigned int heads, format_data_t *p) ++{ ++ format_check_t cdata = { .expect = {0}, 0 }; ++ format_data_t tmp = *p; ++ ++ if (info->force) { ++ printf("Skipping format check due to --force.\n"); ++ } else { ++ check_blocksize(info, p->blksize); ++ ++ printf("Checking the format of selected tracks...\n"); ++ ++ /* Check device format on the first and last 3 regular tracks */ ++ tmp.start_unit = 2; ++ tmp.stop_unit = 4; ++ cdata = check_track_format(&tmp); ++ if (!cdata.result) { ++ tmp.start_unit = (cylinders * heads) - 3; ++ tmp.stop_unit = (cylinders * heads) - 1; ++ cdata = check_track_format(&tmp); ++ } ++ if (cdata.result) { ++ evaluate_format_error(info, &cdata, heads); ++ ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform " ++ "a clean format.\n"); ++ } else { ++ printf("Done. Disk seems fine.\n"); ++ } ++ } ++ ++ if (!((info->withoutprompt) && (info->verbosity < 1))) ++ printf("Formatting the first two tracks of the device.\n"); ++ ++ /* Disable the device before we do anything */ ++ if (ioctl(filedes, BIODASDDISABLE, p)) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to disable the device " ++ "failed. (%s)\n", prog_name, strerror(errno)); ++ disk_disabled = 1; ++ ++ /* Now do the actual formatting of our first two tracks */ ++ if (ioctl(filedes, BIODASDFMT, p)) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to format the device " ++ "failed. (%s)\n", prog_name, strerror(errno)); ++ ++ /* Re-Enable the device so that we can continue working with it */ ++ if (ioctl(filedes, BIODASDENABLE, p)) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to enable the device " ++ "failed. (%s)\n", prog_name, strerror(errno)); ++ disk_disabled = 0; ++} ++ + static void do_format_dasd(dasdfmt_info_t *info, volume_label_t *vlabel, + format_data_t *p, unsigned int cylinders, + unsigned int heads) +@@ -877,7 +1113,15 @@ static void do_format_dasd(dasdfmt_info_ + int count; + + p->start_unit = 0; +- p->stop_unit = (cylinders * heads) - 1; ++ ++ switch (mode) { ++ case FULL: /* all tracks */ ++ p->stop_unit = (cylinders * heads) - 1; ++ break; ++ case QUICK: /* just the first two */ ++ p->stop_unit = 1; ++ break; ++ } + + if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) + dasdfmt_print_info(info, vlabel, cylinders, heads, p); +@@ -919,11 +1163,17 @@ static void do_format_dasd(dasdfmt_info_ + } + } + +- if (!((info->withoutprompt) && (info->verbosity < 1))) +- printf("Formatting the device. This may take a " +- "while (get yourself a coffee).\n"); +- +- dasdfmt_prepare_and_format(info, cylinders, heads, p); ++ switch (mode) { ++ case FULL: ++ if (!((info->withoutprompt) && (info->verbosity < 1))) ++ printf("Formatting the device. This may take a " ++ "while (get yourself a coffee).\n"); ++ dasdfmt_prepare_and_format(info, cylinders, heads, p); ++ break; ++ case QUICK: ++ dasdfmt_quick_format(info, cylinders, heads, p); ++ break; ++ } + + if (!info->yast_mode) + printf("Finished formatting the device.\n"); +@@ -981,6 +1231,8 @@ int main(int argc, char *argv[]) + format_params.blksize = DEFAULT_BLOCKSIZE; + format_params.intensity = DASD_FMT_INT_COMPAT; + ++ mode = FULL; ++ + /*************** parse parameters **********************/ + + while (1) { +@@ -1082,6 +1334,18 @@ int main(int argc, char *argv[]) + case 'C': + info.force_host = 1; + break; ++ case 'M': ++ if (strcasecmp(optarg, "full") == 0) ++ mode = FULL; ++ else if (strcasecmp(optarg, "quick") == 0) ++ mode = QUICK; ++ else ++ ERRMSG_EXIT(EXIT_FAILURE, ++ "%s: The specified mode '%s' is " ++ "invalid. Consult the man page for " ++ "more information.\n", ++ prog_name, optarg); ++ break; + case -1: + /* End of options string - start of devices list */ + info.device_id = optind; +@@ -1194,8 +1458,14 @@ int main(int argc, char *argv[]) + + get_device_info(&info); + +- if (!info.blksize_specified) +- format_params = ask_user_for_blksize(format_params); ++ /* Either let the user specify the blksize or get it from the kernel */ ++ if (!info.blksize_specified) { ++ if (!(mode == FULL || ++ info.dasd_info.format == DASD_FORMAT_NONE)) ++ get_blocksize(&format_params.blksize); ++ else ++ format_params = ask_user_for_blksize(format_params); ++ } + + if (info.keep_volser) { + if (format_params.intensity == 0x00) { +--- a/dasdfmt/dasdfmt.h ++++ b/dasdfmt/dasdfmt.h +@@ -143,6 +143,14 @@ struct dasd_eckd_characteristics { + unsigned int long_no_cyl; + } __attribute__ ((packed)); + ++/* ++ * Represents possible format modes that can be specified when formatting ++ * a DASD. ++ */ ++typedef enum format_mode_t { ++ FULL, /* default mode */ ++ QUICK, /* format only the first 2 tracks */ ++} format_mode_t; + + /* + * struct format_data_t +@@ -168,6 +176,43 @@ typedef struct format_data_t { + #define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */ + #define DASD_FMT_INT_FMT_NOR0 16 /* remove permission to write record zero */ + ++/* ++ * struct format_check_t ++ * represents all data necessary to evaluate the format of ++ * different tracks of a dasd ++ */ ++typedef struct format_check_t { ++ /* Input */ ++ struct format_data_t expect; ++ ++ /* Output */ ++ unsigned int result; /* Error indication (DASD_FMT_ERR_*) */ ++ unsigned int unit; /* Track that is in error */ ++ unsigned int rec; /* Record that is in error */ ++ unsigned int num_records; /* Records in the track in error */ ++ unsigned int blksize; /* Block-size of first record in error */ ++ unsigned int key_length; /* Key length of first record in error */ ++} format_check_t; ++ ++/* ++ * values to be used in format_check_t for indicating ++ * possible format errors ++ */ ++#define DASD_FMT_ERR_TOO_FEW_RECORDS 1 ++#define DASD_FMT_ERR_TOO_MANY_RECORDS 2 ++#define DASD_FMT_ERR_BLKSIZE 3 ++#define DASD_FMT_ERR_RECORD_ID 4 ++#define DASD_FMT_ERR_KEY_LENGTH 5 ++ ++/* ++ * values to be used for dasd_information2_t.format ++ * 0x00: NOT formatted ++ * 0x01: Linux disc layout ++ * 0x02: Common disc layout ++ */ ++#define DASD_FORMAT_NONE 0 ++#define DASD_FORMAT_LDL 1 ++#define DASD_FORMAT_CDL 2 + + /* Disable the volume (for Linux) */ + #define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) +@@ -180,6 +225,9 @@ typedef struct format_data_t { + /* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ + #define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t) + ++/* Check device format according to format_data_t */ ++#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t) ++ + /**************************************************************************** + * SECTION: Further IOCTL Definitions (see fs.h and hdreq.h ) * + ****************************************************************************/ +@@ -225,7 +273,7 @@ typedef struct format_data_t { + if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ + "is in invalid format\n",prog_name);} + +-#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpQLtyvVFkCYP:" ++#define dasdfmt_getopt_string "b:n:l:f:d:m:M:r:hpQLtyvVFkCYP:" + + static struct option dasdfmt_getopt_long_options[]= + { +@@ -247,6 +295,7 @@ static struct option dasdfmt_getopt_long + { "keep_volser", 0, 0, 'k'}, + { "norecordzero", 0, 0, 'z'}, + { "check_host_count", 0, 0, 'C'}, ++ { "mode", 1, 0, 'M'}, + {0, 0, 0, 0} + }; + diff --git a/s390-tools-sles12sp3-dasdfmt-08-Make-progress-output-reusable-and-add-ETR.patch b/s390-tools-sles12sp3-dasdfmt-08-Make-progress-output-reusable-and-add-ETR.patch new file mode 100644 index 0000000..0063641 --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-08-Make-progress-output-reusable-and-add-ETR.patch @@ -0,0 +1,279 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Make progress output reusable and add ETR + + The progress indicator (in form of a progressbar, hashmarks or + percentages) is created within the formatting loop. + + Put the drawing of the progress into a separate function to make it + reusable. Clean up the formatting loop while at it and make it + more readable. Also, add the estimated time remaining to the output. + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.c | 198 +++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 138 insertions(+), 60 deletions(-) + +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -11,6 +11,7 @@ + + #include + #include ++#include + + #include "zt_common.h" + #include "dasdfmt.h" +@@ -20,6 +21,8 @@ + #include + + #define BUSIDSIZE 8 ++#define SEC_PER_DAY (60 * 60 * 24) ++#define SEC_PER_HOUR (60 * 60) + + /* Full tool name */ + static const char tool_name[] = "dasdfmt: zSeries DASD format program"; +@@ -88,6 +91,120 @@ static void exit_usage(int exitcode) + exit(exitcode); + } + ++/* ++ * Helper function to calculate the days, hours, minutes, and seconds ++ * for a given timestamp in seconds ++ */ ++static void calc_time(time_t time, int *d, int *h, int *m, int *s) ++{ ++ *d = time / SEC_PER_DAY; ++ time %= SEC_PER_DAY; ++ *h = time / SEC_PER_HOUR; ++ time %= SEC_PER_HOUR; ++ *m = time / 60; ++ *s = time % 60; ++} ++ ++/* ++ * This function calculates and prints the estimated time remaining. ++ */ ++static void print_etr(int p_new, int started) ++{ ++ static struct timeval start; ++ struct timeval now; ++ time_t time_elapsed; ++ time_t time_end; ++ int d, h, m, s; ++ static int p_init; ++ int p; ++ ++ if (!started) { ++ gettimeofday(&start, NULL); ++ p_init = p_new; ++ } ++ gettimeofday(&now, NULL); ++ time_elapsed = now.tv_sec - start.tv_sec; ++ ++ /* ++ * We might start somewhere in the middle with an initial percentage ++ * value of i.e. 60%. Therefore we need to calculate the relative ++ * percentage of p_new within that remaining range (100 - 60) in order ++ * to correctly estimate the remaining time. ++ */ ++ if (p_init == 100) ++ p = p_init; ++ else ++ p = 100 * (p_new - p_init) / (100 - p_init); ++ ++ if (p == 0) ++ time_end = time_elapsed; ++ else ++ time_end = time_elapsed * (100 - p) / p; ++ ++ /* Calculate days, hours, minutes, and seconds */ ++ calc_time(time_end, &d, &h, &m, &s); ++ if (p_new == 100) ++ calc_time(time_elapsed, &d, &h, &m, &s); ++ ++ /* Avoid printing leading zeros */ ++ if (d > 0) ++ printf(" [%dd %dh %dm %ds%-4s", d, h, m, s, "]"); ++ else if (h > 0) ++ printf(" [%dh %dm %ds%-7s", h, m, s, "]"); ++ else if (m > 0) ++ printf(" [%dm %ds%-6s", m, s, "]"); ++ else if (s > 0 || p > 50) ++ printf(" [%ds%-5s", s, "]"); ++ else ++ printf(" [--%-1s", "]"); ++} ++ ++/* ++ * Draw the progress indicator depending on what command line argument is set. ++ * This can either be a progressbar, hashmarks, or percentage. ++ */ ++static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders) ++{ ++ static int hashcount; ++ static int started; ++ static int p_old; ++ int p_new = 0; ++ int barlength; ++ int i; ++ ++ if (info->print_progressbar) { ++ printf("cyl %7d of %7d |", cyl, cylinders); ++ p_new = cyl * 100 / cylinders; ++ if (p_new != p_old || !started) { ++ /* percent value has changed */ ++ p_old = p_new; ++ barlength = cyl * 33 / cylinders; ++ for (i = 1; i <= barlength; i++) ++ printf("#"); ++ for (i = barlength + 1; i <= 33; i++) ++ printf("-"); ++ printf("|%3d%%", p_new); ++ print_etr(p_new, started); ++ started = 1; ++ } ++ printf("\r"); ++ fflush(stdout); ++ } ++ ++ if (info->print_hashmarks && ++ (cyl / info->hashstep - hashcount) != 0) { ++ printf("%d|", info->procnum); ++ fflush(stdout); ++ hashcount++; ++ } ++ ++ if (info->print_percentage) { ++ printf("cyl %7d of %7d |%3d%%\n", cyl, cylinders, ++ cyl * 100 / cylinders); ++ fflush(stdout); ++ } ++} ++ + static int reread_partition_table(void) + { + int i = 0; +@@ -906,9 +1023,10 @@ static void dasdfmt_write_labels(dasdfmt + static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders, + unsigned int heads, format_data_t *format_params) + { +- format_data_t format_step; +- int j, cyl, tmp, p1, p2, hashcount = 0; +- unsigned int k; ++ unsigned int step_value; ++ unsigned long cur_trk; ++ format_data_t step; ++ int cyl = 0; + + if (info->print_hashmarks) { + if (info->hashstep < reqsize) +@@ -923,73 +1041,33 @@ static void dasdfmt_format(dasdfmt_info_ + info->hashstep); + } + +- format_step.blksize = format_params->blksize; +- format_step.intensity = format_params->intensity; +- +- k = 0; +- cyl = 1; +- if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) +- printf("\n"); +- +- while (1) { +- p1 = -1; +- p2 = 0; +- if (k + heads * reqsize >= format_params->stop_unit) +- reqsize = 1; +- format_step.start_unit = k; +- format_step.stop_unit = k + reqsize * heads - 1; ++ step = *format_params; ++ cur_trk = format_params->start_unit; + +- if (cyl == 1) +- format_step.start_unit += 1; ++ while (cur_trk < format_params->stop_unit) { ++ step_value = reqsize * heads - (cur_trk % heads); ++ step.start_unit = cur_trk; ++ if (cur_trk + reqsize * heads >= format_params->stop_unit) ++ step.stop_unit = format_params->stop_unit; ++ else ++ step.stop_unit = cur_trk + step_value - 1; + +- if (ioctl(filedes, BIODASDFMT, &format_step) != 0) ++ if (ioctl(filedes, BIODASDFMT, &step) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (format cylinder) IOCTL " + "BIODASDFMT failed. (%s)\n", + prog_name, strerror(errno)); + +- if (info->print_progressbar) { +- printf("cyl %7d of %7d |", cyl, cylinders); +- p2 = p1; +- p1 = cyl * 100 / cylinders; +- if (p1 != p2) { +- /* percent value has changed */ +- tmp = cyl * 50 / cylinders; +- for (j = 1; j <= tmp; j++) +- printf("#"); +- for (j = tmp + 1; j <= 50; j++) +- printf("-"); +- printf("|%3d%%", p1); +- } +- printf("\r"); +- fflush(stdout); +- } +- +- if (info->print_hashmarks) +- if ((cyl / info->hashstep - hashcount) != 0) { +- printf("%d|",info->procnum); +- fflush(stdout); +- hashcount++; +- } +- +- if (info->print_percentage) { +- printf("cyl %7d of %7d |%3d%%\n", cyl, cylinders, +- cyl*100/cylinders); +- fflush(stdout); +- } ++ cyl = cur_trk / heads + 1; ++ draw_progress(info, cyl, cylinders); + +- if (k % heads == 0) { +- k += reqsize * heads; +- cyl += reqsize; +- } else { +- k += format_params->stop_unit % heads; +- } +- +- if (k > format_params->stop_unit) +- break; ++ cur_trk += step_value; + } ++ /* We're done, draw the 100% mark */ ++ cyl = step.stop_unit / heads + 1; ++ draw_progress(info, cyl, cylinders); + + if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) +- printf("\n\n"); ++ printf("\n"); + } + + static void dasdfmt_prepare_and_format(dasdfmt_info_t *info, diff --git a/s390-tools-sles12sp3-dasdfmt-09-Add-command-line-argument-check.patch b/s390-tools-sles12sp3-dasdfmt-09-Add-command-line-argument-check.patch new file mode 100644 index 0000000..d06bab5 --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-09-Add-command-line-argument-check.patch @@ -0,0 +1,453 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Add command line argument --check + + Provide a function to check a DASD volume for correct formatting. This + can be useful in cases where only a few tracks of a volume are + incorrectly formatted. + + All tracks on the device are checked. In an error case, the check + process is stopped and appropriate messages are displayed. + + The --check command line argument can be combined with either -P, + -p or -m to display progress on the console. + + Signed-off-by: Jan Höppner + Signed-off-by: Stefan Haberland + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.8 | 5 + + dasdfmt/dasdfmt.c | 244 ++++++++++++++++++++++++++++++++++++++++-------------- + dasdfmt/dasdfmt.h | 4 + 3 files changed, 190 insertions(+), 63 deletions(-) + +--- a/dasdfmt/dasdfmt.8 ++++ b/dasdfmt/dasdfmt.8 +@@ -121,6 +121,11 @@ using \fB-b\fR (\fB--blocksize\fR). + .RE + + .TP ++\fB--check\fR ++Perform a complete format check on a DASD volume. A blocksize can be specified ++with \fB-b\fR (\fB--blocksize\fR). ++ ++.TP + \fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR + Number of cylinders to be processed in one formatting step. + The value must be an integer in the range 1 - 255. +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -76,7 +76,8 @@ static void exit_usage(int exitcode) + " the host access open count to ensure the device\n" + " is not online on another operating system instance\n" + " --norecordzero prevent storage server from modifying" +- " record 0\n\n" ++ " record 0\n" ++ " --check perform complete format check on device\n\n" + " is the volume identifier, which is converted\n" + " to EBCDIC and written to disk.\n" + " (6 characters, e.g. LNX001\n" +@@ -163,7 +164,8 @@ static void print_etr(int p_new, int sta + * Draw the progress indicator depending on what command line argument is set. + * This can either be a progressbar, hashmarks, or percentage. + */ +-static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders) ++static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders, ++ int aborted) + { + static int hashcount; + static int started; +@@ -175,7 +177,7 @@ static void draw_progress(dasdfmt_info_t + if (info->print_progressbar) { + printf("cyl %7d of %7d |", cyl, cylinders); + p_new = cyl * 100 / cylinders; +- if (p_new != p_old || !started) { ++ if (p_new != p_old || !started || aborted) { + /* percent value has changed */ + p_old = p_new; + barlength = cyl * 33 / cylinders; +@@ -184,6 +186,8 @@ static void draw_progress(dasdfmt_info_t + for (i = barlength + 1; i <= 33; i++) + printf("-"); + printf("|%3d%%", p_new); ++ if (aborted) ++ p_new = 100; + print_etr(p_new, started); + started = 1; + } +@@ -284,11 +288,17 @@ static void evaluate_format_error(dasdfm + unsigned int kl = 0; + int blksize = cdata->expect.blksize; + ++ if (info->print_progressbar || info->print_hashmarks) ++ printf("\n"); ++ + /* +- * Reading record zero will never happen. If the record in error is 0 +- * nonetheless, the device is not formatted at all! ++ * If mode is not QUICK and a device format couldn't be determined, the ++ * device is considered not formatted. ++ * Also, reading record zero will never happen. If the record in error ++ * is 0 nonetheless, the device is not formatted at all as well! + */ +- if (cdata->rec == 0) { ++ if ((info->dasd_info.format == DASD_FORMAT_NONE && mode != QUICK) || ++ cdata->rec == 0) { + ERRMSG("WARNING: The specified device is not " + "formatted at all.\n"); + return; +@@ -529,6 +539,35 @@ static void check_blocksize(dasdfmt_info + } + + /* ++ * Check whether a specified layout matches the layout ++ * a device is formatted with. ++ */ ++static void check_layout(dasdfmt_info_t *info, unsigned int intensity) ++{ ++ char layout[4]; ++ ++ if (!info->layout_specified || ++ info->dasd_info.format == DASD_FORMAT_NONE) ++ return; ++ ++ if ((intensity & DASD_FMT_INT_COMPAT) && ++ info->dasd_info.format == DASD_FORMAT_CDL) ++ return; ++ ++ if (!(intensity & DASD_FMT_INT_COMPAT) && ++ info->dasd_info.format == DASD_FORMAT_LDL) ++ return; ++ ++ if (info->dasd_info.format == DASD_FORMAT_CDL) ++ sprintf(layout, "CDL"); ++ if (info->dasd_info.format == DASD_FORMAT_LDL) ++ sprintf(layout, "LDL"); ++ ++ ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a " ++ "different layout (%s).\n", layout); ++} ++ ++/* + * check for disk type and set some variables (e.g. usage count) + */ + static void check_disk(dasdfmt_info_t *info) +@@ -715,10 +754,29 @@ static void set_label(dasdfmt_info_t *in + } + + /* ++ * Check whether hashsteps are within the correct interval. ++ */ ++static void check_hashmarks(dasdfmt_info_t *info) ++{ ++ if (info->print_hashmarks) { ++ if (info->hashstep < reqsize) ++ info->hashstep = reqsize; ++ if ((info->hashstep < 1) || (info->hashstep > 1000)) { ++ printf("Hashmark increment is not in range <1,1000>, " ++ "using the default.\n"); ++ info->hashstep = 10; ++ } ++ ++ printf("Printing hashmark every %d cylinders.\n", ++ info->hashstep); ++ } ++} ++ ++/* + * This function checks whether a range of tracks is in regular format + * with the specified block size. + */ +-static format_check_t check_track_format(format_data_t *p) ++static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p) + { + format_check_t cdata = { + .expect = { +@@ -731,9 +789,11 @@ static format_check_t check_track_format + + if (ioctl(filedes, BIODASDCHECKFMT, &cdata)) { + if (errno == ENOTTY) { +- ERRMSG_EXIT(EXIT_FAILURE, "%s: Missing kernel support " +- "for format checking (--force to " +- "override)\n", prog_name); ++ ERRMSG("%s: Missing kernel support for format checking", ++ prog_name); ++ if (!info->check) ++ ERRMSG(" (--force to override)"); ++ ERRMSG_EXIT(EXIT_FAILURE, ".\n"); + } + ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n", + prog_name, strerror(errno)); +@@ -742,6 +802,97 @@ static format_check_t check_track_format + return cdata; + } + ++/* ++ * Either do the actual format or check depending on the check-value. ++ */ ++static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders, ++ unsigned int heads, format_data_t *format_params) ++{ ++ format_check_t cdata = { .expect = {0}, 0}; ++ format_data_t step = *format_params; ++ unsigned long step_value; ++ unsigned long cur_trk; ++ int cyl = 0; ++ ++ check_hashmarks(info); ++ ++ cur_trk = format_params->start_unit; ++ ++ while (cur_trk < format_params->stop_unit) { ++ step_value = reqsize * heads - (cur_trk % heads); ++ step.start_unit = cur_trk; ++ if (cur_trk + heads * reqsize >= format_params->stop_unit) ++ step.stop_unit = format_params->stop_unit; ++ else ++ step.stop_unit = cur_trk + step_value - 1; ++ ++ if (info->check) { ++ cdata = check_track_format(info, &step); ++ if (cdata.result) { ++ cyl = cur_trk / heads + 1; ++ draw_progress(info, cyl, cylinders, 1); ++ evaluate_format_error(info, &cdata, heads); ++ break; ++ } ++ } else { ++ if (ioctl(filedes, BIODASDFMT, &step) != 0) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call " ++ "to format tracks failed. (%s)\n", ++ prog_name, strerror(errno)); ++ } ++ ++ cyl = cur_trk / heads + 1; ++ draw_progress(info, cyl, cylinders, 0); ++ ++ cur_trk += step_value; ++ } ++ /* We're done, draw the 100% mark */ ++ if (!cdata.result) { ++ cyl = step.stop_unit / heads + 1; ++ draw_progress(info, cyl, cylinders, 0); ++ printf("\n"); ++ } ++ ++ return cdata.result; ++} ++ ++/* ++ * This function checks the format of the entire disk. ++ */ ++static void check_disk_format(dasdfmt_info_t *info, unsigned int cylinders, ++ unsigned int heads, format_data_t *check_params) ++{ ++ check_params->start_unit = 0; ++ check_params->stop_unit = (cylinders * heads) - 1; ++ ++ printf("Checking format of the entire disk...\n"); ++ ++ if (info->testmode) { ++ printf("Test mode active, omitting ioctl.\n"); ++ return; ++ } ++ ++ check_blocksize(info, check_params->blksize); ++ check_layout(info, check_params->intensity); ++ ++ /* ++ * If no layout was specified, set the intensity ++ * according to what the layout seems to be. ++ */ ++ if (!info->layout_specified) { ++ if (info->dasd_info.format == DASD_FORMAT_CDL) ++ check_params->intensity |= DASD_FMT_INT_COMPAT; ++ else if (info->dasd_info.format == DASD_FORMAT_LDL) ++ check_params->intensity &= ~DASD_FMT_INT_COMPAT; ++ } ++ ++ if (process_tracks(info, cylinders, heads, check_params)) { ++ ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform a " ++ "clean format.\n"); ++ } ++ ++ printf("Done. Disk is fine.\n"); ++} + + /* + * ask the user to specify a blocksize +@@ -1023,51 +1174,7 @@ static void dasdfmt_write_labels(dasdfmt + static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders, + unsigned int heads, format_data_t *format_params) + { +- unsigned int step_value; +- unsigned long cur_trk; +- format_data_t step; +- int cyl = 0; +- +- if (info->print_hashmarks) { +- if (info->hashstep < reqsize) +- info->hashstep = reqsize; +- if ((info->hashstep < 1) || (info->hashstep > 1000)) { +- printf("Hashmark increment is not in range <1,1000>, " +- "using the default.\n"); +- info->hashstep = 10; +- } +- +- if(!info->yast_mode) printf("Printing hashmark every %d cylinders.\n", +- info->hashstep); +- } +- +- step = *format_params; +- cur_trk = format_params->start_unit; +- +- while (cur_trk < format_params->stop_unit) { +- step_value = reqsize * heads - (cur_trk % heads); +- step.start_unit = cur_trk; +- if (cur_trk + reqsize * heads >= format_params->stop_unit) +- step.stop_unit = format_params->stop_unit; +- else +- step.stop_unit = cur_trk + step_value - 1; +- +- if (ioctl(filedes, BIODASDFMT, &step) != 0) +- ERRMSG_EXIT(EXIT_FAILURE, "%s: (format cylinder) IOCTL " +- "BIODASDFMT failed. (%s)\n", +- prog_name, strerror(errno)); +- +- cyl = cur_trk / heads + 1; +- draw_progress(info, cyl, cylinders); +- +- cur_trk += step_value; +- } +- /* We're done, draw the 100% mark */ +- cyl = step.stop_unit / heads + 1; +- draw_progress(info, cyl, cylinders); +- +- if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) +- printf("\n"); ++ process_tracks(info, cylinders, heads, format_params); + } + + static void dasdfmt_prepare_and_format(dasdfmt_info_t *info, +@@ -1082,6 +1189,10 @@ static void dasdfmt_prepare_and_format(d + | DASD_FMT_INT_INVAL) + }; + ++ if (!((info->withoutprompt) && (info->verbosity < 1))) ++ printf("Formatting the device. This may take a while " ++ "(get yourself a coffee).\n"); ++ + if (info->verbosity > 0) + printf("Detaching the device...\n"); + +@@ -1147,11 +1258,11 @@ static void dasdfmt_quick_format(dasdfmt + /* Check device format on the first and last 3 regular tracks */ + tmp.start_unit = 2; + tmp.stop_unit = 4; +- cdata = check_track_format(&tmp); ++ cdata = check_track_format(info, &tmp); + if (!cdata.result) { + tmp.start_unit = (cylinders * heads) - 3; + tmp.stop_unit = (cylinders * heads) - 1; +- cdata = check_track_format(&tmp); ++ cdata = check_track_format(info, &tmp); + } + if (cdata.result) { + evaluate_format_error(info, &cdata, heads); +@@ -1243,9 +1354,6 @@ static void do_format_dasd(dasdfmt_info_ + + switch (mode) { + case FULL: +- if (!((info->withoutprompt) && (info->verbosity < 1))) +- printf("Formatting the device. This may take a " +- "while (get yourself a coffee).\n"); + dasdfmt_prepare_and_format(info, cylinders, heads, p); + break; + case QUICK: +@@ -1337,6 +1445,7 @@ int main(int argc, char *argv[]) + printf("%s is not a valid option!\n", optarg); + exit(1); + } ++ info.layout_specified = 1; + break; + case 'y': + info.withoutprompt = 1; +@@ -1424,6 +1533,9 @@ int main(int argc, char *argv[]) + "more information.\n", + prog_name, optarg); + break; ++ case OPT_CHECK: ++ info.check = 1; ++ break; + case -1: + /* End of options string - start of devices list */ + info.device_id = optind; +@@ -1539,7 +1651,7 @@ int main(int argc, char *argv[]) + /* Either let the user specify the blksize or get it from the kernel */ + if (!info.blksize_specified) { + if (!(mode == FULL || +- info.dasd_info.format == DASD_FORMAT_NONE)) ++ info.dasd_info.format == DASD_FORMAT_NONE) || info.check) + get_blocksize(&format_params.blksize); + else + format_params = ask_user_for_blksize(format_params); +@@ -1568,8 +1680,14 @@ int main(int argc, char *argv[]) + + set_geo(&info, &cylinders, &heads); + set_label(&info, &vlabel, &format_params, cylinders); +- do_format_dasd(&info, &vlabel, &format_params, +- cylinders, heads); ++ ++ if (info.check) { ++ check_disk_format(&info, cylinders, heads, ++ &format_params); ++ } else { ++ do_format_dasd(&info, &vlabel, &format_params, ++ cylinders, heads); ++ } + + if (close(filedes) != 0) + ERRMSG("%s: error during close: %s\ncontinuing...\n", +--- a/dasdfmt/dasdfmt.h ++++ b/dasdfmt/dasdfmt.h +@@ -273,6 +273,7 @@ typedef struct format_check_t { + if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ + "is in invalid format\n",prog_name);} + ++#define OPT_CHECK 128 + #define dasdfmt_getopt_string "b:n:l:f:d:m:M:r:hpQLtyvVFkCYP:" + + static struct option dasdfmt_getopt_long_options[]= +@@ -296,6 +297,7 @@ static struct option dasdfmt_getopt_long + { "norecordzero", 0, 0, 'z'}, + { "check_host_count", 0, 0, 'C'}, + { "mode", 1, 0, 'M'}, ++ { "check", 0, 0, OPT_CHECK}, + {0, 0, 0, 0} + }; + +@@ -328,6 +330,8 @@ typedef struct dasdfmt_info { + int device_id; + int keep_volser; + int force_host; ++ int layout_specified; ++ int check; + int yast_mode; + int procnum; + } dasdfmt_info_t; diff --git a/s390-tools-sles12sp3-dasdfmt-10-Add-expand-format-mode.patch b/s390-tools-sles12sp3-dasdfmt-10-Add-expand-format-mode.patch new file mode 100644 index 0000000..840edfb --- /dev/null +++ b/s390-tools-sles12sp3-dasdfmt-10-Add-expand-format-mode.patch @@ -0,0 +1,266 @@ +Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes +From: Jan Höppner + +Summary: dasdfmt: Add new formatting modes +Description: Introduce new formatting modes 'quick' and 'expand' to either + format an earlier formatted DASD that could potentially be + re-initialized very easily or format unformatted tracks at the + end of a device that was previously extended. + + Also add the command line argument --check to provide a function + that checks a DASD volume for correct formatting. +Upstream-ID: - +Problem-ID: LS1501 + +Upstream-Description: + + dasdfmt: Add expand format mode + + If a DASD was extended, the format of the first part of the disk + can be assumed to be correct. Usually, a full format would be necessary + to ensure a fully functional disk. However, this would also format + the already formatted part resulting in the loss of the data stored in + that part. + + Add an expand mode which will search for the start of the unformatted + area and begin formatting from there. + + The mode is being specified by --mode=expand (or -M expand for short). + + Furthermore: + - Add string array for the individual modes for output purposes + - Avoid writing labels when EXPAND mode is active since they can be + assumed to be correct + - Add man page description + + +Signed-off-by: Jan Höppner +--- + dasdfmt/dasdfmt.8 | 7 +++ + dasdfmt/dasdfmt.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++----- + dasdfmt/dasdfmt.h | 5 ++ + 3 files changed, 123 insertions(+), 9 deletions(-) + +--- a/dasdfmt/dasdfmt.8 ++++ b/dasdfmt/dasdfmt.8 +@@ -118,6 +118,13 @@ Format the first two tracks and write la + this option if you are sure that the target DASD already contains a regular + format with the specified blocksize. A blocksize can optionally be specified + using \fB-b\fR (\fB--blocksize\fR). ++.IP expand ++Format all unformatted tracks at the end of the target DASD. This mode assumes ++that tracks at the beginning of the DASD volume have already been correctly ++formatted, while a consecutive set of tracks at the end are unformatted. You can ++use this mode to make added space available for Linux use after dynamically ++increasing the size of a DASD volume. A blocksize can optionally be specified ++using \fB-b\fR (\fB--blocksize\fR). + .RE + + .TP +--- a/dasdfmt/dasdfmt.c ++++ b/dasdfmt/dasdfmt.c +@@ -88,7 +88,9 @@ static void exit_usage(int exitcode) + " device node of the device to format\n" + " is either\n" + " 'full' to fully format the device (default)\n" +- " 'quick' to format only the first two tracks\n"); ++ " 'quick' to format only the first two tracks\n" ++ " 'expand' to format only the unformatted end" ++ " of a device\n"); + exit(exitcode); + } + +@@ -791,8 +793,11 @@ static format_check_t check_track_format + if (errno == ENOTTY) { + ERRMSG("%s: Missing kernel support for format checking", + prog_name); +- if (!info->check) ++ if (mode == EXPAND) { ++ ERRMSG(". Mode 'expand' cannot be used"); ++ } else if (!info->check) { + ERRMSG(" (--force to override)"); ++ } + ERRMSG_EXIT(EXIT_FAILURE, ".\n"); + } + ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n", +@@ -957,8 +962,7 @@ static void dasdfmt_print_info(dasdfmt_i + printf(" Compatible Disk Layout : %s\n", + (p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no"); + printf(" Blocksize : %d\n", p->blksize); +- printf(" Mode : %s\n", +- (mode == FULL) ? "Full" : "Quick"); ++ printf(" Mode : %s\n", mode_str[mode]); + + if (info->testmode) + printf("Test mode active, omitting ioctl.\n"); +@@ -1169,6 +1173,60 @@ static void dasdfmt_write_labels(dasdfmt + } + + /* ++ * This function will search for the beginning of an unformatted area ++ * on the device. It checks selected tracks beforehand and makes sure ++ * that the device is formatted to a certain extent. Otherwise the ++ * process is terminated. ++ */ ++static void dasdfmt_find_start(dasdfmt_info_t *info, unsigned int cylinders, ++ unsigned heads, format_data_t *format_params) ++{ ++ format_check_t cdata; ++ unsigned int middle; ++ unsigned int left = 2; ++ unsigned int right = (cylinders * heads) - 1; ++ unsigned int first = left; ++ ++ check_blocksize(info, format_params->blksize); ++ ++ format_params->start_unit = 0; ++ format_params->stop_unit = 4; ++ cdata = check_track_format(info, format_params); ++ ++ if (cdata.result) { ++ evaluate_format_error(info, &cdata, heads); ++ ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform a " ++ "clean format.\n"); ++ } ++ ++ printf("Expansion mode active. Searching for starting position...\n"); ++ ++ while (left <= right) { ++ /* new track number to look at */ ++ middle = left + ((right - left) / 2); ++ ++ format_params->start_unit = middle; ++ format_params->stop_unit = middle; ++ cdata = check_track_format(info, format_params); ++ if (cdata.blksize != format_params->blksize) { ++ first = middle; ++ right = middle - 1; ++ } else { ++ left = middle + 1; ++ } ++ } ++ ++ if (first == 2 && cdata.blksize == format_params->blksize) ++ ERRMSG_EXIT(EXIT_FAILURE, ++ "No unformatted part found, aborting.\n"); ++ ++ printf("Done. Unformatted part starts at track %d.\n", first); ++ ++ /* return format_params with start_unit set to the correct value */ ++ format_params->start_unit = first; ++} ++ ++/* + * formats the disk cylinderwise + */ + static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders, +@@ -1239,6 +1297,40 @@ static void dasdfmt_prepare_and_format(d + } + + /* ++ * This function will start the expand format process. ++ */ ++static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders, ++ unsigned int heads, format_data_t *p) ++{ ++ if (!((info->withoutprompt) && (info->verbosity < 1))) ++ printf("Formatting the device. This may take a while " ++ "(get yourself a coffee).\n"); ++ ++ if (info->verbosity > 0) ++ printf("Detaching the device...\n"); ++ ++ if (ioctl(filedes, BIODASDDISABLE, p) != 0) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " ++ "BIODASDDISABLE failed. (%s)\n", prog_name, ++ strerror(errno)); ++ disk_disabled = 1; ++ ++ dasdfmt_format(info, cylinders, heads, p); ++ ++ if (info->verbosity > 0) ++ printf("Formatting tracks complete...\n"); ++ ++ if (info->verbosity > 0) ++ printf("Re-accessing the device...\n"); ++ ++ if (ioctl(filedes, BIODASDENABLE, p) != 0) ++ ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " ++ "BIODASDENABLE failed. (%s)\n", prog_name, ++ strerror(errno)); ++ disk_disabled = 0; ++} ++ ++/* + * This function will only format the first two tracks of a DASD. + * The rest of the DASD is untouched and left as is. + */ +@@ -1310,6 +1402,10 @@ static void do_format_dasd(dasdfmt_info_ + case QUICK: /* just the first two */ + p->stop_unit = 1; + break; ++ case EXPAND: /* only the end of the disk */ ++ dasdfmt_find_start(info, cylinders, heads, p); ++ p->stop_unit = (cylinders * heads) - 1; ++ break; + } + + if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) +@@ -1338,10 +1434,12 @@ static void do_format_dasd(dasdfmt_info_ + + if (!info->testmode) { + if (!info->withoutprompt) { +- printf("\n--->> ATTENTION! <<---\n"); +- printf("All data of that device will be lost.\nType " +- "\"yes\" to continue, no will leave the disk " +- "untouched: "); ++ printf("\n"); ++ if (mode != EXPAND) ++ printf("--->> ATTENTION! <<---\nAll data of " ++ "that device will be lost.\n"); ++ printf("Type \"yes\" to continue, no will leave the " ++ "disk untouched: "); + if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL) + return; + if (strcasecmp(inp_buffer, "yes") && +@@ -1359,12 +1457,14 @@ static void do_format_dasd(dasdfmt_info_ + case QUICK: + dasdfmt_quick_format(info, cylinders, heads, p); + break; ++ case EXPAND: ++ dasdfmt_expand_format(info, cylinders, heads, p); + } + + if (!info->yast_mode) + printf("Finished formatting the device.\n"); + +- if (!info->writenolabel) ++ if (!(info->writenolabel || mode == EXPAND)) + dasdfmt_write_labels(info, vlabel, cylinders, heads); + + if (!info->yast_mode) +@@ -1526,6 +1626,8 @@ int main(int argc, char *argv[]) + mode = FULL; + else if (strcasecmp(optarg, "quick") == 0) + mode = QUICK; ++ else if (strcasecmp(optarg, "expand") == 0) ++ mode = EXPAND; + else + ERRMSG_EXIT(EXIT_FAILURE, + "%s: The specified mode '%s' is " +--- a/dasdfmt/dasdfmt.h ++++ b/dasdfmt/dasdfmt.h +@@ -150,8 +150,13 @@ struct dasd_eckd_characteristics { + typedef enum format_mode_t { + FULL, /* default mode */ + QUICK, /* format only the first 2 tracks */ ++ EXPAND, /* search for unformatted area and format only that part*/ + } format_mode_t; + ++static const char mode_str[3][10] = { ++ "Full", "Quick", "Expand" ++}; ++ + /* + * struct format_data_t + * represents all data necessary to format a dasd diff --git a/s390-tools-sles12sp3-dbginfo-01-libutil-Add-utility-functions.patch b/s390-tools-sles12sp3-dbginfo-01-libutil-Add-utility-functions.patch new file mode 100644 index 0000000..5fed129 --- /dev/null +++ b/s390-tools-sles12sp3-dbginfo-01-libutil-Add-utility-functions.patch @@ -0,0 +1,1053 @@ +Subject: [PATCH] [FEAT RTL1601] libutil: Add utility functions +From: Peter Oberparleiter + +Summary: libutil: Add utility functions +Description: Introduce utility functions for use by s390-tools. +Upstream-ID: - +Problem-ID: RTL1601 + +Signed-off-by: Peter Oberparleiter +--- + include/util_base.h | 2 + include/util_libc.h | 125 +++++++++++++++++++ + include/util_opt.h | 82 ++++++++++++ + include/util_panic.h | 45 ++++++ + include/util_prg.h | 55 ++++++++ + libutil/Makefile | 11 + + libutil/util_libc.c | 155 +++++++++++++++++++++++ + libutil/util_opt.c | 281 +++++++++++++++++++++++++++++++++++++++++++ + libutil/util_panic.c | 119 ++++++++++++++++++ + libutil/util_prg.c | 111 ++++++++++++++++ + 10 files changed, 985 insertions(+), 1 deletion(-) + +--- a/include/util_base.h ++++ b/include/util_base.h +@@ -15,4 +15,6 @@ void util_hexdump(FILE *fh, const char * + void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group, + int cnt, int indent); + ++#define UTIL_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) ++ + #endif /* UTIL_BASE_H */ +--- /dev/null ++++ b/include/util_libc.h +@@ -0,0 +1,125 @@ ++/** ++ * @defgroup util_libc_h util_libc: Libc wrapper interface ++ * @{ ++ * @brief Handle standard errors for libc functions ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef UTIL_LIBC_H ++#define UTIL_LIBC_H ++ ++#include ++ ++/** ++ * Allocate memory or panic in case of failure ++ * ++ * @param[in] size Number of bytes to be allocated ++ * ++ * @returns Pointer to allocated memory buffer ++ */ ++#define util_malloc(size) \ ++ __util_malloc(__func__, __FILE__, __LINE__, size) ++ ++void *__util_malloc(const char *func, const char *file, int line, size_t size); ++ ++/** ++ * Allocate zero-initialized memory or panic in case of failure ++ * ++ * @param[in] size Number of bytes to be allocated ++ * ++ * @returns Pointer to allocated memory buffer initialized with zeroes ++ */ ++#define util_zalloc(size) \ ++ __util_zalloc(__func__, __FILE__, __LINE__, size) ++ ++void *__util_zalloc(const char *func, const char *file, int line, size_t size); ++ ++ ++/** ++ * Re-allocate memory or exit in case of failure ++ * ++ * @param[in] ptr Pointer ot old memory buffer ++ * @param[in] size Number of bytes to be allocated ++ * ++ * @returns Pointer to allocated memory buffer ++ */ ++#define util_realloc(ptr, size) \ ++ __util_realloc(__func__, __FILE__, __LINE__, ptr, size) ++ ++void *__util_realloc(const char *func, const char *file, int line, ++ void *ptr, size_t size); ++ ++/** ++ * Duplicate a string buffer or exit in case of failure ++ * ++ * @param[in] str String to be duplicated ++ * ++ * @returns Pointer to newly allocated and copied string ++ */ ++#define util_strdup(str) \ ++ __util_strdup(__func__, __FILE__, __LINE__, str) ++ ++void *__util_strdup(const char *func, const char *file, int line, ++ const char *str); ++ ++/** ++ * Print to allocated string or exit in case of failure ++ * ++ * @param[in] strp String to be allocated ++ * @param[in] fmt Format string for generation of string ++ * @param[in] ap Parameters for format string ++ * ++ * @returns num Number of formatted characters ++ */ ++#define util_vasprintf(strp, fmt, ap) \ ++ __util_vasprintf(__func__, __FILE__, __LINE__, strp, fmt, ap) ++ ++#define UTIL_VASPRINTF(strp, fmt, ap) \ ++do { \ ++ va_start(ap, fmt); \ ++ util_vasprintf(strp, fmt, ap); \ ++ va_end(ap); \ ++} while (0) ++ ++int __util_vasprintf(const char *func, const char *file, int line, ++ char **strp, const char *fmt, va_list ap); ++ ++/** ++ * Print to newly allocated string or exit in case of failure ++ * ++ * @param[in] strp String to be allocated ++ * @param[in] ... Format string and parameters for format string ++ * ++ * @returns num Number of formatted characters ++ */ ++#define util_asprintf(strp, ...) \ ++ __util_asprintf(__func__, __FILE__, __LINE__, strp, ##__VA_ARGS__) ++ ++int __util_asprintf(const char *func, const char *file, int line, ++ char **strp, const char *fmt, ...); ++ ++ ++/** ++ * Print to string buffer or exit in case of failure ++ * ++ * @param[in] str String buffer ++ * @param[in] fmt Format string for generation of string ++ * @param[in] ap Parameters for format string ++ * ++ * @returns num Number of formatted characters ++ */ ++#define util_vsprintf(str, fmt, ap) \ ++ __util_vsprintf(__func__, __FILE__, __LINE__, str, fmt, ap) ++ ++#define UTIL_VSPRINTF(str, fmt, ap) \ ++do { \ ++ va_start(ap, fmt); \ ++ util_vsprintf(str, fmt, ap); \ ++ va_end(ap); \ ++} while (0) ++ ++int __util_vsprintf(const char *func, const char *file, int line, ++ char *str, const char *fmt, va_list ap); ++ ++#endif /** UTIL_LIBC_H @} */ +--- /dev/null ++++ b/include/util_opt.h +@@ -0,0 +1,82 @@ ++/** ++ * @defgroup util_opt_h util_opt: Command line options interface ++ * @{ ++ * @brief Parse the command line options ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef UTIL_OPT_H ++#define UTIL_OPT_H ++ ++#include ++#include ++ ++/* Flag indicating that an option does not have a short form */ ++#define UTIL_OPT_FLAG_NOSHORT 1 ++ ++/* Flag indicating that an option does not have a long form */ ++#define UTIL_OPT_FLAG_NOLONG 2 ++ ++/* Flag indicating that this is a section heading */ ++#define UTIL_OPT_FLAG_SECTION 4 ++ ++/** ++ * Command line option ++ */ ++struct util_opt { ++ /** Defined by getopt.h, see "man getopt_long" */ ++ struct option option; ++ /** For options with arguments: Argument name */ ++ char *argument; ++ /** Description displayed for --help */ ++ char *desc; ++ /** Flags for this option */ ++ int flags; ++}; ++ ++/** ++ * Standard option: --help ++ */ ++#define UTIL_OPT_HELP \ ++{ \ ++ .option = { "help", 0, NULL, 'h' }, \ ++ .desc = "Print this help, then exit", \ ++} ++ ++/** ++ * Standard option: --version ++ */ ++#define UTIL_OPT_VERSION \ ++{ \ ++ .option = { "version", 0, NULL, 'v' }, \ ++ .desc = "Print version information, then exit", \ ++} ++ ++/** ++ * End-marker for the option pointer vector ++ */ ++#define UTIL_OPT_END \ ++{ \ ++ .option = { NULL, 0, NULL, 0 }, \ ++} ++ ++/** ++ * Section header ++ */ ++#define UTIL_OPT_SECTION(title) \ ++{ \ ++ .desc = (title), \ ++ .flags = UTIL_OPT_FLAG_SECTION, \ ++} ++ ++/* ++ * Option functions ++ */ ++void util_opt_init(struct util_opt *opt_vec, const char *opt_prefix); ++int util_opt_getopt_long(int argc, char *argv[]); ++void util_opt_print_help(void); ++void util_opt_print_indented(const char *opt, const char *desc); ++void util_opt_print_parse_error(char opt, char *argv[]); ++ ++#endif /** UTIL_OPT_H @} */ +--- /dev/null ++++ b/include/util_panic.h +@@ -0,0 +1,45 @@ ++/** ++ * @defgroup util_panic_h util_panic: Panic interface ++ * @{ ++ * @brief Collect FFDC data for unexpected errors ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef UTIL_PANIC_H ++#define UTIL_PANIC_H ++ ++#include "zt_common.h" ++ ++#ifndef __noreturn ++#define __noreturn ++#endif ++ ++/** ++ * Write message, print backtrace and then call the abort() function ++ * ++ * @param[in] ... Format string and parameters describing the panic reason ++ */ ++#define util_panic(...) \ ++ __util_panic(__func__, __FILE__, __LINE__, ##__VA_ARGS__) ++ ++void __util_panic(const char *func, const char *file, int line, ++ const char *fmt, ...) __noreturn; ++ ++/** ++ * Ensure that assumption is not true, otherwise panic ++ * ++ * Example: util_assert(ptr == NULL, "The ptr must be NULL, but is %p", ptr) ++ * ++ * @param[in] assumption This assumption has to be true ++ * @param[in] ... Format string and parameters describing the assumption ++ */ ++#define util_assert(assumption, ...) \ ++ __util_assert(#assumption, __func__, __FILE__, __LINE__, \ ++ assumption, ##__VA_ARGS__) ++ ++void __util_assert(const char *assertion_string, ++ const char *func, const char *file, int line, ++ int assumption, const char *fmt, ...); ++ ++#endif /** UTIL_PANIC_H @} */ +--- /dev/null ++++ b/include/util_prg.h +@@ -0,0 +1,55 @@ ++/** ++ * @defgroup util_prg_h util_prg: Program interface ++ * @{ ++ * @brief Print standard program messages ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef UTIL_PRG_H ++#define UTIL_PRG_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * Copyright description ++ */ ++struct util_prg_copyright { ++ /** Name of the copyright owner, e.g. IBM */ ++ const char *owner; ++ /** Year of first publishing */ ++ int pub_first; ++ /** Year of last major changes */ ++ int pub_last; ++}; ++ ++/** ++ * @brief Coypright end marker ++ */ ++#define UTIL_PRG_COPYRIGHT_END {NULL, 0, 0} ++ ++/** ++ * Program description ++ */ ++struct util_prg { ++ /** Description for help */ ++ const char *desc; ++ /** Positional arguments */ ++ const char *args; ++ /** Copyright list */ ++ struct util_prg_copyright copyright_vec[]; ++}; ++ ++void util_prg_init(const struct util_prg *prg); ++void util_prg_print_parse_error(void); ++void util_prg_print_required_arg(const char *option); ++void util_prg_print_invalid_option(const char *option); ++void util_prg_print_arg_error(const char *arg_name); ++void util_prg_print_version(void); ++void util_prg_print_help(void); ++ ++#endif /** UTIL_PRG_H @} */ +--- a/libutil/Makefile ++++ b/libutil/Makefile +@@ -2,12 +2,21 @@ include ../common.mak + + CPPFLAGS += -I../include + +-all: util_base.o util_list.o util_part.o util_proc.o ++all: util_base.o util_list.o util_part.o util_proc.o util_libc.o util_opt.o \ ++ util_panic.o util_prg.o + + util_list.o: util_list.c ../include/util.h + + util_proc.o: util_proc.c ../include/util_proc.h + ++util_libc.o: util_libc.c ../include/util_libc.h ++ ++util_opt.o: util_opt.c ../include/util_opt.h ++ ++util_panic.o: util_panic.c ../include/util_panic.h ++ ++util_prg.o: util_prg.c ../include/util_prg.h ++ + install: all + + clean: +--- /dev/null ++++ b/libutil/util_libc.c +@@ -0,0 +1,155 @@ ++/* ++ * util - Utility function library ++ * ++ * Handle standard errors for libc functions ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#define _GNU_SOURCE /* for program_invocation_short_name */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "util_base.h" ++#include "util_panic.h" ++#include "util_libc.h" ++ ++/* ++ * Return size as string of largest unit, e.g. 1025 = "1 KiB" ++ */ ++static void format_size(char *str, size_t size) ++{ ++ static const char * const unit_vec[] = ++ {"byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; ++ unsigned int i; ++ ++ for (i = 0; i < UTIL_ARRAY_SIZE(unit_vec); i++) { ++ if (size / 1024 == 0) { ++ sprintf(str, "%zu %s", size, unit_vec[i]); ++ return; ++ } ++ size /= 1024; ++ } ++ sprintf(str, "huge"); ++} ++ ++static void __util_oom(const char *func, const char *file, int line, ++ size_t size) ++{ ++ char size_str[256]; ++ ++ fprintf(stderr, "%s: Failed to allocate memory", ++ program_invocation_short_name); ++ if (size > 0) { ++ format_size(size_str, size); ++ fprintf(stderr, " (%s)", size_str); ++ } ++ fprintf(stderr, " at %s:%d %s()\n", file, line, func); ++ exit(EXIT_FAILURE); ++} ++ ++/* ++ * Allocate memory or exit in case of failure ++ */ ++void *__util_malloc(const char *func, const char *file, int line, size_t size) ++{ ++ void *buf; ++ ++ buf = malloc(size); ++ ++ if (buf == NULL) ++ __util_oom(func, file, line, size); ++ ++ return buf; ++} ++ ++/* ++ * Allocate zero-initialized memory or exit in case of failure ++ */ ++void *__util_zalloc(const char *func, const char *file, int line, size_t size) ++{ ++ void *buf = __util_malloc(func, file, line, size); ++ ++ memset(buf, 0, size); ++ ++ return buf; ++} ++ ++/* ++ * Re-allocate memory or exit in case of failure ++ */ ++void *__util_realloc(const char *func, const char *file, int line, ++ void *ptr, size_t size) ++{ ++ void *buf; ++ ++ buf = realloc(ptr, size); ++ ++ if (buf == NULL) ++ __util_oom(func, file, line, size); ++ ++ return buf; ++} ++ ++/* ++ * Duplicate a string buffer or exit in case of failure ++ */ ++void *__util_strdup(const char *func, const char *file, int line, ++ const char *str) ++{ ++ void *buf = strdup(str); ++ ++ if (buf == NULL) ++ __util_oom(func, file, line, strlen(str) + 1); ++ ++ return buf; ++} ++ ++/* ++ * Print to newly allocated string or exit in case of failure ++ */ ++int __util_vasprintf(const char *func, const char *file, int line, ++ char **strp, const char *fmt, va_list ap) ++{ ++ int rc; ++ ++ rc = vasprintf(strp, fmt, ap); ++ if (rc == -1) ++ __util_oom(func, file, line, 0); ++ ++ return rc; ++} ++ ++/* ++ * Print to newly allocated string or exit in case of failure ++ */ ++int __util_asprintf(const char *func, const char *file, int line, ++ char **strp, const char *fmt, ...) ++{ ++ va_list ap; ++ int rc; ++ ++ va_start(ap, fmt); ++ rc = __util_vasprintf(func, file, line, strp, fmt, ap); ++ va_end(ap); ++ return rc; ++} ++ ++/* ++ * Print to string buffer or exit in case of failure ++ */ ++int __util_vsprintf(const char *func, const char *file, int line, ++ char *str, const char *fmt, va_list ap) ++{ ++ int rc; ++ ++ rc = vsprintf(str, fmt, ap); ++ if (rc == -1) ++ __util_assert("rc != -1", func, file, line, ++ rc != -1, "Could not format string\n"); ++ return rc; ++} +--- /dev/null ++++ b/libutil/util_opt.c +@@ -0,0 +1,281 @@ ++/* ++ * util - Utility function library ++ * ++ * Parse the command line options ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "util_base.h" ++#include "util_libc.h" ++#include "util_opt.h" ++#include "util_panic.h" ++#include "util_prg.h" ++ ++/* ++ * Private data ++ */ ++/// @cond ++static struct util_opt_l { ++ /* Option character string for getopt_long() */ ++ char *opt_str; ++ /* Option array for getopt_long() */ ++ struct option *option_vec; ++ /* Original util_opt array */ ++ struct util_opt *opt_vec; ++ /* Length of longest option string */ ++ int opt_max; ++} l; ++ ++struct util_opt_l *util_opt_l = &l; ++/// @endcond ++ ++#define util_opt_iterate(opt) \ ++ for (opt = &l.opt_vec[0]; opt->desc != NULL; opt++) ++ ++#define MAX(x, y) ((x) < (y) ? (y) : (x)) ++#define MAX_OPTLEN 256 ++ ++static int opt_max_len(void); ++ ++/** ++ * Initialize the command line options ++ * ++ * Build short option string and long option array to be used for getopt_long(). ++ * The ":" prefix is added to the short option string for handling of "missing ++ * required arguments". ++ * ++ * @param[in] opt_vec Option array ++ * @param[in] opt_prefix Optional option string prefix ++ */ ++void util_opt_init(struct util_opt *opt_vec, const char *opt_prefix) ++{ ++ int i, j, count; ++ char *str; ++ size_t prefix_len = opt_prefix ? strlen(opt_prefix) : 0; ++ ++ opterr = 0; ++ /* Get number of options */ ++ for (count = 0; opt_vec[count].desc != NULL; count++); ++ /* ++ * Allocate short option string for worst case when all options have ++ * optional parameters e.g "x::" and long option string. ++ */ ++ l.opt_str = util_malloc(sizeof(char) * count * 3 + 2 + prefix_len); ++ l.option_vec = util_malloc(sizeof(struct option) * (count + 1)); ++ l.opt_vec = opt_vec; ++ ++ str = l.opt_str; ++ if (opt_prefix) { ++ strcpy(str, opt_prefix); ++ str += prefix_len; ++ } ++ /* Force getopt_long() to return ':' for missing required arguments */ ++ *str++ = ':'; ++ /* Construction of input structures for getopt_long() function. */ ++ for (i = 0, j = 0; i < count; i++) { ++ if (opt_vec[i].flags & UTIL_OPT_FLAG_SECTION) ++ continue; ++ memcpy(&l.option_vec[j++], &opt_vec[i].option, ++ sizeof(struct option)); ++ if (opt_vec[i].flags & UTIL_OPT_FLAG_NOSHORT) ++ continue; ++ *str++ = opt_vec[i].option.val; ++ switch (opt_vec[i].option.has_arg) { ++ case no_argument: ++ break; ++ case required_argument: ++ *str++ = ':'; ++ break; ++ case optional_argument: ++ *str++ = ':'; ++ *str++ = ':'; ++ break; ++ default: ++ util_panic("Unexpected \"has_arg\" parameter: %d\n", ++ opt_vec[i].option.has_arg); ++ } ++ } ++ /* Add end marker to option array and short option string */ ++ memset(&l.option_vec[j], 0, sizeof(struct option)); ++ *str = '\0'; ++ ++ l.opt_max = opt_max_len(); ++} ++ ++/** ++ * Wrapper for getopt_long ++ * ++ * @param[in] argc Count of command line parameters ++ * @param[in] argv Array of command line parameters ++ */ ++int util_opt_getopt_long(int argc, char *argv[]) ++{ ++ return getopt_long(argc, argv, l.opt_str, l.option_vec, NULL); ++} ++ ++/* ++ * Format option name: Add short, long option and argument (as applicable) ++ */ ++static void format_opt(char *buf, size_t maxlen, const struct util_opt *opt) ++{ ++ int has_arg, flags, rc; ++ char val, *arg_str; ++ const char *name; ++ ++ has_arg = opt->option.has_arg; ++ name = opt->option.name; ++ val = opt->option.val; ++ flags = opt->flags; ++ ++ /* Prepare potential option argument string */ ++ if (has_arg == optional_argument) { ++ if (flags & UTIL_OPT_FLAG_NOLONG) ++ util_asprintf(&arg_str, "[%s]", opt->argument); ++ else ++ util_asprintf(&arg_str, "[=%s]", opt->argument); ++ } else if (has_arg == required_argument) { ++ util_asprintf(&arg_str, " %s", opt->argument); ++ } else { ++ util_asprintf(&arg_str, ""); ++ } ++ ++ /* Format the option */ ++ if (flags & UTIL_OPT_FLAG_NOLONG) ++ rc = snprintf(buf, maxlen, "-%c%s", val, arg_str); ++ else if (flags & UTIL_OPT_FLAG_NOSHORT) ++ rc = snprintf(buf, maxlen, " --%s%s", name, arg_str); ++ else ++ rc = snprintf(buf, maxlen, "-%c, --%s%s", val, name, arg_str); ++ ++ util_assert(rc < (int)maxlen, "Option too long: %s\n", name); ++ free(arg_str); ++} ++ ++/* ++ * Return size of the longest formatted option ++ */ ++static int opt_max_len(void) ++{ ++ const struct util_opt *opt; ++ unsigned int max = 0; ++ char opt_str[MAX_OPTLEN]; ++ ++ util_opt_iterate(opt) { ++ if (opt->flags & UTIL_OPT_FLAG_SECTION) ++ continue; ++ format_opt(opt_str, MAX_OPTLEN, opt); ++ max = MAX(max, strlen(opt_str)); ++ } ++ return max; ++} ++ ++/* ++ * Print option description with indentation ++ */ ++static void print_opt_description(const char *desc_in, int indent) ++{ ++ char *word, *line, *desc, *desc_ptr; ++ int word_len, pos = indent; ++ ++ desc = desc_ptr = util_strdup(desc_in); ++ line = strsep(&desc, "\n"); ++ while (line) { ++ word = strsep(&line, " "); ++ pos = indent; ++ while (word) { ++ word_len = strlen(word); ++ if (pos + word_len + 1 > 80) { ++ printf("\n%*s", indent, " "); ++ pos = indent; ++ } ++ printf(" %s", word); ++ pos += word_len + 1; ++ word = strsep(&line, " "); ++ } ++ if (desc) ++ printf("\n%*s", indent, " "); ++ line = strsep(&desc, "\n"); ++ } ++ printf("\n"); ++ free(desc_ptr); ++} ++ ++/** ++ * Print an option name, followed by a description indented to fit the ++ * longest option name ++ */ ++void util_opt_print_indented(const char *opt, const char *desc) ++{ ++ printf(" %-*s ", l.opt_max, opt); ++ print_opt_description(desc, 2 + l.opt_max); ++} ++ ++/** ++ * Print the usage of the command line options to the console ++ */ ++void util_opt_print_help(void) ++{ ++ char opt_str[MAX_OPTLEN]; ++ struct util_opt *opt; ++ int first = 1; ++ ++ /* ++ * Create format string: " -%c, --%-s %s" ++ * ++ * Example: ++ * ++ * -p, --print STRING Print STRING to console ++ */ ++ util_opt_iterate(opt) { ++ if (opt->flags & UTIL_OPT_FLAG_SECTION) { ++ printf("%s%s\n", first ? "" : "\n", opt->desc); ++ first = 0; ++ continue; ++ } ++ format_opt(opt_str, MAX_OPTLEN, opt); ++ util_opt_print_indented(opt_str, opt->desc); ++ } ++} ++ ++/** ++ * Print option parsing error message ++ * ++ * This function should be used when the return code of the ++ * util_opt_getopt_long() function returns a character that does ++ * not match any of the expected options. ++ * ++ * @param[in] opt Short option returned by getopt_long() ++ * @param[in] argv Option array ++ */ ++void util_opt_print_parse_error(char opt, char *argv[]) ++{ ++ char optopt_str[3]; ++ ++ switch (opt) { ++ case ':': ++ /* A required option argument has not been specified */ ++ util_prg_print_required_arg(argv[optind - 1]); ++ break; ++ case '?': ++ /* An invalid option has been specified */ ++ if (optopt) { ++ /* Short option */ ++ sprintf(optopt_str, "-%c", optopt); ++ util_prg_print_invalid_option(optopt_str); ++ } else { ++ /* Long option */ ++ util_prg_print_invalid_option(argv[optind - 1]); ++ } ++ break; ++ default: ++ util_panic("Option '%c' should not be handled here\n", opt); ++ } ++} ++ +--- /dev/null ++++ b/libutil/util_panic.c +@@ -0,0 +1,119 @@ ++/* ++ * util - Utility function library ++ * ++ * Collect FFDC data for unexpected errors ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "util_base.h" ++#include "util_panic.h" ++ ++/* ++ * Obtain a backtrace and print it to stderr ++ * ++ * To get symbols, compile the code with "-rdynamic". ++ */ ++static void print_backtrace(void) ++{ ++ void *array[256]; ++ size_t i, size; ++ char **strings; ++ ++ fprintf(stderr, "Backtrace:\n\n"); ++ size = backtrace(array, UTIL_ARRAY_SIZE(array)); ++ strings = backtrace_symbols(array, size); ++ if (strings == NULL) { ++ fprintf(stderr, " Could not obtain backtrace (ENOMEM)\n"); ++ return; ++ } ++ for (i = 0; i < size; i++) ++ fprintf(stderr, " %s\n", strings[i]); ++ ++ free(strings); ++} ++ ++/* ++ * Check for core ulimit ++ */ ++static void ulimit_core_check(void) ++{ ++ struct rlimit limit; ++ ++ if (getrlimit(RLIMIT_CORE, &limit) != 0) ++ return; ++ if (limit.rlim_cur != 0) ++ return; ++ fprintf(stderr, "Core dump size is zero. To get a full core dump use 'ulimit -c unlimited'.\n"); ++} ++ ++/* ++ * Print FFDC data and then abort ++ */ ++static void panic_finish(const char *func, const char *file, int line, ++ const char *fmt, va_list ap) ++{ ++ /* Write panic error string */ ++ fprintf(stderr, "\n"); ++ fprintf(stderr, "Error string:\n"); ++ fprintf(stderr, "\n"); ++ fprintf(stderr, " "); ++ vfprintf(stderr, fmt, ap); ++ fprintf(stderr, "\n"); ++ /* Write file, line number, and function name */ ++ fprintf(stderr, "Location:\n\n"); ++ fprintf(stderr, " %s:%d: %s()\n", file, line, func); ++ fprintf(stderr, "\n"); ++ ++ /* Print the function backtrace */ ++ print_backtrace(); ++ fprintf(stderr, "\n"); ++ ++ ulimit_core_check(); ++ fprintf(stderr, "----------------------------------------------------------------------->8-----\n"); ++ abort(); ++} ++ ++/* ++ * Do panic processing if the assumption is not true ++ */ ++void __util_assert(const char *assertion_str, ++ const char *func, const char *file, int line, ++ int assumption, const char *fmt, ...) ++{ ++ va_list ap; ++ ++ if (assumption) ++ return; ++ va_start(ap, fmt); ++ fprintf(stderr, "---8<-------------------------------------------------------------------------\n"); ++ fprintf(stderr, "ASSERTION FAILED: The application terminated due to an internal or OS error\n"); ++ fprintf(stderr, "\n"); ++ fprintf(stderr, "The following assumption was *not* true:\n"); ++ fprintf(stderr, "\n"); ++ fprintf(stderr, " %s\n", assertion_str); ++ panic_finish(func, file, line, fmt, ap); ++} ++ ++/* ++ * Do panic processing ++ */ ++void __util_panic(const char *func, const char *file, int line, ++ const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ fprintf(stderr, "---8<-------------------------------------------------------------------------\n"); ++ fprintf(stderr, "PANIC: The application terminated due to an unrecoverable error\n"); ++ panic_finish(func, file, line, fmt, ap); ++ while(1); ++} +--- /dev/null ++++ b/libutil/util_prg.c +@@ -0,0 +1,111 @@ ++/* ++ * util - Utility function library ++ * ++ * Print standard program messages ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#define _GNU_SOURCE /* for program_invocation_short_name */ ++ ++#include ++#include ++ ++#include "util_prg.h" ++#include "zt_common.h" ++ ++/* ++ * Private data ++ */ ++static struct util_prg_l { ++ const struct util_prg *prg; ++} l; ++ ++struct util_prg_l *util_prg_l = &l; ++ ++/** ++ * Print program usage information for the --help option ++ */ ++void util_prg_print_help(void) ++{ ++ printf("Usage: %s [OPTIONS]", program_invocation_short_name); ++ if (l.prg->args) ++ printf(" %s", l.prg->args); ++ printf("\n\n%s\n\n", l.prg->desc); ++} ++ ++/** ++ * Print program version information for the --version option ++ */ ++void util_prg_print_version(void) ++{ ++ const struct util_prg_copyright *copyright; ++ ++ printf("%s version %s\n", program_invocation_short_name, ++ RELEASE_STRING); ++ copyright = l.prg->copyright_vec; ++ while (copyright->owner) { ++ if (copyright->pub_first == copyright->pub_last) ++ printf("Copyright %s %d\n", copyright->owner, ++ copyright->pub_first); ++ else ++ printf("Copyright %s %d, %d\n", copyright->owner, ++ copyright->pub_first, copyright->pub_last); ++ copyright++; ++ } ++} ++ ++/* ++ * Ask user to use the --help option ++ */ ++void util_prg_print_parse_error(void) ++{ ++ fprintf(stderr, "Try '%s --help' for more information.\n", ++ program_invocation_short_name); ++} ++ ++/** ++ * An option has been specified that is not supported ++ * ++ * @param[in] option Option string (short or long) ++ */ ++void util_prg_print_invalid_option(const char *opt_name) ++{ ++ fprintf(stderr, "%s: Invalid option '%s'\n", ++ program_invocation_short_name, opt_name); ++ util_prg_print_parse_error(); ++} ++ ++/** ++ * A required argument for an option is missing ++ * ++ * @param[in] option Option string ++ */ ++void util_prg_print_required_arg(const char *opt_name) ++{ ++ fprintf(stderr, "%s: Option '%s' requires an argument\n", ++ program_invocation_short_name, opt_name); ++ util_prg_print_parse_error(); ++} ++ ++/** ++ * A superfluous invalid positional argument has been specified ++ * ++ * @param[in] arg_name Name of the invalid argument ++ */ ++void util_prg_print_arg_error(const char *arg_name) ++{ ++ fprintf(stderr, "%s: Invalid argument '%s'\n", ++ program_invocation_short_name, arg_name); ++ util_prg_print_parse_error(); ++} ++ ++/** ++ * Initialize the program module ++ * ++ * @param[in] prg Program description ++ */ ++void util_prg_init(const struct util_prg *prg) ++{ ++ l.prg = prg; ++} diff --git a/s390-tools-sles12sp3-dbginfo-02-dump2tar-Add-sysfs-collection-helper-for-dbginfo.sh-v2.patch b/s390-tools-sles12sp3-dbginfo-02-dump2tar-Add-sysfs-collection-helper-for-dbginfo.sh-v2.patch new file mode 100644 index 0000000..e0c486d --- /dev/null +++ b/s390-tools-sles12sp3-dbginfo-02-dump2tar-Add-sysfs-collection-helper-for-dbginfo.sh-v2.patch @@ -0,0 +1,4687 @@ +Subject: [PATCH] [FEAT RTL1601] dump2tar: Add sysfs collection helper for dbginfo.sh +From: Peter Oberparleiter + +Summary: dump2tar: Add sysfs collection helper for dbginfo.sh +Description: Certain files in virtual filesystems such as sysfs, + debugfs and procfs do not correctly report their size. + As a result, tools like tar, cp or rsync cannot be easily + used to collect these files. + + This patch adds a tool to efficiently dump such files + into a compressed tar archive. It is intended to be used + by the dbginfo.sh script to significantly speed up data + collection. +Upstream-ID: - +Problem-ID: RTL1601 + +Changelog: + + - v2: Fix compiler warning and missing DESTDIR logic in Makefiles + +Signed-off-by: Peter Oberparleiter +--- + Makefile | 2 + README | 5 + dump2tar/Makefile | 12 + dump2tar/include/buffer.h | 47 + + dump2tar/include/dref.h | 26 + dump2tar/include/dump.h | 60 + + dump2tar/include/global.h | 20 + dump2tar/include/idcache.h | 23 + dump2tar/include/misc.h | 98 ++ + dump2tar/include/strarray.h | 23 + dump2tar/include/tar.h | 41 + dump2tar/man/Makefile | 12 + dump2tar/man/dump2tar.1 | 454 ++++++++++ + dump2tar/src/Makefile | 36 + dump2tar/src/buffer.c | 271 ++++++ + dump2tar/src/dref.c | 92 ++ + dump2tar/src/dump.c | 1850 ++++++++++++++++++++++++++++++++++++++++++++ + dump2tar/src/dump2tar.c | 474 +++++++++++ + dump2tar/src/global.c | 17 + dump2tar/src/idcache.c | 153 +++ + dump2tar/src/misc.c | 492 +++++++++++ + dump2tar/src/strarray.c | 81 + + dump2tar/src/tar.c | 270 ++++++ + 23 files changed, 4558 insertions(+), 1 deletion(-) + +--- a/Makefile ++++ b/Makefile +@@ -8,7 +8,7 @@ SUB_DIRS = $(LIB_DIRS) zipl zdump fdasd + 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 ++ systemd hmcdrvfs cpacfstats zdev dump2tar + + all: subdirs_make + +--- a/README ++++ b/README +@@ -210,6 +210,11 @@ s390-tools (1.34.0) + configuration of devices and device drivers which are specific to the s390 + platform. + ++ * dump2tar: ++ dump2tar is a tool for creating a tar archive from the contents of ++ arbitrary files. It works even when the size of the actual file content ++ is not known beforehand (e.g. FIFOs, sysfs files). ++ + For more information refer to the following publications: + * "Device Drivers, Features, and Commands" chapter "Useful Linux commands" + * "Using the dump tools" +--- /dev/null ++++ b/dump2tar/Makefile +@@ -0,0 +1,12 @@ ++# Common definitions ++include ../common.mak ++ ++all: ++ $(MAKE) -C src ++ ++install: all ++ $(MAKE) -C src install ++ $(MAKE) -C man install ++ ++clean: ++ $(MAKE) -C src clean +--- /dev/null ++++ b/dump2tar/include/buffer.h +@@ -0,0 +1,47 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Data buffering functions ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef BUFFER_H ++#define BUFFER_H ++ ++#include ++#include ++#include ++ ++/* Buffers for building tar file entries */ ++struct buffer { ++ size_t total; /* Total number of bytes in buffer */ ++ size_t off; /* Current offset to next free byte in memory buffer */ ++ size_t size; /* Memory buffer size */ ++ char *addr; /* Memory buffer address */ ++ bool fd_open; /* Has fd been openend yet? */ ++ FILE *file; /* FILE * of file containing previous buffer data */ ++ int fd; /* Handle of file containing previous buffer data */ ++}; ++ ++void buffer_init(struct buffer *buffer, size_t size); ++struct buffer *buffer_alloc(size_t size); ++void buffer_reset(struct buffer *buffer); ++void buffer_close(struct buffer *buffer); ++void buffer_free(struct buffer *buffer, bool dyn); ++int buffer_open(struct buffer *buffer); ++int buffer_flush(struct buffer *buffer); ++ssize_t buffer_make_room(struct buffer *buffer, size_t size, bool usefile, ++ size_t max_buffer_size); ++int buffer_truncate(struct buffer *buffer, size_t len); ++ ++ssize_t buffer_read_fd(struct buffer *buffer, int fd, size_t chunk, ++ bool usefile, size_t max_buffer_size); ++int buffer_add_data(struct buffer *buffer, char *addr, size_t len, ++ bool usefile, size_t max_buffer_size); ++ ++typedef int (*buffer_cb_t)(void *data, void *addr, size_t len); ++int buffer_iterate(struct buffer *buffer, buffer_cb_t cb, void *data); ++void buffer_print(struct buffer *buffer); ++ ++#endif /* BUFFER_H */ +--- /dev/null ++++ b/dump2tar/include/dref.h +@@ -0,0 +1,26 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Reference counting for directory handles ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef DREF_H ++#define DREF_H ++ ++#include ++#include ++ ++/* Multiple jobs may refer to an open DIR * - need reference counting */ ++struct dref { ++ DIR *dd; ++ int dirfd; ++ unsigned int count; ++}; ++ ++struct dref *dref_create(const char *dirname); ++struct dref *dref_get(struct dref *dref); ++void dref_put(struct dref *dref); ++ ++#endif /* DREF_H */ +--- /dev/null ++++ b/dump2tar/include/dump.h +@@ -0,0 +1,60 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Main dump logic ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef DUMP_H ++#define DUMP_H ++ ++#include ++#include ++#include ++ ++#include "strarray.h" ++ ++#define NUM_EXCLUDE_TYPES 7 ++ ++struct dump_spec { ++ char *inname; ++ char *outname; ++ bool is_cmd; ++}; ++ ++struct dump_opts { ++ bool add_cmd_status; ++ bool append; ++ bool dereference; ++ bool exclude_type[NUM_EXCLUDE_TYPES]; ++ bool gzip; ++ bool ignore_failed_read; ++ bool no_eof; ++ bool quiet; ++ bool recursive; ++ bool threaded; ++ bool verbose; ++ const char *output_file; ++ int file_timeout; ++ int timeout; ++ long jobs; ++ long jobs_per_cpu; ++ size_t file_max_size; ++ size_t max_buffer_size; ++ size_t max_size; ++ size_t read_chunk_size; ++ struct strarray exclude; ++ struct dump_spec *specs; ++ unsigned int num_specs; ++}; ++ ++struct dump_opts *dump_opts_new(void); ++int dump_opts_set_type_excluded(struct dump_opts *opts, char c); ++void dump_opts_add_spec(struct dump_opts *opts, char *inname, char *outname, ++ bool is_cmd); ++void dump_opts_free(struct dump_opts *opts); ++ ++int dump_to_tar(struct dump_opts *opts); ++ ++#endif /* DUMP_H */ +--- /dev/null ++++ b/dump2tar/include/global.h +@@ -0,0 +1,20 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Global variables ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef GLOBAL_H ++#define GLOBAL_H ++ ++#include ++ ++extern bool global_threaded; ++extern bool global_debug; ++extern bool global_verbose; ++extern bool global_quiet; ++extern bool global_timestamps; ++ ++#endif /* GLOBAL_H */ +--- /dev/null ++++ b/dump2tar/include/idcache.h +@@ -0,0 +1,23 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Caches for user and group ID lookups ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef IDCACHE_H ++#define IDCACHE_H ++ ++#include ++#include ++ ++/* Buffer sizes for getpwuid_r and getgid_r calls (bytes) */ ++#define PWD_BUFFER_SIZE 4096 ++#define GRP_BUFFER_SIZE 4096 ++ ++void uid_to_name(uid_t uid, char *name, size_t len); ++void gid_to_name(gid_t gid, char *name, size_t len); ++void idcache_cleanup(void); ++ ++#endif /* IDCACHE_H */ +--- /dev/null ++++ b/dump2tar/include/misc.h +@@ -0,0 +1,98 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Helper functions ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef MISC_H ++#define MISC_H ++ ++#include ++#include ++#include ++#include ++ ++#include "global.h" ++ ++#include "util_libc.h" ++ ++#define MSG_LEN 256 ++ ++#define DBG(...) \ ++ do { \ ++ if (global_debug) \ ++ debug(__FILE__, __LINE__, ##__VA_ARGS__); \ ++ } while (0) ++ ++#define mwarn(fmt, ...) _mwarn(true, (fmt), ##__VA_ARGS__) ++#define mwarnx(fmt, ...) _mwarn(false, (fmt), ##__VA_ARGS__) ++ ++/* Helper macro for constructing messages in variables */ ++#define HANDLE_RC(rc, max, off, label) \ ++ do { \ ++ if ((rc) > 0) \ ++ (off) += (rc); \ ++ if ((off) > (max)) \ ++ goto label; \ ++ } while (0) ++ ++/* Program exit codes */ ++#define EXIT_OK 0 ++#define EXIT_RUNTIME 1 ++#define EXIT_USAGE 2 ++ ++/* Number of nanoseconds in a second */ ++#define NSEC_PER_SEC 1000000000L ++#define NSEC_PER_MSEC 1000000L ++#define NSEC_PER_USEC 1000L ++ ++extern struct timespec main_start_ts; ++struct dref; ++ ++int misc_write_data(int fd, char *addr, size_t len); ++ssize_t misc_read_data(int fd, char *addr, size_t len); ++void inc_timespec(struct timespec *ts, time_t sec, long nsec); ++void set_timespec(struct timespec *ts, time_t sec, long nsec); ++bool ts_before(struct timespec *a, struct timespec *b); ++int snprintf_duration(char *buff, size_t len, struct timespec *start, ++ struct timespec *end); ++char *get_threadname(void); ++void debug(const char *file, unsigned long line, const char *format, ...); ++void _mwarn(bool print_errno, const char *format, ...); ++void verb(const char *format, ...); ++void info(const char *format, ...); ++#define mmalloc(len) util_zalloc(len) ++#define mcalloc(n, len) util_zalloc((n) * (len)) ++#define mrealloc(ptr, len) util_realloc((ptr), (len)) ++#define mstrdup(str) util_strdup(str) ++#define masprintf(fmt, ...) __masprintf(__func__, __FILE__, __LINE__, \ ++ (fmt), ##__VA_ARGS__) ++char *__masprintf(const char *func, const char *file, int line, ++ const char *fmt, ...); ++#define set_threadname(fmt, ...) __set_threadname(__func__, __FILE__, \ ++ __LINE__, (fmt), \ ++ ##__VA_ARGS__) ++void __set_threadname(const char *func, const char *file, int line, ++ const char *fmt, ...); ++ ++void clear_threadname(void); ++void chomp(char *str, char *c); ++void lchomp(char *str, char *c); ++void remove_double_slashes(char *str); ++int stat_file(bool dereference, const char *abs, const char *rel, ++ struct dref *dref, struct stat *st); ++void set_dummy_stat(struct stat *st); ++bool starts_with(const char *str, const char *prefix); ++bool ends_with(const char *str, const char *suffix); ++ ++int cmd_child(int fd, char *cmd); ++int cmd_open(char *cmd, pid_t *pid_ptr); ++int cmd_close(int fd, pid_t pid, int *status_ptr); ++ ++void misc_init(void); ++void misc_cleanup(void); ++void set_stdout_data(void); ++ ++#endif /* MISC_H */ +--- /dev/null ++++ b/dump2tar/include/strarray.h +@@ -0,0 +1,23 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Dynamically growing string arrays ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef STRARRAY_H ++#define STRARRAY_H ++ ++/* A string array that can grow in size */ ++struct strarray { ++ unsigned int num; ++ char **str; ++}; ++ ++void free_strarray(struct strarray *array); ++void add_str_to_strarray(struct strarray *array, const char *str); ++void add_vstr_to_strarray(struct strarray *array, const char *fmt, ...); ++int add_file_to_strarray(struct strarray *array, const char *filename); ++ ++#endif /* STRARRAY_H */ +--- /dev/null ++++ b/dump2tar/include/tar.h +@@ -0,0 +1,41 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * TAR file generation ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#ifndef TAR_H ++#define TAR_H ++ ++#include ++#include ++#include ++ ++#define TYPE_REGULAR '0' ++#define TYPE_LINK '2' ++#define TYPE_DIR '5' ++ ++#define TAR_BLOCKSIZE 512 ++ ++struct buffer; ++ ++/* emit_cb_t - Callback used for emitting chunks of a byte stream ++ * @data: Arbitrary pointer passed via the @data parameter of the ++ * tar_emit_file_* functions ++ * @addr: Pointer to data ++ * @len: Size of data ++ * Return %0 on success. Returning non-zero will indicate failure and abort ++ * further data emission. */ ++typedef int (*emit_cb_t)(void *data, void *addr, size_t len); ++ ++int tar_emit_file_from_buffer(char *filename, char *link, size_t len, ++ struct stat *stat, char type, ++ struct buffer *content, emit_cb_t emit_cb, ++ void *data); ++int tar_emit_file_from_data(char *filename, char *link, size_t len, ++ struct stat *stat, char type, void *addr, ++ emit_cb_t emit_cb, void *data); ++ ++#endif /* TAR_H */ +--- /dev/null ++++ b/dump2tar/man/Makefile +@@ -0,0 +1,12 @@ ++# Common definitions ++include ../../common.mak ++ ++all: ++ ++install: ++ $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 ++ $(INSTALL) -m 644 -c dump2tar.1 $(DESTDIR)$(MANDIR)/man1 ++ ++clean: ++ ++.PHONY: all clean +--- /dev/null ++++ b/dump2tar/man/dump2tar.1 +@@ -0,0 +1,454 @@ ++.\" Macro for inserting an option description prologue. ++.\" .OD [] [args] ++.de OD ++. ds args " ++. if !'\\$3'' .as args \fI\\$3\fP ++. if !'\\$4'' .as args \\$4 ++. if !'\\$5'' .as args \fI\\$5\fP ++. if !'\\$6'' .as args \\$6 ++. if !'\\$7'' .as args \fI\\$7\fP ++. PD 0 ++. if !'\\$2'' .IP "\fB\-\\$2\fP \\*[args]" 4 ++. if !'\\$1'' .IP "\fB\-\-\\$1\fP \\*[args]" 4 ++. PD ++.. ++.\" Macro for inserting code line. ++.\" .CL ++.de CL ++. ds pfont \\n[.f] ++. nh ++. na ++. ft CW ++\\$* ++. ft \\*[pfont] ++. ad ++. hy ++. br ++.. ++.\" Macro for inserting a man page reference. ++.\" .MP man-page section [suffix] ++.de MP ++. nh ++. na ++. BR \\$1 (\\$2)\\$3 ++. ad ++. hy ++.. ++. ++.TH "dump2tar" "1" "2016\-09\-02" "" "" ++. ++.SH "NAME" ++dump2tar - Gather file contents and command output into a tar archive ++. ++. ++.SH "SYNOPSIS" ++.B "dump2tar " ++.RI "[" "OPTIONS" "] " "SPECS" ++. ++. ++.SH "DESCRIPTION" ++.B dump2tar ++creates a tar archive from the contents of any files, including files of ++unknown size. ++ ++Examples for files of unknown size are: ++.IP \(bu 3 ++Named pipes (FIFOs) ++.PP ++.IP \(bu 3 ++Particular Linux kernel debugfs or sysfs files ++.PP ++.IP \(bu 3 ++Character or block devices ++.PP ++ ++When adding such a file, ++.B dump2tar ++first reads all available data until an end-of-file indication is found. From ++this data, it then creates a regular file entry in the resulting tar archive. ++By default, symbolic links and directories are preserved in the archive in ++their original form. ++ ++.B dump2tar ++can also: ++.IP \(bu 3 ++Add files under a different name ++.PP ++.IP \(bu 3 ++Run arbitrary commands and add the resulting command output as a ++regular file ++.PP ++. ++. ++.SH "FILE SPECIFICATIONS" ++. ++This section describes the format of the ++.I SPECS ++argument mentioned in the command synopsis. ++Use the following command line syntax to identify data sources and ++to specify file names within the archive: ++.PP ++ ++.TP ++.I "PATH" ++Adds the contents of the file system subtree at file system location ++.I PATH ++(with possible exceptions described by options) in the archive under the same ++file name as on the file system. ++.PP ++. ++. ++.TP ++.IR "FILENAME" ":=" "PATH" ++Adds the contents of the file at file system location ++.I PATH ++in the archive under the name specified by ++.IR FILENAME . ++.PP ++. ++. ++.TP ++.IR "FILENAME" "|=" "CMDLINE" ++Runs the command ++.IR CMDLINE ++and captures both the resulting standard output and standard error streams. ++Adds the collected output as a regular file named ++.I FILENAME ++in the resulting archive. You can also include the resulting program exit code ++by using option \-\-add\-cmd\-status. ++.PP ++. ++You can also specify "\-\-". All specifications that follow are interpreted as ++simple file names. This is useful for archiving files that contain ":=" or "|=". ++.PP ++. ++. ++.SH "OUTPUT OPTIONS" ++. ++.OD "output\-file" "o" "TARFILE" ++Writes the resulting tar archive to ++.IR TARFILE . ++An existing file at the specified file system location is overwritten. ++ ++If this option is omitted or if "\-" is specified for ++.IR TARFILE , ++the archive is written to the standard output stream. ++.PP ++. ++. ++.OD "gzip" "z" "" ++Compresses the resulting tar archive using gzip. ++.PP ++. ++. ++.OD "max\-size" "m" "VALUE" ++Sets an upper size limit, in bytes, for the resulting archive. If this limit ++is exceeded after adding a file, no further files are added. ++.PP ++. ++. ++.OD "timeout" "t" "VALUE" ++Sets an upper time limit, in seconds, for the archiving process. If this limit ++is exceeded while adding a file, that file is truncated and no ++further files are added. ++.PP ++. ++. ++.OD "no-eof" "" "" ++Does not write an end-of-file marker. ++ ++Use this option if you want to create an archive that can be extended by ++appending additional tar archive data. ++ ++Note: Do not use this option for the final data to be added. ++A valid tar archive requires a trailing end-of-file marker. ++.PP ++. ++. ++.OD "append" "" "" ++Appends data to the end of the archive. ++ ++Use this option to incrementally build a tar file by repeatedly calling ++.BR dump2tar . ++You must specify the \-\-no\-eof option for each but the final call of ++.BR dump2tar . ++.PP ++. ++. ++.OD "add-cmd-status" "" "" ++Adds a separate file named ++.RI \(dq FILENAME .cmdstatus\(dq ++for each command output added through the ++.RI \(dq FILENAME |= CMDLINE \(dq ++notation (see FILE SPECIFICATIONS). ++This file contains information about the exit status of the ++process that executed the command: ++. ++.RS 8 ++.TP ++.RI EXITSTATUS= VALUE ++Unless ++.I VALUE ++is -1, the process ended normally with the specified exit value. ++.PP ++. ++.TP ++.RI TERMSIG= VALUE ++Unless ++.I VALUE ++is -1, the process was stopped by a signal of the specified number. ++.PP ++. ++.TP ++.RI WAITPID_ERRNO= VALUE ++Unless ++.I VALUE ++is -1, an attempt to obtain the status of the process failed with the ++specified error. ++.PP ++.RE ++. ++. ++. ++.SH "INPUT OPTIONS" ++. ++.OD "files\-from" "F" "FILENAME" ++Reads input data specifications (see FILE SPECIFICATIONS) from ++.IR FILENAME , ++one specification per line. Each line contains either a file name or a ++.IR FILENAME := PATH ++or ++.IR FILENAME |= CMDLINE ++specification. Empty lines are ignored. ++ ++A line can also consist of only "\-\-". All lines following this specification ++are interpreted as simple file names. This is useful for archiving files that ++contain ":=" or "|=". ++.PP ++. ++. ++.OD "ignore\-failed\-read" "i" "" ++Continues after read errors. ++ ++By default, ++.B dump2tar ++stops processing after encountering errors while reading an input file. ++With this option, ++.B dump2tar ++prints a warning message and adds an empty entry for the erroneous file in ++the archive. ++.PP ++. ++. ++.OD "buffer\-size" "b" "VALUE" ++Reads data from input files in chunks of ++.I VALUE ++bytes. Large values can accelerate the archiving process for large files ++at the cost of increased memory usage. The default value is 1048576. ++.PP ++. ++. ++.OD "file\-timeout" "T" "VALUE" ++Sets an upper time limit, in seconds, for reading an input file. ++ ++.B dump2tar ++stops processing a file when the time limit is exceeded. Archive entries for ++such files are truncated to the amount of data that is collected by the time ++the limit is reached. ++.PP ++. ++. ++.OD "file\-max\-size" "M" "N" ++Sets an upper size limit, in bytes, for an input file. ++ ++.B dump2tar ++stops processing a file when the size limit is exceeded. Archive entries for ++such files are truncated to the specified size. ++.PP ++. ++. ++.OD "jobs" "j" "N" ++By default, ++.B dump2tar ++processes one file at a time. With this option, ++.B dump2tar ++processes ++.I N ++files in parallel. ++ ++Parallel processing can accelerate the archiving process, ++especially if input files are located on slow devices, or when output from ++multiple commands is added to the archive. ++ ++Note: Use ++.B tar ++option \-\-delay\-directory\-restore when extracting files from an archive ++created with \-\-jobs to prevent conflicts with directory permissions and ++modification times. ++.PP ++. ++. ++.OD "jobs\-per\-cpu" "J" "N" ++Processes ++.I N ++files for each online CPU in parallel. ++ ++Parallel processing can accelerate the ++archiving process, especially if input files are located on slow devices, or ++when output from multiple commands is added to the archive. ++ ++Note: Use ++.B tar ++option \-\-delay\-directory\-restore when extracting files from an archive ++created with \-\-jobs\-per\-cpu to prevent conflicts with directory permissions ++and modification times. ++.PP ++. ++. ++.OD "exclude" "x" "PATTERN" ++Does not add files to the archive if their file names match ++.IR PATTERN . ++.I PATTERN ++is an expression that uses the shell wildcards. ++.PP ++. ++. ++.OD "exclude\-from" "X" "FILENAME" ++Does not add files to the archive if their names match at least one of the ++patterns listed in the pattern file with name ++.IR FILENAME . ++In the pattern file, each line specifies an expression that uses the ++shell wildcards. ++.PP ++. ++. ++.OD "exclude\-type" "" "TYPE" ++Does not add files to the archive if they match at least one of the file types ++specified with ++.IR TYPE . ++.I TYPE ++uses one or more of the characters "fdcbpls", where: ++ ++.RS 8 ++.IP f 3 ++regular files ++.PP ++.IP d 3 ++directories ++.PP ++.IP c 3 ++character devices ++.PP ++.IP b 3 ++block devices ++.PP ++.IP p 3 ++named pipes (FIFOs) ++.PP ++.IP l 3 ++symbolic links ++.PP ++.IP s 3 ++sockets ++.PP ++.RE ++. ++.PP ++. ++. ++.OD "dereference" "" "" ++Adds the content of link targets instead of symbolic links. ++.PP ++. ++. ++.OD "no\-recursion" "" "" ++Does not add files from sub\-directories. ++ ++By default, ++.B dump2tar ++adds archive entries for specified directories, and for the files within these ++directories. With this option, a specified directory results in a single entry ++for the directory. Any contained files to be included must be specified ++explicitly. ++.PP ++. ++. ++.SH "MISC OPTIONS" ++. ++.OD "help" "h" "" ++Prints an overview of available options, then exits. ++.PP ++. ++. ++.OD "verbose" "V" "" ++Prints additional informational output. ++.PP ++. ++. ++.OD "quiet" "q" "" ++Suppresses printing of informational output. ++.PP ++. ++. ++. ++.SH "EXAMPLES" ++. ++.\fB ++.CL # dump2tar a b \-o archive.tar ++.\fR ++ ++.RS 4 ++Creates a tar archive named archive.tar containing files a and b. ++.RE ++.PP ++. ++.\fB ++.CL # dump2tar /proc \-o procdump.tar.gz \-z \-i \-T 1 \-M 1048576 ++.\fR ++ ++.RS 4 ++Creates a gzip compressed tar archive named procdump.tar.gz that contains ++all procfs files. Unreadable files are ignored. Files are truncated when the ++first of the two limiting conditions is reached, either 1048576 bytes of ++content or the reading time of 1 second. ++.RE ++.PP ++. ++.\fB ++.CL # dump2tar '|=dmesg' '|=lspci' \-o data.tar ++.\fR ++ ++.RS 4 ++Creates a tar archive named data.tar containing the output of the 'dmesg' ++and 'lspci' commands. ++.RE ++.PP ++. ++.\fB ++.CL # dump2tar /sys/kernel/debug/ -x '*/tracing/*' -o debug.tar -i ++.\fR ++ ++.RS 4 ++Creates a tar archive named debug.tar containing the contents of directory ++/sys/kernel/debug/ while excluding any file that is located in a sub-directory ++named 'tracing'. ++.RE ++.PP ++. ++. ++.SH "EXIT CODES" ++.TP ++.B 0 ++The program finished successfully ++.TP ++.B 1 ++A run-time error occurred ++.TP ++.B 2 ++The specified command was not valid ++.PP ++. ++. ++.SH "SEE ALSO" ++.MP dump2tar 1 , ++.MP tar 1 +--- /dev/null ++++ b/dump2tar/src/Makefile +@@ -0,0 +1,36 @@ ++# Common definitions ++include ../../common.mak ++ ++CPPFLAGS += -I ../../include -I../include -std=gnu99 -Wno-unused-parameter ++LDLIBS += -lpthread -lrt ++ifneq ($(HAVE_ZLIB),0) ++CPPFLAGS += -DHAVE_ZLIB ++LDLIBS += -lz ++endif ++ ++core_objects = buffer.o dref.o global.o dump.o idcache.o misc.o strarray.o tar.o ++libs = $(rootdir)/libutil/util_libc.o $(rootdir)/libutil/util_opt.o \ ++ $(rootdir)/libutil/util_prg.o $(rootdir)/libutil/util_panic.o ++ ++check_dep_zlib: ++ $(call check_dep, \ ++ "dump2tar", \ ++ "zlib.h", \ ++ "zlib-devel", \ ++ "HAVE_ZLIB=0") ++ ++all: check_dep_zlib dump2tar ++ ++dump2tar: $(core_objects) dump2tar.o $(libs) ++ ++install: dump2tar ++ $(INSTALL) -c dump2tar $(DESTDIR)$(USRBINDIR) ++ ++clean: ++ @rm -f dump2tar *.o ++ ++.PHONY: all install clean ++ ++# Additional manual dependencies ++../../libutil/%.o: ++ make -C ../../libutil $< +--- /dev/null ++++ b/dump2tar/src/buffer.c +@@ -0,0 +1,271 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Data buffering functions ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include "buffer.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "misc.h" ++ ++void buffer_print(struct buffer *buffer) ++{ ++ fprintf(stderr, "DEBUG: buffer at %p\n", (void *) buffer); ++ if (!buffer) ++ return; ++ fprintf(stderr, "DEBUG: total=%zu\n", buffer->total); ++ fprintf(stderr, "DEBUG: off=%zu\n", buffer->off); ++ fprintf(stderr, "DEBUG: size=%zu\n", buffer->size); ++ fprintf(stderr, "DEBUG: addr=%p\n", (void *) buffer->addr); ++ fprintf(stderr, "DEBUG: fd_open=%d\n", buffer->fd_open); ++ fprintf(stderr, "DEBUG: fd=%d\n", buffer->fd); ++ if (buffer->fd_open) { ++ fprintf(stderr, "DEBUG: fd->pos=%zu\n", ++ lseek(buffer->fd, 0, SEEK_CUR)); ++ } ++} ++ ++/* Initialize @buffer to hold @size bytes in memory */ ++void buffer_init(struct buffer *buffer, size_t size) ++{ ++ memset(buffer, 0, sizeof(struct buffer)); ++ buffer->addr = mmalloc(size); ++ buffer->size = size; ++} ++ ++/* Allocate a new buffer for holding @size bytes in memory */ ++struct buffer *buffer_alloc(size_t size) ++{ ++ struct buffer *buffer; ++ ++ buffer = mmalloc(sizeof(struct buffer)); ++ buffer_init(buffer, size); ++ ++ return buffer; ++} ++ ++/* Forget about any data stored in @buffer */ ++void buffer_reset(struct buffer *buffer) ++{ ++ buffer->total = 0; ++ buffer->off = 0; ++ if (buffer->fd_open) { ++ if (ftruncate(buffer->fd, 0)) ++ mwarn("Cannot truncate temporary file"); ++ if (lseek(buffer->fd, 0, SEEK_SET) == (off_t) -1) ++ mwarn("Cannot seek in temporary file"); ++ } ++} ++ ++/* Close buffer file associated with @buffer */ ++void buffer_close(struct buffer *buffer) ++{ ++ if (!buffer->fd_open) ++ return; ++ ++ fclose(buffer->file); ++ buffer->fd = 0; ++ buffer->fd_open = false; ++} ++ ++/* Release all resources associated with @buffer. If @dyn is %true, also free ++ * @buffer itself. */ ++void buffer_free(struct buffer *buffer, bool dyn) ++{ ++ if (!buffer) ++ return; ++ buffer_reset(buffer); ++ buffer_close(buffer); ++ free(buffer->addr); ++ if (dyn) ++ free(buffer); ++} ++ ++/* Open a buffer file for @buffer. Return %EXIT_OK on success, %EXIT_RUNTIME ++ * otherwise. */ ++int buffer_open(struct buffer *buffer) ++{ ++ if (buffer->fd_open) ++ return EXIT_OK; ++ ++ buffer->file = tmpfile(); ++ if (!buffer->file) { ++ mwarn("Could not create temporary file"); ++ return EXIT_RUNTIME; ++ } ++ ++ buffer->fd = fileno(buffer->file); ++ buffer->fd_open = true; ++ ++ return EXIT_OK; ++} ++ ++/* Write data in memory of @buffer to buffer file. Return %EXIT_OK on success, ++ * %EXIT_RUNTIME otherwise. */ ++int buffer_flush(struct buffer *buffer) ++{ ++ if (buffer->off == 0) ++ return EXIT_OK; ++ if (buffer_open(buffer)) ++ return EXIT_RUNTIME; ++ if (misc_write_data(buffer->fd, buffer->addr, buffer->off)) { ++ mwarn("Could not write to temporary file"); ++ return EXIT_RUNTIME; ++ } ++ buffer->off = 0; ++ ++ return EXIT_OK; ++} ++ ++/* Try to ensure that at least @size bytes are available at ++ * @buffer->addr[buffer->off]. Return the actual number of bytes available or ++ * @-1 on error. If @usefile is %true, make use of a buffer file if ++ * the total buffer size exceeds @max_buffer_size. */ ++ssize_t buffer_make_room(struct buffer *buffer, size_t size, bool usefile, ++ size_t max_buffer_size) ++{ ++ size_t needsize; ++ ++ if (size > max_buffer_size && usefile) ++ size = max_buffer_size; ++ ++ needsize = buffer->off + size; ++ if (needsize <= buffer->size) { ++ /* Room available */ ++ return size; ++ } ++ ++ if (needsize > max_buffer_size && usefile) { ++ /* Need to write out memory buffer to buffer file */ ++ if (buffer_flush(buffer)) ++ return -1; ++ if (size <= buffer->size) ++ return size; ++ needsize = size; ++ } ++ ++ /* Need to increase memory buffer size */ ++ buffer->size = needsize; ++ buffer->addr = mrealloc(buffer->addr, buffer->size); ++ ++ return size; ++} ++ ++/* Try to read @chunk bytes from @fd to @buffer. Return the number of bytes ++ * read on success, %0 on EOF or %-1 on error. */ ++ssize_t buffer_read_fd(struct buffer *buffer, int fd, size_t chunk, ++ bool usefile, size_t max_buffer_size) ++{ ++ ssize_t c = buffer_make_room(buffer, chunk, usefile, max_buffer_size); ++ ++ DBG("buffer_read_fd wanted %zd got %zd", chunk, c); ++ if (c < 0) ++ return c; ++ ++ c = read(fd, buffer->addr + buffer->off, c); ++ if (c > 0) { ++ buffer->total += c; ++ buffer->off += c; ++ } ++ ++ return c; ++} ++ ++/* Add @len bytes at @addr to @buffer. If @addr is %NULL, add zeroes. Return ++ * %EXIT_OK on success, %EXIT_RUNTIME otherwise. */ ++int buffer_add_data(struct buffer *buffer, char *addr, size_t len, bool usefile, ++ size_t max_buffer_size) ++{ ++ ssize_t c; ++ ++ while (len > 0) { ++ c = buffer_make_room(buffer, len, usefile, max_buffer_size); ++ if (c < 0) ++ return EXIT_RUNTIME; ++ if (addr) { ++ memcpy(buffer->addr + buffer->off, addr, c); ++ addr += c; ++ } else { ++ memset(buffer->addr + buffer->off, 0, c); ++ } ++ buffer->total += c; ++ buffer->off += c; ++ ++ len -= c; ++ } ++ ++ return EXIT_OK; ++} ++ ++/* Call @cb for all chunks of data in @buffer. @data is passed to @cb. */ ++int buffer_iterate(struct buffer *buffer, buffer_cb_t cb, void *data) ++{ ++ int rc; ++ ssize_t r; ++ ++ if (buffer->total == 0) ++ return EXIT_OK; ++ ++ if (!buffer->fd_open) ++ return cb(data, buffer->addr, buffer->off); ++ ++ /* Free memory buffer to be used as copy buffer */ ++ if (buffer_flush(buffer)) ++ return EXIT_RUNTIME; ++ if (lseek(buffer->fd, 0, SEEK_SET) == (off_t) -1) { ++ mwarn("Cannot seek in temporary file"); ++ return EXIT_RUNTIME; ++ } ++ ++ /* Copy data from temporary file to target file */ ++ while ((r = misc_read_data(buffer->fd, buffer->addr, ++ buffer->size)) != 0) { ++ if (r < 0) { ++ mwarn("Cannot read from temporary file"); ++ return EXIT_RUNTIME; ++ } ++ rc = cb(data, buffer->addr, r); ++ if (rc) ++ return rc; ++ } ++ ++ return EXIT_OK; ++} ++ ++/* Truncate @buffer to at most @len bytes */ ++int buffer_truncate(struct buffer *buffer, size_t len) ++{ ++ size_t delta; ++ ++ if (buffer->total <= len) ++ return EXIT_OK; ++ ++ delta = buffer->total - len; ++ ++ buffer->total = len; ++ if (buffer->fd_open && delta > buffer->off) { ++ /* All of memory and some of file buffer is truncated */ ++ buffer->off = 0; ++ if (ftruncate(buffer->fd, len)) { ++ mwarn("Cannot truncate temporary file"); ++ return EXIT_RUNTIME; ++ } ++ if (lseek(buffer->fd, len, SEEK_SET) == (off_t) -1) { ++ mwarn("Cannot seek in temporary file"); ++ return EXIT_RUNTIME; ++ } ++ } else { ++ /* Only memory buffer is truncated */ ++ buffer->off -= delta; ++ } ++ ++ return EXIT_OK; ++} +--- /dev/null ++++ b/dump2tar/src/dref.c +@@ -0,0 +1,92 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Reference counting for directory handles ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include "dref.h" ++ ++#include ++#include ++#include ++ ++#include "global.h" ++#include "misc.h" ++ ++/* dref_mutex serializes access to drefs */ ++static pthread_mutex_t dref_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static unsigned long num_open_dirs; ++static unsigned long num_open_dirs_max; ++ ++/* Lock dref mutex */ ++static void dref_lock(void) ++{ ++ if (!global_threaded) ++ return; ++ pthread_mutex_lock(&dref_mutex); ++} ++ ++/* Unlock dref mutex */ ++static void dref_unlock(void) ++{ ++ if (!global_threaded) ++ return; ++ pthread_mutex_unlock(&dref_mutex); ++} ++ ++/* Create a reference count managed directory handle for @dirname */ ++struct dref *dref_create(const char *dirname) ++{ ++ struct dref *dref; ++ DIR *dd; ++ ++ dd = opendir(dirname); ++ DBG("opendir(%s)=%p (total=%lu)", dirname, dd, ++num_open_dirs); ++ if (!dd) { ++ num_open_dirs--; ++ return NULL; ++ } ++ ++ if (num_open_dirs > num_open_dirs_max) ++ num_open_dirs_max = num_open_dirs; ++ ++ dref = mmalloc(sizeof(struct dref)); ++ dref->dd = dd; ++ dref->dirfd = dirfd(dd); ++ dref->count = 1; ++ ++ return dref; ++} ++ ++/* Obtain a reference to @dref */ ++struct dref *dref_get(struct dref *dref) ++{ ++ if (dref) { ++ dref_lock(); ++ dref->count++; ++ dref_unlock(); ++ } ++ ++ return dref; ++} ++ ++/* Release a reference to @dref. If this was the last reference, lose the ++ * associated directory handle and free @dref. */ ++void dref_put(struct dref *dref) ++{ ++ if (dref) { ++ dref_lock(); ++ dref->count--; ++ if (dref->count == 0) { ++ num_open_dirs--; ++ DBG("closedir(%p) (total=%lu, max=%lu)", dref->dd, ++ num_open_dirs, num_open_dirs_max); ++ closedir(dref->dd); ++ free(dref); ++ } ++ dref_unlock(); ++ } ++} +--- /dev/null ++++ b/dump2tar/src/dump.c +@@ -0,0 +1,1850 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Main dump logic ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include "dump.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_ZLIB ++#include ++#endif /* HAVE_ZLIB */ ++ ++#include "buffer.h" ++#include "dref.h" ++#include "global.h" ++#include "idcache.h" ++#include "misc.h" ++#include "tar.h" ++ ++/* Default input file read size (bytes) */ ++#define DEFAULT_READ_CHUNK_SIZE (512 * 1024) ++#define DEFAULT_MAX_BUFFER_SIZE (2 * 1024 * 1024) ++ ++#define _SET_ABORTED(task) _set_aborted((task), __func__, __LINE__) ++#define SET_ABORTED(task) set_aborted((task), __func__, __LINE__) ++ ++#define read_error(task, filename, fmt, ...) \ ++ do { \ ++ if (!(task)->opts->ignore_failed_read) \ ++ SET_ABORTED((task)); \ ++ _mwarn(true, "%s: " fmt, (filename), ##__VA_ARGS__); \ ++ } while (0) ++ ++#define write_error(task, fmt, ...) \ ++ do { \ ++ SET_ABORTED((task)); \ ++ _mwarn(true, "%s: " fmt, (task)->opts->output_file, \ ++ ##__VA_ARGS__); \ ++ } while (0) ++ ++#define tverb(fmt, ...) \ ++ do { \ ++ if (task->opts->verbose) \ ++ verb((fmt), ##__VA_ARGS__); \ ++ } while (0) ++ ++ ++/* Jobs representing a file or command output to add */ ++struct job { ++ struct job *next_job; ++ enum job_type { ++ JOB_INIT, /* Initialization work */ ++ JOB_FILE, /* Add a regular file */ ++ JOB_LINK, /* Add a symbolic link */ ++ JOB_DIR, /* Add a directory */ ++ JOB_CMD, /* Add command output */ ++ } type; ++ enum job_status { ++ JOB_QUEUED, /* Transient: Job processing has not started */ ++ JOB_IN_PROGRESS,/* Transient: Job processing has started */ ++ JOB_EXCLUDED, /* Final: File was excluded */ ++ JOB_FAILED, /* Final: Data could not be obtained */ ++ JOB_DONE, /* Final: All data was obtained */ ++ JOB_PARTIAL, /* Final: Only some data was obtained */ ++ } status; ++ char *outname; ++ char *inname; ++ char *relname; ++ struct stat stat; ++ bool timed; ++ struct timespec deadline; ++ struct dref *dref; ++ int cmd_status; ++ struct buffer *content; ++}; ++ ++/* Run-time statistics */ ++struct stats { ++ unsigned long num_done; ++ unsigned long num_excluded; ++ unsigned long num_failed; ++ unsigned long num_partial; ++}; ++ ++/* Information specific to a single dump task */ ++struct task { ++ /* Input */ ++ struct dump_opts *opts; ++ ++ /* State */ ++ ++ /* mutex serializes access to global data */ ++ pthread_mutex_t mutex; ++ pthread_cond_t worker_cond; ++ pthread_cond_t cond; ++ unsigned long num_jobs_active; ++ struct job *jobs_head; ++ struct job *jobs_tail; ++ bool aborted; ++ ++ /* output_mutex serializes access to output file */ ++ pthread_mutex_t output_mutex; ++ int output_fd; ++ size_t output_written; ++#ifdef HAVE_ZLIB ++ gzFile output_gzfd; ++#endif /* HAVE_ZLIB */ ++ unsigned long output_num_files; ++ ++ /* No protection needed (only accessed in single-threaded mode) */ ++ struct stats stats; ++ struct timespec start_ts; ++}; ++ ++/* Per thread management data */ ++struct per_thread { ++ long num; ++ pthread_t thread; ++ bool running; ++ bool timed_out; ++ struct stats stats; ++ struct job *job; ++ struct buffer buffer; ++ struct task *task; ++}; ++ ++static const struct { ++ mode_t mode; ++ char c; ++} exclude_types[NUM_EXCLUDE_TYPES] = { ++ { S_IFREG, 'f' }, ++ { S_IFDIR, 'd' }, ++ { S_IFCHR, 'c' }, ++ { S_IFBLK, 'b' }, ++ { S_IFIFO, 'p' }, ++ { S_IFLNK, 'l' }, ++ { S_IFSOCK, 's' }, ++}; ++ ++/* Lock main mutex */ ++static void main_lock(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ DBG("main lock"); ++ pthread_mutex_lock(&task->mutex); ++} ++ ++/* Unlock main mutex */ ++static void main_unlock(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ DBG("main unlock"); ++ pthread_mutex_unlock(&task->mutex); ++} ++ ++/* Lock output mutex */ ++static void output_lock(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ pthread_mutex_lock(&task->output_mutex); ++} ++ ++/* Unlock output mutex */ ++static void output_unlock(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ pthread_mutex_unlock(&task->output_mutex); ++} ++ ++/* Wake up all waiting workers */ ++static void _worker_wakeup_all(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ DBG("waking up all worker threads"); ++ pthread_cond_broadcast(&task->worker_cond); ++} ++ ++/* Wake up one waiting worker */ ++static void _worker_wakeup_one(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ DBG("waking up one worker thread"); ++ pthread_cond_signal(&task->worker_cond); ++} ++ ++/* Wait for a signal to a worker */ ++static int _worker_wait(struct task *task) ++{ ++ int rc; ++ ++ DBG("waiting for signal to worker"); ++ rc = pthread_cond_wait(&task->worker_cond, &task->mutex); ++ DBG("waiting for signal to worker done (rc=%d)", rc); ++ ++ return rc; ++} ++ ++/* Wake up main thread */ ++static void _main_wakeup(struct task *task) ++{ ++ if (!global_threaded) ++ return; ++ DBG("waking up main thread"); ++ pthread_cond_broadcast(&task->cond); ++} ++ ++/* Wait for a signal to the main thread */ ++static int _main_wait(struct task *task) ++{ ++ int rc; ++ ++ DBG("waiting for status change"); ++ rc = pthread_cond_wait(&task->cond, &task->mutex); ++ DBG("waiting for status change done (rc=%d)", rc); ++ ++ return rc; ++} ++ ++/* Wait for a signal to the main thread. Abort waiting after @deadline */ ++static int _main_wait_timed(struct task *task, struct timespec *deadline) ++{ ++ int rc; ++ ++ DBG("timed waiting for status change"); ++ rc = pthread_cond_timedwait(&task->cond, &task->mutex, deadline); ++ DBG("timed waiting for status change done (rc=%d)", rc); ++ ++ return rc; ++} ++ ++/* Allow thread to be canceled */ ++static void cancel_enable(void) ++{ ++ if (!global_threaded) ++ return; ++ if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) ++ mwarn("pthread_setcancelstate"); ++} ++ ++/* Prevent thread from being canceled */ ++static void cancel_disable(void) ++{ ++ if (!global_threaded) ++ return; ++ if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) ++ mwarn("pthread_setcancelstate"); ++} ++ ++/* Abort processing and inform all threads to shutdown. Must be called with ++ * task->mutex locked */ ++static void _set_aborted(struct task *task, const char *func, unsigned int line) ++{ ++ DBG("set aborted at %s:%u", func, line); ++ task->aborted = true; ++ _worker_wakeup_all(task); ++ _main_wakeup(task); ++} ++ ++/* Abort processing and inform all threads to shutdown */ ++static void set_aborted(struct task *task, const char *func, unsigned int line) ++{ ++ main_lock(task); ++ _set_aborted(task, func, line); ++ main_unlock(task); ++} ++ ++/* Check if abort processing has been initiated */ ++static bool is_aborted(struct task *task) ++{ ++ bool result; ++ ++ main_lock(task); ++ result = task->aborted; ++ main_unlock(task); ++ ++ return result; ++} ++ ++/* Release resources associated with @job */ ++static void free_job(struct task *task, struct job *job) ++{ ++ DBG("free job %p (%s)", job, job->inname); ++ if (!job) ++ return; ++ free(job->inname); ++ free(job->outname); ++ free(job->relname); ++ dref_put(job->dref); ++ free(job); ++} ++ ++/* Check if file type specified by mode @m was marked as excluded */ ++static bool is_type_excluded(struct dump_opts *opts, mode_t m) ++{ ++ int i; ++ ++ m &= S_IFMT; ++ for (i = 0; i < NUM_EXCLUDE_TYPES; i++) { ++ if (exclude_types[i].mode == m) ++ return opts->exclude_type[i]; ++ } ++ return false; ++} ++ ++/* Replace all '/' characters in @filename with '_' */ ++static void escape_filename(char *filename) ++{ ++ for (; *filename; filename++) { ++ if (*filename == '/') ++ *filename = '_'; ++ } ++} ++ ++/* Determine filename in archive from original filename @inname and ++ * requested new filename @outname and depending on @type. */ ++static void set_outname(char **result_ptr, const char *outname, ++ const char *inname, enum job_type type) ++{ ++ const char *prefix = "", *name, *suffix; ++ char *result, *end; ++ size_t olen = outname ? strlen(outname) : 0, plen, nlen; ++ ++ if (olen == 0) { ++ /* No output name specified: outname = inname */ ++ name = inname; ++ } else if (outname[olen - 1] == '/') { ++ /* Output name is a directory: outname = outname/inname */ ++ prefix = outname; ++ name = inname; ++ } else { ++ /* Output name is a filename: outname = inname */ ++ name = outname; ++ } ++ ++ if (type == JOB_DIR) ++ suffix = "/"; ++ else ++ suffix = ""; ++ ++ plen = strlen(prefix); ++ nlen = strlen(name); ++ ++ result = mmalloc(plen + nlen + strlen(suffix) + /* NUL */ 1); ++ ++ /* Add prefix */ ++ strcpy(result, prefix); ++ ++ /* Add name */ ++ end = result + plen; ++ strcpy(end, name); ++ if (type == JOB_CMD) ++ escape_filename(end); ++ ++ /* Add suffix */ ++ end = end + nlen; ++ strcpy(end, suffix); ++ ++ remove_double_slashes(result); ++ ++ *result_ptr = result; ++} ++ ++static void sanitize_dirname(char **name_ptr) ++{ ++ char *name; ++ ++ name = mmalloc(strlen(*name_ptr) + /* Slash */ 1 + /* NUL */ 1); ++ strcpy(name, *name_ptr); ++ remove_double_slashes(name); ++ chomp(name, "/"); ++ strcat(name, "/"); ++ free(*name_ptr); ++ *name_ptr = name; ++} ++ ++/* Allocate and initialize a new job representation to add an entry according ++ * to the specified parameters. @relname and @dref are used for opening files ++ * more efficiently using *at() functions if specified. @is_cmd specifies if ++ * the specified inname is a command line. */ ++static struct job *create_job(struct task *task, const char *inname, ++ const char *outname, bool is_cmd, ++ const char *relname, struct dref *dref, ++ struct stats *stats) ++{ ++ struct job *job = mmalloc(sizeof(struct job)); ++ int rc; ++ ++ DBG("create job inname=%s outname=%s is_cmd=%d relname=%s dref=%p", ++ inname, outname, is_cmd, relname, dref); ++ ++ job->status = JOB_QUEUED; ++ ++ if (!inname) { ++ job->type = JOB_INIT; ++ return job; ++ } ++ ++ job->inname = mstrdup(inname); ++ ++ if (is_cmd) { ++ /* Special case - read from command output */ ++ job->type = JOB_CMD; ++ set_dummy_stat(&job->stat); ++ goto out; ++ } ++ ++ if (!relname && strcmp(job->inname, "-") == 0) { ++ /* Special case - read from standard input */ ++ job->type = JOB_FILE; ++ set_dummy_stat(&job->stat); ++ goto out; ++ } ++ ++ rc = stat_file(task->opts->dereference, job->inname, relname, dref, ++ &job->stat); ++ ++ if (rc < 0) { ++ read_error(task, job->inname, "Cannot stat file"); ++ free_job(task, job); ++ stats->num_failed++; ++ return NULL; ++ } ++ ++ if (is_type_excluded(task->opts, job->stat.st_mode)) { ++ free_job(task, job); ++ stats->num_excluded++; ++ return NULL; ++ } ++ ++ if (S_ISLNK(job->stat.st_mode)) { ++ job->type = JOB_LINK; ++ } else if (S_ISDIR(job->stat.st_mode)) { ++ job->type = JOB_DIR; ++ sanitize_dirname(&job->inname); ++ ++ /* No need to keep parent directory open */ ++ relname = NULL; ++ dref = NULL; ++ } else { ++ job->type = JOB_FILE; ++ } ++ ++ if (relname) ++ job->relname = mstrdup(relname); ++ job->dref = dref_get(dref); ++ ++out: ++ set_outname(&job->outname, outname, inname, job->type); ++ ++ return job; ++} ++ ++void job_print(struct job *job) ++{ ++ printf("DEBUG: job_print at %p\n", job); ++ printf("DEBUG: next_job=%p\n", job->next_job); ++ printf("DEBUG: type=%d\n", job->type); ++ printf("DEBUG: status==%d\n", job->status); ++ printf("DEBUG: outname=%s\n", job->outname); ++ printf("DEBUG: inname=%s\n", job->inname); ++ printf("DEBUG: relname=%s\n", job->relname); ++ printf("DEBUG: timed=%d\n", job->timed); ++ printf("DEBUG: dref=%p\n", job->dref); ++ printf("DEBUG: cmd_status=%d\n", job->cmd_status); ++ printf("DEBUG: content=%p\n", job->content); ++} ++ ++/* Return the number of bytes written to the output file */ ++static size_t get_output_size(struct task *task) ++{ ++#ifdef HAVE_ZLIB ++ if (task->opts->gzip) { ++ gzflush(task->output_gzfd, Z_SYNC_FLUSH); ++ return gztell(task->output_gzfd); ++ } ++#endif /* HAVE_ZLIB */ ++ return task->output_written; ++} ++ ++/* Write @len bytes at address @ptr to the output file */ ++static int write_output(struct task *task, const char *ptr, size_t len) ++{ ++ size_t todo = len; ++ ssize_t w; ++ ++#ifdef HAVE_ZLIB ++ if (task->opts->gzip) { ++ if (gzwrite(task->output_gzfd, ptr, len) == 0) ++ goto err_write; ++ task->output_written += len; ++ ++ return EXIT_OK; ++ } ++#endif /* HAVE_ZLIB */ ++ ++ while (todo > 0) { ++ w = write(task->output_fd, ptr, todo); ++ if (w < 0) ++ goto err_write; ++ todo -= w; ++ ptr += w; ++ } ++ task->output_written += len; ++ ++ return EXIT_OK; ++ ++err_write: ++ write_error(task, "Cannot write output"); ++ ++ return EXIT_RUNTIME; ++} ++ ++/* Write an end-of-file marker to the output file */ ++static void write_eof(struct task *task) ++{ ++ char zeroes[TAR_BLOCKSIZE]; ++ ++ memset(zeroes, 0, sizeof(zeroes)); ++ write_output(task, zeroes, TAR_BLOCKSIZE); ++ write_output(task, zeroes, TAR_BLOCKSIZE); ++} ++ ++/* Callback for writing out chunks of job data */ ++static int _write_job_data_cb(void *data, void *addr, size_t len) ++{ ++ struct task *task = data; ++ ++ return write_output(task, addr, len); ++} ++ ++/* Write tar entry for a file containing the exit status of the process that ++ * ran command job @job */ ++static int write_job_status_file(struct task *task, struct job *job) ++{ ++ char *name, *content; ++ size_t len; ++ struct stat st; ++ int rc, status = job->cmd_status, exitstatus = -1, termsig = -1, ++ waitpid_errno = -1; ++ ++ name = masprintf("%s.cmdstatus", job->outname); ++ if (status < 0) ++ waitpid_errno = -status; ++ else if (WIFEXITED(status)) ++ exitstatus = WEXITSTATUS(status); ++ else if (WIFSIGNALED(status)) ++ termsig = WTERMSIG(status); ++ ++ content = masprintf("EXITSTATUS=%d\n" ++ "TERMSIG=%d\n" ++ "WAITPID_ERRNO=%d\n", exitstatus, termsig, ++ waitpid_errno); ++ ++ len = strlen(content); ++ set_dummy_stat(&st); ++ rc = tar_emit_file_from_data(name, NULL, len, &st, TYPE_REGULAR, ++ content, _write_job_data_cb, task); ++ free(name); ++ free(content); ++ ++ return rc; ++} ++ ++/* Write tar entry for data in @job to output. Must be called with output_lock ++ * held. */ ++static void _write_job_data(struct task *task, struct job *job) ++{ ++ struct buffer *buffer = job->content; ++ ++ switch (job->status) { ++ case JOB_DONE: ++ case JOB_PARTIAL: ++ break; ++ case JOB_FAILED: ++ /* Create empty entries for failed reads */ ++ if (task->opts->ignore_failed_read) ++ break; ++ return; ++ default: ++ return; ++ } ++ ++ switch (job->type) { ++ case JOB_CMD: ++ tar_emit_file_from_buffer(job->outname, NULL, buffer->total, ++ &job->stat, TYPE_REGULAR, buffer, ++ _write_job_data_cb, task); ++ task->output_num_files++; ++ if (task->opts->add_cmd_status) { ++ write_job_status_file(task, job); ++ task->output_num_files++; ++ } ++ break; ++ case JOB_FILE: ++ tar_emit_file_from_buffer(job->outname, NULL, buffer->total, ++ &job->stat, TYPE_REGULAR, buffer, ++ _write_job_data_cb, task); ++ task->output_num_files++; ++ break; ++ case JOB_LINK: ++ tar_emit_file_from_buffer(job->outname, buffer->addr, 0, ++ &job->stat, TYPE_LINK, NULL, ++ _write_job_data_cb, task); ++ task->output_num_files++; ++ break; ++ case JOB_DIR: ++ tar_emit_file_from_buffer(job->outname, NULL, 0, &job->stat, ++ TYPE_DIR, NULL, _write_job_data_cb, ++ task); ++ task->output_num_files++; ++ break; ++ default: ++ break; ++ } ++ ++ if (task->opts->max_size > 0 && ++ get_output_size(task) > task->opts->max_size) { ++ mwarnx("Archive size exceeds maximum of %ld bytes - aborting", ++ task->opts->max_size); ++ SET_ABORTED(task); ++ } ++} ++ ++/* Read the contents of the symbolic link at @filename. On success, the ++ * contents is returned in @buffer and the return value is %EXIT_OK. ++ * If @relname is non-null it points to the name of the file relative ++ * to its parent directory for which @dirfd is an open file handle. */ ++static int read_symlink(struct task *task, const char *filename, ++ const char *relname, int dirfd, struct buffer *buffer) ++{ ++ ssize_t actual = 0; ++ size_t currlen = buffer->size ? buffer->size : ++ task->opts->read_chunk_size; ++ int rc = EXIT_OK; ++ ++ while (!is_aborted(task)) { ++ buffer_make_room(buffer, currlen, false, ++ task->opts->max_buffer_size); ++ ++ cancel_enable(); ++ if (relname) ++ actual = readlinkat(dirfd, relname, buffer->addr, ++ buffer->size); ++ else ++ actual = readlink(filename, buffer->addr, buffer->size); ++ cancel_disable(); ++ ++ if (actual == -1) { ++ read_error(task, filename, "Cannot read link"); ++ rc = EXIT_RUNTIME; ++ /* Reset actual counter to get an empty buffer */ ++ actual = 0; ++ break; ++ } ++ ++ /* Ensure that content doesn't exceed --file-max-size limit */ ++ if (task->opts->file_max_size > 0 && ++ (size_t) actual > task->opts->file_max_size) { ++ actual = task->opts->file_max_size;/* Don't count NUL */ ++ mwarnx("%s: Warning: Data exceeds maximum size of %ld " ++ "bytes - truncating", filename, ++ task->opts->file_max_size); ++ break; ++ } ++ ++ if ((size_t) actual < buffer->size) ++ break; ++ ++ currlen += task->opts->read_chunk_size; ++ } ++ ++ if (rc == EXIT_OK && is_aborted(task)) ++ rc = EXIT_RUNTIME; ++ ++ buffer->addr[actual] = 0; ++ buffer->total = actual + 1; ++ ++ return rc; ++} ++ ++/* Read data from the file descriptor @fd until an end-of-file condition is ++ * encountered. On success, *@done bytes in @buffer contain the read data ++ * and the return value is %EXIT_OK. */ ++static int read_fd(struct task *task, const char *name, int fd, ++ struct buffer *buffer) ++{ ++ ssize_t rc = 0; ++ size_t c = buffer->size ? buffer->size : task->opts->read_chunk_size; ++ ++ while (!is_aborted(task)) { ++ cancel_enable(); ++ rc = buffer_read_fd(buffer, fd, c, true, ++ task->opts->max_buffer_size); ++ cancel_disable(); ++ ++ if (rc <= 0) ++ break; ++ ++ /* Ensure that content doesn't exceed --file-max-size limit */ ++ if (task->opts->file_max_size > 0 && ++ buffer->total >= task->opts->file_max_size) { ++ buffer_truncate(buffer, task->opts->file_max_size); ++ rc = 0; ++ mwarnx("%s: Warning: Data exceeds maximum size of %ld " ++ "bytes - truncating", name, ++ task->opts->file_max_size); ++ break; ++ } ++ ++ c = buffer->size - buffer->off; ++ if (c > 0) { ++ /* Read to memory */ ++ } else if (buffer->size + task->opts->read_chunk_size < ++ task->opts->max_buffer_size) { ++ /* Enlarge memory buffer */ ++ c = task->opts->read_chunk_size; ++ } else { ++ /* Use full memory buffer size */ ++ c = task->opts->max_buffer_size; ++ } ++ } ++ ++ if (is_aborted(task) || rc != 0) ++ return EXIT_RUNTIME; ++ ++ return EXIT_OK; ++} ++ ++/* Read data from the file at @filename until an end-of-file condition is ++ * encountered. On success, @buffer contains the data read and the return ++ * value is %EXIT_OK. If @relname is non-null it points to the name of the ++ * file relative to its parent directory for which @dirfd is an open file ++ * handle. */ ++static int read_regular(struct task *task, const char *filename, ++ const char *relname, int dirfd, struct buffer *buffer) ++{ ++ int fd, rc = EXIT_OK; ++ bool need_close = true; ++ ++ /* Opening a named pipe can block when peer is not ready */ ++ cancel_enable(); ++ if (strcmp(filename, "-") == 0) { ++ fd = STDIN_FILENO; ++ need_close = false; ++ filename = "Standard input"; ++ } else if (relname) ++ fd = openat(dirfd, relname, O_RDONLY); ++ else ++ fd = open(filename, O_RDONLY); ++ cancel_disable(); ++ ++ if (fd < 0) { ++ read_error(task, filename, "Cannot open file"); ++ return EXIT_RUNTIME; ++ } ++ ++ rc = read_fd(task, filename, fd, buffer); ++ if (rc) { ++ if (is_aborted(task)) ++ mwarnx("%s: Read aborted", filename); ++ else ++ read_error(task, filename, "Cannot read file"); ++ } ++ ++ if (need_close) ++ close(fd); ++ ++ return rc; ++} ++ ++/* Read the output of command @cmd until an end-of-file condition is ++ * encountered. On success, @buffer contain the output and the return value ++ * is %EXIT_OK. When not %NULL, use @status_ptr to store the resulting process ++ * status. */ ++static int read_cmd_output(struct task *task, char *cmd, struct buffer *buffer, ++ int *status_ptr) ++{ ++ int fd, rc = EXIT_RUNTIME; ++ pid_t pid; ++ ++ fd = cmd_open(cmd, &pid); ++ if (fd < 0) { ++ read_error(task, cmd, "Cannot run command"); ++ return rc; ++ } ++ ++ if (read_fd(task, cmd, fd, buffer)) { ++ if (is_aborted(task)) ++ mwarnx("%s: Command aborted", cmd); ++ else ++ read_error(task, cmd, "Cannot read command output"); ++ } else ++ rc = EXIT_OK; ++ ++ cmd_close(fd, pid, status_ptr); ++ ++ return rc; ++ ++} ++ ++/* Check the exclude patterns in @task->opts->exclude for a match of @filename. ++ * If found, return the matching pattern string, otherwise return %NULL. */ ++static const char *get_exclude_match(struct task *task, const char *filename) ++{ ++ unsigned int i; ++ int mode = FNM_PERIOD | FNM_NOESCAPE; ++ ++ for (i = 0; i < task->opts->exclude.num; i++) { ++ if (fnmatch(task->opts->exclude.str[i], filename, mode) == 0) ++ return task->opts->exclude.str[i]; ++ } ++ ++ return NULL; ++} ++ ++/* Add the specified @job to the start of the job queue */ ++static void _queue_job_head(struct task *task, struct job *job) ++{ ++ DBG("queue job type=%d inname=%s at head", job->type, job->inname); ++ job->next_job = task->jobs_head; ++ task->jobs_head = job; ++ if (!task->jobs_tail) ++ task->jobs_tail = job; ++} ++ ++/* Add the specified @job to the end of the job queue */ ++static void _queue_job_tail(struct task *task, struct job *job) ++{ ++ DBG("queue job type=%d inname=%s at tail", job->type, job->inname); ++ if (task->jobs_tail) ++ task->jobs_tail->next_job = job; ++ else ++ task->jobs_head = job; ++ task->jobs_tail = job; ++} ++ ++/* Add the specified @job to the job queue and trigger processing. ++ * If @head is %true, the new job is inserted at the start of the job queue, ++ * otherwise at the end. */ ++static void queue_job(struct task *task, struct job *job, bool head) ++{ ++ main_lock(task); ++ task->num_jobs_active++; ++ if (head) ++ _queue_job_head(task, job); ++ else ++ _queue_job_tail(task, job); ++ _worker_wakeup_one(task); ++ main_unlock(task); ++} ++ ++/* Add the specified list of jobs starting with @first up to @last to the start ++ * of the job queue and trigger processing */ ++static void queue_jobs(struct task *task, struct job *first, struct job *last, ++ int num) ++{ ++ main_lock(task); ++ last->next_job = task->jobs_head; ++ task->jobs_head = first; ++ task->num_jobs_active += num; ++ _worker_wakeup_all(task); ++ main_unlock(task); ++} ++ ++/* Remove the head of the job queue and return it to the caller */ ++static struct job *_dequeue_job(struct task *task) ++{ ++ struct job *job = NULL; ++ ++ if (task->jobs_head) { ++ job = task->jobs_head; ++ task->jobs_head = job->next_job; ++ job->next_job = NULL; ++ if (job == task->jobs_tail) ++ task->jobs_tail = NULL; ++ DBG("dequeueing job type=%d inname=%s", job->type, job->inname); ++ job->status = JOB_IN_PROGRESS; ++ } else { ++ DBG("no job to dequeue"); ++ } ++ ++ return job; ++} ++ ++/* Create and queue job for file at @filename */ ++static void queue_file(struct task *task, const char *inname, ++ const char *outname, bool is_cmd, ++ const char *relname, struct dref *dref, ++ struct stats *stats, bool head) ++{ ++ struct job *job; ++ ++ job = create_job(task, inname, outname, is_cmd, relname, dref, stats); ++ if (job) ++ queue_job(task, job, head); ++} ++ ++/* Queue initial job */ ++static void init_queue(struct task *task) ++{ ++ queue_file(task, NULL, NULL, false, NULL, NULL, NULL, true); ++} ++ ++/* Create and queue jobs for all files found in @dirname */ ++static void queue_dir(struct task *task, const char *dirname, ++ const char *outname, struct stats *stats) ++{ ++ struct dirent *de; ++ char *inpath, *outpath; ++ struct dref *dref; ++ struct job *job, *first = NULL, *last = NULL; ++ int num = 0; ++ ++ dref = dref_create(dirname); ++ if (!dref) { ++ read_error(task, dirname, "Cannot read directory"); ++ return; ++ } ++ ++ while ((de = readdir(dref->dd))) { ++ if (de->d_name[0] == '.') { ++ if (de->d_name[1] == 0) ++ continue; ++ if (de->d_name[1] == '.' && de->d_name[2] == 0) ++ continue; ++ } ++ DBG("next file %s", de->d_name); ++ inpath = masprintf("%s%s", dirname, de->d_name); ++ outpath = masprintf("%s%s", outname, de->d_name); ++ job = create_job(task, inpath, outpath, false, de->d_name, dref, ++ stats); ++ if (job) { ++ if (last) { ++ last->next_job = job; ++ last = job; ++ } else { ++ first = job; ++ last = job; ++ } ++ num++; ++ } ++ free(inpath); ++ free(outpath); ++ } ++ ++ if (first) ++ queue_jobs(task, first, last, num); ++ ++ dref_put(dref); ++} ++ ++/* Create and queue jobs for all files specified on the command line */ ++static void queue_jobs_from_opts(struct task *task, struct stats *stats) ++{ ++ struct dump_opts *opts = task->opts; ++ unsigned int i; ++ ++ /* Queue directly specified entries */ ++ for (i = 0; i < opts->num_specs && !is_aborted(task); i++) { ++ queue_file(task, opts->specs[i].inname, opts->specs[i].outname, ++ opts->specs[i].is_cmd, NULL, NULL, stats, false); ++ } ++} ++ ++/* Prepare output stream */ ++static int open_output(struct task *task) ++{ ++ bool to_stdout = !task->opts->output_file || ++ strcmp(task->opts->output_file, "-") == 0; ++ int rc = EXIT_OK; ++ ++ if (to_stdout) { ++ set_stdout_data(); ++ task->opts->output_file = "Standard output"; ++ } ++ ++ cancel_enable(); ++#ifdef HAVE_ZLIB ++ if (task->opts->gzip) { ++ if (to_stdout) { ++ task->output_gzfd = ++ gzdopen(STDOUT_FILENO, ++ task->opts->append ? "ab" : "wb"); ++ } else { ++ task->output_gzfd = ++ gzopen(task->opts->output_file, ++ task->opts->append ? "ab" : "wb"); ++ } ++ ++ if (!task->output_gzfd) ++ rc = EXIT_RUNTIME; ++ goto out; ++ } ++#endif /* HAVE_ZLIB */ ++ ++ if (to_stdout) { ++ task->output_fd = STDOUT_FILENO; ++ } else { ++ task->output_fd = ++ open(task->opts->output_file, O_WRONLY | O_CREAT | ++ (task->opts->append ? O_APPEND : 0), 0666); ++ } ++ ++ if (task->output_fd < 0) ++ rc = EXIT_RUNTIME; ++ else if (!task->opts->append && ftruncate(task->output_fd, 0) == -1) ++ rc = EXIT_RUNTIME; ++ ++#ifdef HAVE_ZLIB ++out: ++#endif /* HAVE_ZLIB */ ++ cancel_disable(); ++ ++ if (rc != EXIT_OK) { ++ mwarn("%s: Cannot open output file", task->opts->output_file); ++ return rc; ++ } ++ ++ return EXIT_OK; ++} ++ ++/* Determine if the specified @job should be excluded from archiving */ ++static bool is_job_excluded(struct task *task, struct job *job) ++{ ++ const char *pat; ++ ++ if (job->type == JOB_INIT || job->type == JOB_CMD) ++ return false; ++ ++ pat = get_exclude_match(task, job->inname); ++ if (!pat) ++ return false; ++ ++ tverb("Excluding '%s' due to exclude pattern '%s'\n", job->inname, pat); ++ ++ return true; ++} ++ ++/* Perform all actions necessary to process @job and add resulting tar ++ * data buffers to the buffer list of @thread. */ ++static void process_job(struct per_thread *thread, struct job *job) ++{ ++ struct task *task = thread->task; ++ const char *relname = job->dref ? job->relname : NULL; ++ int dirfd = job->dref ? job->dref->dirfd : -1; ++ struct buffer *buffer = &thread->buffer; ++ enum job_status status = JOB_DONE; ++ ++ DBG("processing job type=%d inname=%s", job->type, job->inname); ++ ++ if (is_job_excluded(task, job)) { ++ status = JOB_EXCLUDED; ++ goto out; ++ } ++ ++ switch (job->type) { ++ case JOB_INIT: /* Perform initial setup steps */ ++ if (open_output(task)) { ++ SET_ABORTED(task); ++ status = JOB_FAILED; ++ goto out; ++ } ++ queue_jobs_from_opts(task, &thread->stats); ++ break; ++ case JOB_CMD: /* Capture command output */ ++ tverb("Dumping command output '%s'\n", job->inname); ++ ++ set_dummy_stat(&job->stat); ++ if (read_cmd_output(task, job->inname, buffer, ++ &job->cmd_status)) ++ status = JOB_FAILED; ++ ++ break; ++ case JOB_LINK: /* Read symbolic link */ ++ tverb("Dumping link '%s'\n", job->inname); ++ ++ if (read_symlink(task, job->inname, relname, dirfd, buffer)) ++ status = JOB_FAILED; ++ ++ break; ++ case JOB_DIR: /* Read directory contents */ ++ tverb("Dumping directory '%s'\n", job->inname); ++ ++ if (task->opts->recursive) { ++ queue_dir(task, job->inname, job->outname, ++ &thread->stats); ++ } ++ break; ++ case JOB_FILE: /* Read file contents */ ++ tverb("Dumping file '%s'\n", job->inname); ++ ++ if (read_regular(task, job->inname, relname, dirfd, buffer)) ++ status = JOB_FAILED; ++ ++ break; ++ default: ++ break; ++ } ++ ++out: ++ job->status = status; ++ DBG("processing done status=%d", job->status); ++} ++ ++/* Add @job results to statistics @stats */ ++static void account_stats(struct task *task, struct stats *stats, ++ struct job *job) ++{ ++ DBG("accounting job %s", job->inname); ++ ++ if (job->type == JOB_INIT) ++ return; ++ ++ switch (job->status) { ++ case JOB_DONE: ++ stats->num_done++; ++ if (job->type == JOB_CMD && task->opts->add_cmd_status) ++ stats->num_done++; ++ break; ++ case JOB_PARTIAL: ++ stats->num_done++; ++ stats->num_partial++; ++ if (job->type == JOB_CMD && task->opts->add_cmd_status) ++ stats->num_done++; ++ break; ++ case JOB_FAILED: ++ stats->num_failed++; ++ break; ++ case JOB_EXCLUDED: ++ stats->num_excluded++; ++ break; ++ default: ++ break; ++ } ++} ++ ++/* Add statistics @from to @to */ ++static void add_stats(struct stats *to, struct stats *from) ++{ ++ to->num_done += from->num_done; ++ to->num_partial += from->num_partial; ++ to->num_excluded += from->num_excluded; ++ to->num_failed += from->num_failed; ++} ++ ++/* Release resources allocated to @thread */ ++static void cleanup_thread(struct per_thread *thread) ++{ ++ if (thread->job) ++ free_job(thread->task, thread->job); ++ buffer_free(&thread->buffer, false); ++} ++ ++/* Register activate @job at @thread */ ++static void start_thread_job(struct per_thread *thread, struct job *job) ++{ ++ struct task *task = thread->task; ++ ++ thread->job = job; ++ job->content = &thread->buffer; ++ if (task->opts->file_timeout > 0 && job->type != JOB_INIT) { ++ /* Set up per-job timeout */ ++ set_timespec(&job->deadline, task->opts->file_timeout, 0); ++ job->timed = true; ++ ++ /* Signal main thread to update deadline timeout */ ++ _main_wakeup(task); ++ } ++} ++ ++/* Unregister active @job at @thread */ ++static void stop_thread_job(struct per_thread *thread, struct job *job) ++{ ++ thread->job = NULL; ++ job->content = NULL; ++ buffer_reset(&thread->buffer); ++} ++ ++/* Wait until a job is available in the job queue. When a job becomes ++ * available, dequeue and return it. Return %NULL if no more jobs are ++ * available, or if processing was aborted. Must be called with task->mutex ++ * locked. */ ++static struct job *_get_next_job(struct task *task) ++{ ++ struct job *job = NULL; ++ ++ do { ++ DBG("checking for jobs"); ++ if (task->aborted) ++ break; ++ job = _dequeue_job(task); ++ if (job) ++ break; ++ if (task->num_jobs_active == 0) ++ break; ++ DBG("found no jobs (%d active)", task->num_jobs_active); ++ } while (_worker_wait(task) == 0); ++ ++ return job; ++} ++ ++/* Unlock the mutex specified by @data */ ++static void cleanup_unlock(void *data) ++{ ++ pthread_mutex_t *mutex = data; ++ ++ pthread_mutex_unlock(mutex); ++} ++ ++/* Write entry for data in @job to output */ ++static void write_job_data(struct task *task, struct job *job) ++{ ++ DBG("write_job_data"); ++ output_lock(task); ++ pthread_cleanup_push(cleanup_unlock, &task->output_mutex); ++ cancel_enable(); ++ ++ _write_job_data(task, job); ++ ++ cancel_disable(); ++ pthread_cleanup_pop(0); ++ output_unlock(task); ++} ++ ++/* Perform second part of job processing for @job at @thread by writing the ++ * resulting tar file entry */ ++static void postprocess_job(struct per_thread *thread, struct job *job, ++ bool cancelable) ++{ ++ struct task *task = thread->task; ++ ++ account_stats(task, &thread->stats, job); ++ if (cancelable) ++ write_job_data(task, job); ++ else ++ _write_job_data(task, job); ++} ++ ++/* Mark @job as complete by releasing all associated resources. If this was ++ * the last active job inform main thread. Must be called with main_lock ++ * mutex held. */ ++static void _complete_job(struct task *task, struct job *job) ++{ ++ task->num_jobs_active--; ++ if (task->num_jobs_active == 0) ++ _main_wakeup(task); ++ free_job(task, job); ++} ++ ++static void init_thread(struct per_thread *thread, struct task *task, long num) ++{ ++ memset(thread, 0, sizeof(struct per_thread)); ++ thread->task = task; ++ thread->num = num; ++} ++ ++/* Dequeue and process all jobs on the job queue */ ++static int process_queue(struct task *task) ++{ ++ struct job *job; ++ struct per_thread thread; ++ ++ init_thread(&thread, task, 0); ++ ++ while ((job = _dequeue_job(task)) && !is_aborted(task)) { ++ start_thread_job(&thread, job); ++ process_job(&thread, job); ++ postprocess_job(&thread, job, false); ++ stop_thread_job(&thread, job); ++ _complete_job(task, job); ++ } ++ ++ task->stats = thread.stats; ++ cleanup_thread(&thread); ++ ++ return EXIT_OK; ++} ++ ++/* Return %true if @job is in a final state, %false otherwise */ ++static bool job_is_final(struct job *job) ++{ ++ switch (job->status) { ++ case JOB_DONE: ++ case JOB_PARTIAL: ++ case JOB_EXCLUDED: ++ case JOB_FAILED: ++ return true; ++ default: ++ break; ++ } ++ ++ return false; ++} ++ ++/* Main thread function: process jobs on the job queue until all jobs ++ * are processed or processing was aborted. */ ++static void *worker_thread_main(void *d) ++{ ++ struct per_thread *thread = d; ++ struct task *task = thread->task; ++ struct job *job; ++ ++ /* Allow cancel only at specific code points */ ++ cancel_disable(); ++ set_threadname("%*sworker %d", (thread->num + 1) * 2, "", thread->num); ++ ++ /* Handle jobs left over from canceled thread */ ++ job = thread->job; ++ if (job) { ++ DBG("handle aborted job %p", job); ++ ++ postprocess_job(thread, job, true); ++ ++ main_lock(task); ++ if (thread->timed_out) ++ goto out; ++ stop_thread_job(thread, job); ++ _complete_job(task, job); ++ main_unlock(task); ++ } ++ ++ DBG("enter worker loop"); ++ ++ main_lock(task); ++ while ((job = _get_next_job(task))) { ++ start_thread_job(thread, job); ++ main_unlock(task); ++ ++ process_job(thread, job); ++ postprocess_job(thread, job, true); ++ ++ main_lock(task); ++ if (thread->timed_out) ++ goto out; ++ stop_thread_job(thread, job); ++ _complete_job(task, job); ++ } ++ ++out: ++ thread->running = false; ++ _main_wakeup(task); ++ main_unlock(task); ++ ++ cancel_enable(); ++ DBG("leave work loop"); ++ ++ return NULL; ++} ++ ++/* Start a worker thread associated with the specified @data. Return %EXIT_OK on ++ * success. */ ++static int start_worker_thread(struct per_thread *data) ++{ ++ int rc; ++ ++ DBG("start thread"); ++ global_threaded = true; ++ data->timed_out = false; ++ rc = pthread_create(&data->thread, NULL, &worker_thread_main, data); ++ if (rc) { ++ mwarnx("Cannot start thread: %s", strerror(rc)); ++ return EXIT_RUNTIME; ++ } ++ data->running = true; ++ ++ return EXIT_OK; ++} ++ ++/* Perform timeout handling for thread associated with @data by canceling and ++ * restarting the corresponding thread. Must be called with task->mutex ++ * held. */ ++static void _timeout_thread(struct per_thread *data) ++{ ++ struct task *task = data->task; ++ struct job *job = data->job; ++ pthread_t thread = data->thread; ++ const char *op, *action; ++ ++ if (!job) { ++ /* Timeout raced with job completion */ ++ return; ++ } ++ if (job_is_final(job)) { ++ /* Job processing done, timeout does not apply */ ++ return; ++ } ++ ++ data->timed_out = true; ++ ++ /* Allow thread to obtain main lock during cancel handling */ ++ main_unlock(task); ++ DBG("cancel num=%d thread=%p", data->num, thread); ++ pthread_cancel(thread); ++ DBG("join num=%d thread=%p", data->num, thread); ++ ++ pthread_join(thread, NULL); ++ main_lock(task); ++ ++ DBG("join done"); ++ ++ if (job->type == JOB_CMD) ++ op = "Command"; ++ else ++ op = "Read"; ++ ++ if (task->opts->ignore_failed_read) ++ action = "skipping"; ++ else ++ action = "aborting"; ++ ++ if (!job->inname || !*job->inname) ++ job_print(job); ++ mwarnx("%s: %s%s timed out after %d second%s - %s", job->inname, ++ task->opts->ignore_failed_read ? "Warning: " : "", op, ++ task->opts->file_timeout, ++ task->opts->file_timeout > 1 ? "s" : "", action); ++ if (!task->opts->ignore_failed_read) ++ _SET_ABORTED(task); ++ ++ /* Interrupted job will be handled by new thread - adjust status */ ++ if (job->status == JOB_IN_PROGRESS) ++ job->status = JOB_PARTIAL; ++ else if (!job_is_final(job)) ++ job->status = JOB_FAILED; ++ ++ if (start_worker_thread(data)) ++ _SET_ABORTED(task); ++} ++ ++/* Return the number of currently running jobs */ ++static long num_jobs_running(struct task *task, struct per_thread *threads) ++{ ++ long i, num = 0; ++ ++ for (i = 0; i < task->opts->jobs; i++) { ++ if (threads[i].running) ++ num++; ++ } ++ ++ return num; ++} ++ ++/* Wait until all jobs are done or timeout occurs */ ++static int wait_for_completion(struct task *task, struct per_thread *threads) ++{ ++ int rc = 0, earliest_timeout; ++ long i; ++ struct per_thread *earliest_thread; ++ struct timespec tool_deadline_ts, deadline_ts, *earliest_ts; ++ struct job *job; ++ ++ /* Set tool deadline */ ++ tool_deadline_ts = task->start_ts; ++ inc_timespec(&tool_deadline_ts, task->opts->timeout, 0); ++ ++ main_lock(task); ++ while (!task->aborted && task->num_jobs_active > 0) { ++ /* Calculate nearest timeout */ ++ earliest_timeout = 0; ++ earliest_ts = NULL; ++ earliest_thread = NULL; ++ ++ if (task->opts->timeout > 0) { ++ earliest_timeout = task->opts->timeout; ++ earliest_ts = &tool_deadline_ts; ++ } ++ ++ for (i = 0; i < task->opts->jobs; i++) { ++ job = threads[i].job; ++ if (!job || !job->timed) ++ continue; ++ if (task->opts->file_timeout == 0) ++ continue; ++ if (!earliest_ts || ++ ts_before(&job->deadline, earliest_ts)) { ++ earliest_timeout = task->opts->file_timeout; ++ earliest_ts = &job->deadline; ++ earliest_thread = &threads[i]; ++ } ++ } ++ ++ /* Wait for status change or timeout */ ++ if (earliest_ts) { ++ deadline_ts = *earliest_ts; ++ rc = _main_wait_timed(task, &deadline_ts); ++ } else { ++ rc = _main_wait(task); ++ } ++ ++ if (rc == 0) ++ continue; ++ if (rc != ETIMEDOUT) { ++ mwarnx("Cannot wait for status change: %s", ++ strerror(rc)); ++ _SET_ABORTED(task); ++ break; ++ } ++ ++ /* Timeout handling */ ++ if (earliest_thread) { ++ /* Per-file timeout, restart */ ++ _timeout_thread(earliest_thread); ++ rc = 0; ++ } else { ++ /* Global timeout, abort */ ++ mwarnx("Operation timed out after %d second%s - " ++ "aborting", earliest_timeout, ++ earliest_timeout > 1 ? "s" : ""); ++ _SET_ABORTED(task); ++ break; ++ } ++ } ++ ++ if (task->aborted) ++ DBG("aborted"); ++ else ++ DBG("all work done"); ++ _worker_wakeup_all(task); ++ ++ /* Allow jobs to finish */ ++ set_timespec(&deadline_ts, 0, NSEC_PER_SEC / 4); ++ while (!task->aborted && num_jobs_running(task, threads) > 0) { ++ DBG("waiting for %lu processes", ++ num_jobs_running(task, threads)); ++ ++ if (_main_wait_timed(task, &deadline_ts)) ++ break; ++ } ++ ++ main_unlock(task); ++ ++ return rc; ++} ++ ++/* Finalize output stream */ ++static void close_output(struct task *task) ++{ ++#ifdef HAVE_ZLIB ++ if (task->opts->gzip) { ++ gzclose(task->output_gzfd); ++ return; ++ } ++#endif /* HAVE_ZLIB */ ++ ++ if (task->output_fd != STDOUT_FILENO) ++ close(task->output_fd); ++} ++ ++/* Start multi-threaded processing of job queue */ ++static int process_queue_threaded(struct task *task) ++{ ++ struct per_thread *threads, *thread; ++ int rc; ++ long i; ++ ++ tverb("Using %ld threads\n", task->opts->jobs); ++ threads = mcalloc(sizeof(struct per_thread), task->opts->jobs); ++ ++ rc = 0; ++ for (i = 0; i < task->opts->jobs; i++) { ++ init_thread(&threads[i], task, i); ++ rc = start_worker_thread(&threads[i]); ++ if (rc) ++ break; ++ } ++ ++ if (!rc) ++ wait_for_completion(task, threads); ++ ++ DBG("thread cleanup"); ++ for (i = 0; i < task->opts->jobs; i++) { ++ thread = &threads[i]; ++ if (thread->running) { ++ DBG("cancel %p", thread->thread); ++ pthread_cancel(thread->thread); ++ } ++ DBG("join %p", thread->thread); ++ pthread_join(thread->thread, NULL); ++ add_stats(&task->stats, &thread->stats); ++ cleanup_thread(thread); ++ } ++ ++ free(threads); ++ ++ return rc; ++} ++ ++/* Abort any remaining queued jobs and account to @stats */ ++static void abort_queued_jobs(struct task *task) ++{ ++ struct job *job; ++ ++ while ((job = _dequeue_job(task))) { ++ DBG("aborting job %s", job->inname); ++ task->stats.num_failed++; ++ job->status = JOB_FAILED; ++ _complete_job(task, job); ++ } ++} ++ ++/* Print a summary line */ ++static void print_summary(struct task *task) ++{ ++ char msg[MSG_LEN]; ++ size_t off = 0; ++ int rc; ++ struct stats *stats = &task->stats; ++ struct timespec end_ts; ++ int num_special; ++ unsigned long num_added; ++ ++ if (task->opts->quiet) ++ return; ++ set_timespec(&end_ts, 0, 0); ++ ++ num_special = 0; ++ num_special += stats->num_partial > 0 ? 1 : 0; ++ num_special += stats->num_excluded > 0 ? 1 : 0; ++ num_special += stats->num_failed > 0 ? 1 : 0; ++ ++ num_added = stats->num_done; ++ if (task->opts->ignore_failed_read) ++ num_added += stats->num_partial + stats->num_failed; ++ ++ rc = snprintf(&msg[off], MSG_LEN - off, "Dumped %lu entries ", ++ num_added); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ if (num_special > 0) { ++ rc = snprintf(&msg[off], MSG_LEN - off, "("); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ if (stats->num_partial > 0) { ++ rc = snprintf(&msg[off], MSG_LEN - off, "%lu partial", ++ stats->num_partial); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ if (--num_special > 0) { ++ rc = snprintf(&msg[off], MSG_LEN - off, ", "); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ } ++ if (stats->num_excluded > 0) { ++ rc = snprintf(&msg[off], MSG_LEN - off, "%lu excluded", ++ stats->num_excluded); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ if (--num_special > 0) { ++ rc = snprintf(&msg[off], MSG_LEN - off, ", "); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ } ++ if (stats->num_failed > 0) { ++ rc = snprintf(&msg[off], MSG_LEN - off, "%lu failed", ++ stats->num_failed); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ rc = snprintf(&msg[off], MSG_LEN - off, ") "); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ ++ rc = snprintf(&msg[off], MSG_LEN - off, "in "); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ snprintf_duration(&msg[off], MSG_LEN - off, &task->start_ts, &end_ts); ++ ++out: ++ info("%s\n", msg); ++} ++ ++static int init_task(struct task *task, struct dump_opts *opts) ++{ ++ pthread_condattr_t attr; ++ ++ memset(task, 0, sizeof(struct task)); ++ set_timespec(&task->start_ts, 0, 0); ++ task->opts = opts; ++ pthread_mutex_init(&task->mutex, NULL); ++ pthread_mutex_init(&task->output_mutex, NULL); ++ pthread_cond_init(&task->worker_cond, NULL); ++ ++ pthread_condattr_init(&attr); ++ if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) || ++ pthread_cond_init(&task->cond, &attr)) { ++ mwarn("Could not adjust pthread clock"); ++ return EXIT_RUNTIME; ++ } ++ ++ return EXIT_OK; ++} ++ ++struct dump_opts *dump_opts_new(void) ++{ ++ struct dump_opts *opts = mmalloc(sizeof(struct dump_opts)); ++ ++ opts->recursive = true; ++ opts->read_chunk_size = DEFAULT_READ_CHUNK_SIZE; ++ opts->max_buffer_size = DEFAULT_MAX_BUFFER_SIZE; ++ ++ return opts; ++} ++ ++void dump_opts_free(struct dump_opts *opts) ++{ ++ unsigned int i; ++ ++ if (!opts) ++ return; ++ ++ free_strarray(&opts->exclude); ++ for (i = 0; i < opts->num_specs; i++) { ++ free(opts->specs[i].inname); ++ free(opts->specs[i].outname); ++ } ++ free(opts->specs); ++ free(opts); ++} ++ ++void dump_opts_print(struct dump_opts *opts) ++{ ++ unsigned int i; ++ ++ printf("DEBUG: dump_opts at %p\n", opts); ++ if (!opts) ++ return; ++ printf("DEBUG: add_cmd_status=%d\n", opts->add_cmd_status); ++ printf("DEBUG: append=%d\n", opts->append); ++ printf("DEBUG: dereference=%d\n", opts->dereference); ++ for (i = 0; i < NUM_EXCLUDE_TYPES; i++) ++ printf("DEBUG: exclude_type[%d]=%d\n", i, ++ opts->exclude_type[i]); ++ printf("DEBUG: gzip=%d\n", opts->gzip); ++ printf("DEBUG: ignore_failed_read=%d\n", opts->ignore_failed_read); ++ printf("DEBUG: no_eof=%d\n", opts->no_eof); ++ printf("DEBUG: quiet=%d\n", opts->quiet); ++ printf("DEBUG: recursive=%d\n", opts->recursive); ++ printf("DEBUG: threaded=%d\n", opts->threaded); ++ printf("DEBUG: verbose=%d\n", opts->verbose); ++ printf("DEBUG: output_file=%s\n", opts->output_file); ++ printf("DEBUG: file_timeout=%d\n", opts->file_timeout); ++ printf("DEBUG: timeout=%d\n", opts->timeout); ++ printf("DEBUG: jobs=%ld\n", opts->jobs); ++ printf("DEBUG: jobs_per_cpu=%ld\n", opts->jobs_per_cpu); ++ printf("DEBUG: file_max_size=%zu\n", opts->file_max_size); ++ printf("DEBUG: max_buffer_size=%zu\n", opts->max_buffer_size); ++ printf("DEBUG: max_size=%zu\n", opts->max_size); ++ printf("DEBUG: read_chunk_size=%zu\n", opts->read_chunk_size); ++ for (i = 0; i < opts->exclude.num; i++) ++ printf("DEBUG: exclude[%d]=%s\n", i, opts->exclude.str[i]); ++ for (i = 0; i < opts->num_specs; i++) { ++ printf("DEBUG: specs[%d]:\n", i); ++ printf("DEBUG: inname=%s\n", opts->specs[i].inname); ++ printf("DEBUG: outname=%s\n", opts->specs[i].outname); ++ printf("DEBUG: is_cmd=%d\n", opts->specs[i].is_cmd); ++ } ++} ++ ++/* Mark file type associated with character @c as excluded */ ++int dump_opts_set_type_excluded(struct dump_opts *opts, char c) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_EXCLUDE_TYPES; i++) { ++ if (exclude_types[i].c == c) { ++ opts->exclude_type[i] = true; ++ return 0; ++ } ++ } ++ return -1; ++} ++ ++/* Add entry specification defined by @iname, @outname and @op to @opts. */ ++void dump_opts_add_spec(struct dump_opts *opts, char *inname, char *outname, ++ bool is_cmd) ++{ ++ unsigned int i = opts->num_specs; ++ ++ opts->specs = mrealloc(opts->specs, (i + 1) * sizeof(struct dump_spec)); ++ opts->specs[i].inname = mstrdup(inname); ++ if (outname) ++ opts->specs[i].outname = mstrdup(outname); ++ else ++ opts->specs[i].outname = NULL; ++ opts->specs[i].is_cmd = is_cmd; ++ opts->num_specs++; ++} ++ ++int dump_to_tar(struct dump_opts *opts) ++{ ++ struct task task; ++ int rc; ++ long num_cpus; ++ ++ if (opts->jobs_per_cpu > 0) { ++ num_cpus = sysconf(_SC_NPROCESSORS_ONLN); ++ if (num_cpus < 1) { ++ mwarn("Cannot determine number of CPUs - assuming 1 " ++ "CPU"); ++ num_cpus = 1; ++ } ++ opts->jobs = num_cpus; ++ } ++ ++ if (opts->jobs == 0 && (opts->timeout > 0 || opts->file_timeout > 0)) { ++ /* Separate thread needed to implement timeout via cancel */ ++ opts->jobs = 1; ++ } ++ ++ rc = init_task(&task, opts); ++ if (rc) ++ return rc; ++ ++ /* Queue initial job */ ++ init_queue(&task); ++ ++ /* Process queue */ ++ if (opts->jobs > 0) ++ rc = process_queue_threaded(&task); ++ else ++ rc = process_queue(&task); ++ abort_queued_jobs(&task); ++ ++ if (task.output_num_files > 0 && !opts->no_eof) ++ write_eof(&task); ++ ++ print_summary(&task); ++ ++ close_output(&task); ++ ++ if (rc == 0 && task.aborted) ++ rc = EXIT_RUNTIME; ++ ++ return rc; ++} +--- /dev/null ++++ b/dump2tar/src/dump2tar.c +@@ -0,0 +1,474 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Command line interface ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dump.h" ++#include "global.h" ++#include "idcache.h" ++#include "misc.h" ++#include "strarray.h" ++#include "util_opt.h" ++#include "util_prg.h" ++ ++#define MIN_BUFFER_SIZE 4096 ++ ++#define OPT_NOSHORT_BASE 256 ++ ++#define OPT_DEREFERENCE (OPT_NOSHORT_BASE + 0) ++#define OPT_NORECURSION (OPT_NOSHORT_BASE + 1) ++#define OPT_EXCLUDETYPE (OPT_NOSHORT_BASE + 2) ++ ++/* Program description */ ++static const struct util_prg dump2tar_prg = { ++ .desc = "Use dump2tar to create a tar archive from the contents " ++ "of arbitrary files.\nIt works even when the size of actual " ++ "file content is not known beforehand,\nsuch as with FIFOs, " ++ "character devices or certain Linux debugfs or sysfs files.\n" ++ "\nYou can also add files under different names and add " ++ "command output using the\nformat described in section SPECS " ++ "below. When no additional options are\nspecified, the " ++ "resulting archive is written to the standard output stream\n" ++ "in uncompressed tar format.", ++ .args = "SPECS", ++ .copyright_vec = { ++ { "IBM Corp.", 2016, 2016 }, ++ UTIL_PRG_COPYRIGHT_END ++ }, ++}; ++ ++/* Definition of command line options */ ++static struct util_opt dump2tar_opts[] = { ++ UTIL_OPT_SECTION("OUTPUT OPTIONS"), ++ { ++ .option = { "output-file", required_argument, NULL, 'o' }, ++ .argument = "FILE", ++ .desc = "Write archive to FILE (default: standard output)", ++ }, ++#ifdef HAVE_ZLIB ++ { ++ .option = { "gzip", no_argument, NULL, 'z' }, ++ .desc = "Write a gzip compressed archive", ++ }, ++#endif /* HAVE_ZLIB */ ++ { ++ .option = { "max-size", required_argument, NULL, 'm' }, ++ .argument = "N", ++ .desc = "Stop adding files when archive size exceeds N bytes", ++ }, ++ { ++ .option = { "timeout", required_argument, NULL, 't' }, ++ .argument = "SEC", ++ .desc = "Stop adding files after SEC seconds", ++ }, ++ { ++ .option = { "no-eof", no_argument, NULL, 131 }, ++ .desc = "Do not write an end-of-file marker", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ { ++ .option = { "add-cmd-status", no_argument, NULL, 132 }, ++ .desc = "Add status of commands as separate file", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ { ++ .option = { "append", no_argument, NULL, 133 }, ++ .desc = "Append output to end of file", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ ++ UTIL_OPT_SECTION("INPUT OPTIONS"), ++ { ++ .option = { "files-from", required_argument, NULL, 'F' }, ++ .argument = "FILE", ++ .desc = "Read filenames from FILE (- for standard input)", ++ }, ++ { ++ .option = { "ignore-failed-read", no_argument, NULL, 'i' }, ++ .desc = "Continue after read errors", ++ }, ++ { ++ .option = { "buffer-size", required_argument, NULL, 'b' }, ++ .argument = "N", ++ .desc = "Read data in chunks of N byte (default: 16384)", ++ }, ++ { ++ .option = { "file-timeout", required_argument, NULL, 'T' }, ++ .desc = "Stop reading file after SEC seconds", ++ }, ++ { ++ .option = { "file-max-size", required_argument, NULL, 'M' }, ++ .argument = "N", ++ .desc = "Stop reading file after N bytes", ++ }, ++ { ++ .option = { "jobs", required_argument, NULL, 'j' }, ++ .argument = "N", ++ .desc = "Read N files in parallel (default: 1)", ++ }, ++ { ++ .option = { "jobs-per-cpu", required_argument, NULL, 'J' }, ++ .argument = "N", ++ .desc = "Read N files per CPU in parallel", ++ }, ++ { ++ .option = { "exclude", required_argument, NULL, 'x' }, ++ .argument = "PATTERN", ++ .desc = "Don't add files matching PATTERN", ++ }, ++ { ++ .option = { "exclude-from", required_argument, NULL, 'X' }, ++ .argument = "FILE", ++ .desc = "Don't add files matching patterns in FILE", ++ }, ++ { ++ .option = { "exclude-type", required_argument, NULL, ++ OPT_EXCLUDETYPE }, ++ .argument = "TYPE", ++ .desc = "Don't add files of specified TYPE (one of: fdcbpls)", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ { ++ .option = { "dereference", no_argument, NULL, OPT_DEREFERENCE }, ++ .desc = "Add link targets instead of links", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ { ++ .option = { "no-recursion", no_argument, NULL, ++ OPT_NORECURSION }, ++ .desc = "Don't add files from sub-directories", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ ++ UTIL_OPT_SECTION("MISC OPTIONS"), ++ UTIL_OPT_HELP, ++ UTIL_OPT_VERSION, ++ { ++ .option = { "verbose", no_argument, NULL, 'V' }, ++ .desc = "Print additional informational output", ++ }, ++ { ++ .option = { "quiet", no_argument, NULL, 'q' }, ++ .desc = "Suppress printing of informational output", ++ }, ++ UTIL_OPT_END, ++}; ++ ++/* Split buffer size specification in @arg into two numbers to be stored in ++ * @from_ptr and @to_ptr. Return %EXIT_OK on success. */ ++static int parse_buffer_size(char *arg, size_t *from_ptr, size_t *to_ptr) ++{ ++ char *err; ++ unsigned long from, to; ++ ++ if (!*arg) { ++ mwarnx("Empty buffer size specified"); ++ return EXIT_USAGE; ++ } ++ ++ from = strtoul(arg, &err, 10); ++ ++ if (*err == '-') ++ to = strtoul(err + 1, &err, 10); ++ else ++ to = *to_ptr; ++ ++ if (*err) { ++ mwarnx("Invalid buffer size: %s", arg); ++ return EXIT_USAGE; ++ } ++ ++ if (from < MIN_BUFFER_SIZE || to < MIN_BUFFER_SIZE) { ++ mwarnx("Buffer size too low (minimum %u)", MIN_BUFFER_SIZE); ++ return EXIT_USAGE; ++ } ++ ++ if (to < from) ++ to = from; ++ ++ *from_ptr = from; ++ *to_ptr = to; ++ ++ return EXIT_OK; ++} ++ ++static void parse_and_add_spec(struct dump_opts *opts, const char *spec) ++{ ++ char *op, *s, *inname, *outname = NULL; ++ bool is_cmd = false; ++ ++ s = mstrdup(spec); ++ op = strstr(s, "|="); ++ if (op) ++ is_cmd = true; ++ else ++ op = strstr(s, ":="); ++ ++ if (op) { ++ *op = 0; ++ inname = op + 2; ++ outname = s; ++ } else { ++ inname = s; ++ } ++ dump_opts_add_spec(opts, inname, outname, is_cmd); ++ free(s); ++} ++ ++static int add_specs_from_file(struct dump_opts *opts, const char *filename) ++{ ++ FILE *fd; ++ char *line = NULL; ++ size_t line_size; ++ int rc = EXIT_RUNTIME; ++ bool need_close = false, parse_spec = true; ++ ++ if (strcmp(filename, "-") == 0) ++ fd = stdin; ++ else { ++ fd = fopen(filename, "r"); ++ if (!fd) { ++ mwarn("%s: Cannot open file", filename); ++ goto out; ++ } ++ need_close = true; ++ } ++ ++ while ((getline(&line, &line_size, fd) != -1)) { ++ chomp(line, "\n"); ++ if (line[0] == 0) ++ continue; ++ if (parse_spec && strcmp(line, "--") == 0) { ++ /* After a line containing --, no more := or |= specs ++ * are expected */ ++ parse_spec = false; ++ continue; ++ } ++ if (parse_spec) ++ parse_and_add_spec(opts, line); ++ else ++ dump_opts_add_spec(opts, line, NULL, false); ++ } ++ ++ if (ferror(fd)) ++ mwarn("%s: Cannot read file", filename); ++ else ++ rc = EXIT_OK; ++ ++out: ++ if (need_close) ++ fclose(fd); ++ free(line); ++ ++ return rc; ++} ++ ++static void print_help(void) ++{ ++ static const struct { ++ const char *name; ++ const char *desc; ++ } specs[] = { ++ { "PATH", "Add file or directory at PATH" }, ++ { "NEWPATH:=PATH", "Add file or directory at PATH as NEWPATH" }, ++ { "NEWPATH|=CMDLINE", "Add output of command line CMDLINE as " ++ "NEWPATH" }, ++ { NULL, NULL }, ++ }; ++ int i; ++ ++ util_prg_print_help(); ++ printf("SPECS\n"); ++ for (i = 0; specs[i].name; i++) ++ util_opt_print_indented(specs[i].name, specs[i].desc); ++ printf("\n"); ++ util_opt_print_help(); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int rc = EXIT_USAGE, opt; ++ long i; ++ struct dump_opts *opts; ++ ++ if (getenv("DUMP2TAR_DEBUG")) ++ global_debug = true; ++ ++ util_prg_init(&dump2tar_prg); ++ util_opt_init(dump2tar_opts, "-"); ++ misc_init(); ++ ++ opts = dump_opts_new(); ++ opterr = 0; ++ while ((opt = util_opt_getopt_long(argc, argv)) != -1) { ++ switch (opt) { ++ case 'h': /* --help */ ++ print_help(); ++ rc = EXIT_OK; ++ goto out; ++ case 'v': /* --version */ ++ util_prg_print_version(); ++ rc = EXIT_OK; ++ goto out; ++ case 'V': /* --verbose */ ++ global_verbose = true; ++ global_quiet = false; ++ opts->verbose = true; ++ opts->quiet = false; ++ break; ++ case 'q': /* --quiet */ ++ global_quiet = true; ++ global_verbose = false; ++ opts->quiet = true; ++ opts->verbose = false; ++ break; ++ case 'i': /* --ignore-failed-read */ ++ opts->ignore_failed_read = true; ++ break; ++ case 'j': /* --jobs N */ ++ opts->jobs = atoi(optarg); ++ if (opts->jobs < 1) { ++ mwarnx("Invalid number of jobs: %s", optarg); ++ goto out; ++ } ++ break; ++ case 'J': /* --jobs-per-cpu N */ ++ opts->jobs_per_cpu = atoi(optarg); ++ if (opts->jobs_per_cpu < 1) { ++ mwarnx("Invalid number of jobs: %s", optarg); ++ goto out; ++ } ++ break; ++ case 'b': /* --buffer-size N */ ++ if (parse_buffer_size(optarg, &opts->read_chunk_size, ++ &opts->max_buffer_size)) ++ goto out; ++ break; ++ case 'x': /* --exclude PATTERN */ ++ add_str_to_strarray(&opts->exclude, optarg); ++ break; ++ case 'X': /* --exclude-from FILE */ ++ if (add_file_to_strarray(&opts->exclude, optarg)) ++ goto out; ++ break; ++ case 'F': /* --files-from FILE */ ++ if (add_specs_from_file(opts, optarg)) ++ goto out; ++ break; ++ case 'o': /* --output-file FILE */ ++ if (opts->output_file) { ++ mwarnx("Output file specified multiple times"); ++ goto out; ++ } ++ opts->output_file = optarg; ++ break; ++ case OPT_DEREFERENCE: /* --dereference */ ++ opts->dereference = true; ++ break; ++ case OPT_NORECURSION: /* --no-recursion */ ++ opts->recursive = false; ++ break; ++ case OPT_EXCLUDETYPE: /* --exclude-type TYPE */ ++ for (i = 0; optarg[i]; i++) { ++ if (dump_opts_set_type_excluded(opts, ++ optarg[i])) ++ break; ++ ++ } ++ if (optarg[i]) { ++ mwarnx("Unrecognized file type: %c", optarg[i]); ++ goto out; ++ } ++ break; ++ case 131: /* --no-eof */ ++ opts->no_eof = true; ++ break; ++ case 132: /* --add-cmd-status */ ++ opts->add_cmd_status = true; ++ break; ++ case 133: /* --append */ ++ opts->append = true; ++ break; ++ case 't': /* --timeout VALUE */ ++ opts->timeout = atoi(optarg); ++ if (opts->timeout < 1) { ++ mwarnx("Invalid timeout value: %s", optarg); ++ goto out; ++ } ++ break; ++ case 'T': /* --file-timeout VALUE */ ++ opts->file_timeout = atoi(optarg); ++ if (opts->file_timeout < 1) { ++ mwarnx("Invalid timeout value: %s", optarg); ++ goto out; ++ } ++ break; ++ case 'm': /* --max-size N */ ++ opts->max_size = atol(optarg); ++ if (opts->max_size < 2) { ++ mwarnx("Invalid maximum size: %s", optarg); ++ goto out; ++ } ++ break; ++ case 'M': /* --file-max-size N */ ++ opts->file_max_size = atol(optarg); ++ if (opts->file_max_size < 2) { ++ mwarnx("Invalid maximum size: %s", optarg); ++ goto out; ++ } ++ break; ++ case 'z': /* --gzip */ ++ opts->gzip = true; ++ break; ++ case 1: /* Filename specification or unrecognized option */ ++ if (optarg[0] == '-') { ++ mwarnx("Invalid option '%s'", optarg); ++ goto out; ++ } ++ parse_and_add_spec(opts, optarg); ++ break; ++ case '?': /* Unrecognized option */ ++ if (optopt) ++ mwarnx("Invalid option '-%c'", optopt); ++ else ++ mwarnx("Invalid option '%s'", argv[optind - 1]); ++ goto out; ++ case ':': /* Missing argument */ ++ mwarnx("Option '%s' requires an argument", ++ argv[optind - 1]); ++ goto out; ++ default: ++ break; ++ } ++ } ++ if (optind >= argc && opts->num_specs == 0) { ++ mwarnx("Please specify files to dump"); ++ goto out; ++ } ++ ++ for (i = optind; i < argc; i++) ++ dump_opts_add_spec(opts, argv[i], NULL, false); ++ ++ rc = dump_to_tar(opts); ++ ++out: ++ idcache_cleanup(); ++ misc_cleanup(); ++ dump_opts_free(opts); ++ ++ if (rc == EXIT_USAGE) ++ util_prg_print_parse_error(); ++ ++ return rc; ++} +--- /dev/null ++++ b/dump2tar/src/global.c +@@ -0,0 +1,17 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Global variables ++ * ++ * Copyright IBM Corp. 2016 ++ * ++ */ ++ ++#include "global.h" ++ ++/* Global settings */ ++bool global_threaded; ++bool global_debug; ++bool global_verbose; ++bool global_quiet; ++bool global_timestamps; +--- /dev/null ++++ b/dump2tar/src/idcache.c +@@ -0,0 +1,153 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Caches for user and group ID lookups ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include "idcache.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "global.h" ++#include "misc.h" ++ ++/* Maximum user and group name lengths as defined in tar header */ ++#define ID_NAME_MAXLEN 32 ++ ++/* Types for user and group ID caches */ ++typedef uid_t generic_id_t; /* Assumes that uid_t == gid_t */ ++ ++struct id_cache_entry { ++ generic_id_t id; ++ char name[ID_NAME_MAXLEN]; ++}; ++ ++struct id_cache { ++ unsigned int num; ++ struct id_cache_entry entries[]; ++}; ++ ++/* cache_mutex serializes access to cached uid and gid data */ ++static pthread_mutex_t id_cache_mutex = PTHREAD_MUTEX_INITIALIZER; ++static struct id_cache *id_cache_uid; ++static struct id_cache *id_cache_gid; ++ ++/* Lock cache mutex */ ++static void cache_lock(void) ++{ ++ if (!global_threaded) ++ return; ++ pthread_mutex_lock(&id_cache_mutex); ++} ++ ++/* Unlock cache mutex */ ++static void cache_unlock(void) ++{ ++ if (!global_threaded) ++ return; ++ pthread_mutex_unlock(&id_cache_mutex); ++} ++ ++/* Copy the name associated with @id in @cache to at most @len bytes at @dest. ++ * Return %true if name was found in cache, %false otherwise. */ ++static bool strncpy_id_cache_entry(char *dest, struct id_cache *cache, ++ generic_id_t id, size_t len) ++{ ++ unsigned int i; ++ bool hit = false; ++ ++ cache_lock(); ++ if (cache) { ++ for (i = 0; i < cache->num; i++) { ++ if (cache->entries[i].id == id) { ++ strncpy(dest, cache->entries[i].name, len); ++ hit = true; ++ break; ++ } ++ } ++ } ++ cache_unlock(); ++ ++ return hit; ++} ++ ++/* Add a new entry consisting of @id and @name to ID cache in @*cache_ptr. ++ * Update @cache_ptr if necessary. */ ++static void add_id_cache_entry(struct id_cache **cache_ptr, generic_id_t id, ++ char *name) ++{ ++ struct id_cache *cache; ++ unsigned int cache_num; ++ size_t new_size; ++ struct id_cache *new_cache; ++ ++ cache_lock(); ++ ++ cache = *cache_ptr; ++ cache_num = cache ? cache->num : 0; ++ new_size = sizeof(struct id_cache) + ++ sizeof(struct id_cache_entry) * (cache_num + 1); ++ new_cache = mrealloc(cache, new_size); ++ if (cache_num == 0) ++ new_cache->num = 0; ++ new_cache->entries[cache_num].id = id; ++ strncpy(new_cache->entries[cache_num].name, name, ID_NAME_MAXLEN); ++ new_cache->num++; ++ *cache_ptr = new_cache; ++ ++ cache_unlock(); ++} ++ ++/* Copy the user name corresponding to user ID @uid to at most @len bytes ++ * at @name */ ++void uid_to_name(uid_t uid, char *name, size_t len) ++{ ++ struct passwd pwd, *pwd_ptr; ++ char buffer[PWD_BUFFER_SIZE], *result; ++ ++ if (strncpy_id_cache_entry(name, id_cache_uid, uid, len)) ++ return; ++ ++ /* getpwuid() can be slow so cache results */ ++ getpwuid_r(uid, &pwd, buffer, PWD_BUFFER_SIZE, &pwd_ptr); ++ if (!pwd_ptr || !pwd_ptr->pw_name) ++ return; ++ result = pwd_ptr->pw_name; ++ ++ add_id_cache_entry(&id_cache_uid, uid, result); ++ ++ strncpy(name, result, len); ++} ++ ++/* Copy the group name corresponding to group ID @gid to at most @len bytes ++ * at @name */ ++void gid_to_name(gid_t gid, char *name, size_t len) ++{ ++ struct group grp, *grp_ptr; ++ char buffer[GRP_BUFFER_SIZE], *result; ++ ++ if (strncpy_id_cache_entry(name, id_cache_gid, gid, len)) ++ return; ++ ++ /* getgrgid() can be slow so cache results */ ++ getgrgid_r(gid, &grp, buffer, GRP_BUFFER_SIZE, &grp_ptr); ++ if (!grp_ptr || !grp_ptr->gr_name) ++ return; ++ result = grp_ptr->gr_name; ++ ++ add_id_cache_entry(&id_cache_gid, gid, result); ++ ++ strncpy(name, result, len); ++} ++ ++void idcache_cleanup(void) ++{ ++ free(id_cache_uid); ++ free(id_cache_gid); ++} +--- /dev/null ++++ b/dump2tar/src/misc.c +@@ -0,0 +1,492 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Helper functions ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#define _GNU_SOURCE /* for program_invocation_short_name */ ++ ++#include "misc.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dref.h" ++#include "global.h" ++ ++struct timespec main_start_ts; ++ ++static pthread_key_t thread_name_key; ++static bool stdout_data; ++ ++/* Write @len bytes at @addr to @fd. Return %EXIT_OK on success, %EXIT_RUNTIME ++ * otherwise. */ ++int misc_write_data(int fd, char *addr, size_t len) ++{ ++ ssize_t w; ++ ++ while (len > 0) { ++ w = write(fd, addr, len); ++ if (w < 0) ++ return EXIT_RUNTIME; ++ len -= w; ++ addr += w; ++ } ++ ++ return EXIT_OK; ++} ++ ++/* Read at most @len bytes from @fd to @addr. Return the number of bytes read ++ * or %-1 on error. */ ++ssize_t misc_read_data(int fd, char *addr, size_t len) ++{ ++ size_t done = 0; ++ ssize_t r; ++ ++ while (len > 0) { ++ r = read(fd, addr, len); ++ if (r < 0) ++ return -1; ++ if (r == 0) ++ break; ++ len -= r; ++ addr += r; ++ done += r; ++ } ++ ++ return done; ++} ++ ++/* Advance timespec @ts by @sec seconds and @nsec nanoseconds */ ++void inc_timespec(struct timespec *ts, time_t sec, long nsec) ++{ ++ ts->tv_nsec += nsec; ++ ts->tv_sec += sec; ++ if (ts->tv_nsec > NSEC_PER_SEC) { ++ ts->tv_nsec -= NSEC_PER_SEC; ++ ts->tv_sec++; ++ } ++} ++ ++/* Set timespec @ts to point to @sec seconds and @nsec nanoseconds in the ++ * future */ ++void set_timespec(struct timespec *ts, time_t sec, long nsec) ++{ ++ clock_gettime(CLOCK_MONOTONIC, ts); ++ inc_timespec(ts, sec, nsec); ++} ++ ++/* Return true if timespec @a refers to a point in time before @b */ ++bool ts_before(struct timespec *a, struct timespec *b) ++{ ++ if (a->tv_sec < b->tv_sec || ++ (a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec)) ++ return true; ++ ++ return false; ++} ++ ++/* Store a string representing the time duration between @start and @end in ++ * at most @len bytes of @buff. */ ++int snprintf_duration(char *buff, size_t len, struct timespec *start, ++ struct timespec *end) ++{ ++ time_t sec; ++ long nsec, msec, s, m, h; ++ ++ sec = end->tv_sec - start->tv_sec; ++ nsec = end->tv_nsec - start->tv_nsec; ++ ++ if (nsec < 0) { ++ nsec += NSEC_PER_SEC; ++ sec--; ++ } ++ ++ msec = nsec / NSEC_PER_MSEC; ++ s = sec % 60; ++ sec /= 60; ++ m = sec % 60; ++ sec /= 60; ++ h = sec; ++ ++ if (h > 0) ++ return snprintf(buff, len, "%luh%lum%lu.%03lus", h, m, s, msec); ++ else if (m > 0) ++ return snprintf(buff, len, "%lum%lu.%03lus", m, s, msec); ++ else ++ return snprintf(buff, len, "%lu.%03lus", s, msec); ++} ++ ++/* Return the name of the current thread */ ++char *get_threadname(void) ++{ ++ return pthread_getspecific(thread_name_key); ++} ++ ++static int snprintf_timestamp(char *str, size_t size) ++{ ++ struct timespec now_ts; ++ ++ set_timespec(&now_ts, 0, 0); ++ now_ts.tv_sec -= main_start_ts.tv_sec; ++ now_ts.tv_nsec -= main_start_ts.tv_nsec; ++ if (now_ts.tv_nsec < 0) { ++ now_ts.tv_nsec += NSEC_PER_SEC; ++ now_ts.tv_sec--; ++ } ++ ++ return snprintf(str, size, "[%3lu.%06lu] ", now_ts.tv_sec, ++ now_ts.tv_nsec / NSEC_PER_USEC); ++} ++ ++/* When DUMP2TAR_DEBUG is set to non-zero, print debugging information */ ++void debug(const char *file, unsigned long line, const char *format, ...) ++{ ++ char msg[MSG_LEN]; ++ size_t off = 0; ++ int rc; ++ va_list args; ++ ++ /* Debug marker */ ++ rc = snprintf(&msg[off], MSG_LEN - off, "DEBUG: "); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ /* Timestamp */ ++ rc = snprintf_timestamp(&msg[off], MSG_LEN - off); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ /* Thread name */ ++ rc = snprintf(&msg[off], MSG_LEN - off, "%s: ", get_threadname()); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ /* Message */ ++ va_start(args, format); ++ rc = vsnprintf(&msg[off], MSG_LEN - off, format, args); ++ va_end(args); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ /* Call site */ ++ rc = snprintf(&msg[off], MSG_LEN - off, " (%s:%lu)", file, line); ++ ++out: ++ fprintf(stderr, "%s\n", msg); ++} ++ ++/* Print a warning message consisting of @format and variable arguments. ++ * If @print_errno is true, also print the text corresponding to errno. ++ * We're not using err.h's warn since we want timestamps and synchronized ++ * output. */ ++void _mwarn(bool print_errno, const char *format, ...) ++{ ++ char msg[MSG_LEN]; ++ size_t off = 0; ++ int rc; ++ va_list args; ++ ++ if (global_timestamps) { ++ rc = snprintf_timestamp(&msg[off], MSG_LEN - off); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ ++ rc = snprintf(&msg[off], MSG_LEN - off, "%s: ", ++ program_invocation_short_name); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ va_start(args, format); ++ rc = vsnprintf(&msg[off], MSG_LEN - off, format, args); ++ va_end(args); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ ++ if (print_errno) ++ snprintf(&msg[off], MSG_LEN - off, ": %s", strerror(errno)); ++ ++out: ++ fprintf(stderr, "%s\n", msg); ++} ++ ++/* Provide informational output if --verbose was specified */ ++void verb(const char *format, ...) ++{ ++ char msg[MSG_LEN]; ++ size_t off = 0; ++ int rc; ++ va_list args; ++ FILE *fd; ++ ++ if (!global_verbose) ++ return; ++ if (stdout_data) ++ fd = stderr; ++ else ++ fd = stdout; ++ if (global_timestamps) { ++ rc = snprintf_timestamp(&msg[off], MSG_LEN - off); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ ++ va_start(args, format); ++ rc = vsnprintf(&msg[off], MSG_LEN - off, format, args); ++ va_end(args); ++ ++out: ++ fprintf(fd, "%s", msg); ++} ++ ++/* Provide informational output. */ ++void info(const char *format, ...) ++{ ++ char msg[MSG_LEN]; ++ size_t off = 0; ++ int rc; ++ va_list args; ++ FILE *fd; ++ ++ if (global_quiet) ++ return; ++ if (stdout_data) ++ fd = stderr; ++ else ++ fd = stdout; ++ ++ if (global_timestamps) { ++ rc = snprintf_timestamp(&msg[off], MSG_LEN - off); ++ HANDLE_RC(rc, MSG_LEN, off, out); ++ } ++ ++ va_start(args, format); ++ rc = vsnprintf(&msg[off], MSG_LEN - off, format, args); ++ va_end(args); ++ ++out: ++ fprintf(fd, "%s", msg); ++} ++ ++/* Return a newly allocated buffer containing the result of the specified ++ * string format arguments */ ++char *__masprintf(const char *func, const char *file, int line, const char *fmt, ++ ...) ++{ ++ char *str; ++ va_list args; ++ ++ va_start(args, fmt); ++ __util_vasprintf(func, file, line, &str, fmt, args); ++ va_end(args); ++ ++ return str; ++} ++ ++/* Set the internal name of the calling thread */ ++void __set_threadname(const char *func, const char *file, int line, ++ const char *fmt, ...) ++{ ++ char *str; ++ va_list args; ++ ++ va_start(args, fmt); ++ __util_vasprintf(func, file, line, &str, fmt, args); ++ va_end(args); ++ ++ pthread_setspecific(thread_name_key, str); ++} ++ ++/* Clear any previously set thread name */ ++void clear_threadname(void) ++{ ++ void *addr = pthread_getspecific(thread_name_key); ++ ++ if (addr) { ++ pthread_setspecific(thread_name_key, NULL); ++ free(addr); ++ } ++} ++ ++/* Remove any number of trailing characters @c in @str */ ++void chomp(char *str, char *c) ++{ ++ ssize_t i; ++ ++ for (i = strlen(str) - 1; i >= 0 && strchr(c, str[i]); i--) ++ str[i] = 0; ++} ++ ++/* Remove any number of leading characters @c in @str */ ++void lchomp(char *str, char *c) ++{ ++ char *from; ++ ++ for (from = str; *from && strchr(c, *from); from++) ++ ; ++ if (str != from) ++ memmove(str, from, strlen(from) + 1); ++} ++ ++/* Perform a stat on file referenced by either @abs or @rel and @dref. Store ++ * results in @stat and return stat()'s return code. */ ++int stat_file(bool dereference, const char *abs, const char *rel, ++ struct dref *dref, struct stat *st) ++{ ++ int rc; ++ ++ if (dref) { ++ if (dereference) ++ rc = fstatat(dref->dirfd, rel, st, 0); ++ else ++ rc = fstatat(dref->dirfd, rel, st, AT_SYMLINK_NOFOLLOW); ++ } else { ++ if (dereference) ++ rc = stat(abs, st); ++ else ++ rc = lstat(abs, st); ++ } ++ ++ return rc; ++} ++ ++/* Fill stat buffer @st with dummy values. */ ++void set_dummy_stat(struct stat *st) ++{ ++ /* Fake stat */ ++ memset(st, 0, sizeof(struct stat)); ++ st->st_mode = S_IRUSR | S_IWUSR | S_IFREG; ++ st->st_uid = geteuid(); ++ st->st_gid = getegid(); ++ st->st_mtime = time(NULL); ++} ++ ++/* Redirect all output streams to @fd and execute command @CMD */ ++int cmd_child(int fd, char *cmd) ++{ ++ char *argv[] = { "/bin/sh", "-c", NULL, NULL }; ++ char *env[] = { NULL }; ++ ++ argv[2] = cmd; ++ if (dup2(fd, STDOUT_FILENO) == -1 || dup2(fd, STDERR_FILENO) == -1) { ++ mwarn("Could not redirect command output"); ++ return EXIT_RUNTIME; ++ } ++ ++ execve("/bin/sh", argv, env); ++ ++ return EXIT_RUNTIME; ++} ++ ++#define PIPE_READ 0 ++#define PIPE_WRITE 1 ++ ++/* Run command @cmd as a child process and store its PID in @pid_ptr. On ++ * success, return a file descriptor that is an output pipe to the standard ++ * output and standard error streams of the child process. Return %-1 on ++ * error. */ ++int cmd_open(char *cmd, pid_t *pid_ptr) ++{ ++ int pfd[2]; ++ pid_t pid; ++ ++ if (pipe(pfd) < 0) ++ return -1; ++ ++ pid = fork(); ++ if (pid < 0) { ++ /* Fork error */ ++ close(pfd[PIPE_READ]); ++ close(pfd[PIPE_WRITE]); ++ return -1; ++ } else if (pid == 0) { ++ /* Child process */ ++ close(pfd[PIPE_READ]); ++ exit(cmd_child(pfd[PIPE_WRITE], cmd)); ++ } ++ ++ /* Parent process */ ++ close(pfd[PIPE_WRITE]); ++ ++ *pid_ptr = pid; ++ ++ return pfd[PIPE_READ]; ++} ++ ++/* Close the file descriptor @fd and end the process with PID @pid. When ++ * not %NULL, use @status_ptr to store the resulting process status. */ ++int cmd_close(int fd, pid_t pid, int *status_ptr) ++{ ++ int status, rc = EXIT_OK; ++ ++ close(fd); ++ kill(pid, SIGQUIT); ++ if (waitpid(pid, &status, 0) == -1) { ++ status = -errno; ++ rc = EXIT_RUNTIME; ++ } ++ if (status_ptr) ++ *status_ptr = status; ++ ++ return rc; ++} ++ ++void misc_init(void) ++{ ++ set_timespec(&main_start_ts, 0, 0); ++ pthread_key_create(&thread_name_key, free); ++ set_threadname("main"); ++} ++ ++void misc_cleanup(void) ++{ ++ clear_threadname(); ++ pthread_key_delete(thread_name_key); ++} ++ ++void set_stdout_data(void) ++{ ++ stdout_data = true; ++} ++ ++bool starts_with(const char *str, const char *prefix) ++{ ++ size_t len; ++ ++ len = strlen(prefix); ++ ++ if (strncmp(str, prefix, len) == 0) ++ return true; ++ return false; ++} ++ ++bool ends_with(const char *str, const char *suffix) ++{ ++ size_t str_len, s_len; ++ ++ str_len = strlen(str); ++ s_len = strlen(suffix); ++ ++ if (str_len < s_len) ++ return false; ++ if (strcmp(str + str_len - s_len, suffix) != 0) ++ return false; ++ ++ return true; ++} ++ ++/* Remove subsequent slashes in @str */ ++void remove_double_slashes(char *str) ++{ ++ size_t i, to; ++ char last; ++ ++ last = 0; ++ for (i = 0, to = 0; str[i]; i++) { ++ if (last != '/' || str[i] != '/') ++ last = str[to++] = str[i]; ++ } ++ str[to] = 0; ++} +--- /dev/null ++++ b/dump2tar/src/strarray.c +@@ -0,0 +1,81 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * Dynamically growing string arrays ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include "strarray.h" ++ ++#include ++#include ++#include ++ ++#include "misc.h" ++ ++/* Release resources associated with string array @array */ ++void free_strarray(struct strarray *array) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < array->num; i++) ++ free(array->str[i]); ++ free(array->str); ++ array->str = NULL; ++ array->num = 0; ++} ++ ++/* Add string @str to string array @array */ ++void add_str_to_strarray(struct strarray *array, const char *str) ++{ ++ array->str = mrealloc(array->str, sizeof(char *) * (array->num + 2)); ++ array->str[array->num + 1] = NULL; ++ array->str[array->num] = mstrdup(str); ++ array->num++; ++} ++ ++/* Add string resulting from @fmt and additional arguments to @array */ ++void add_vstr_to_strarray(struct strarray *array, const char *fmt, ...) ++{ ++ va_list args; ++ char *str; ++ ++ va_start(args, fmt); ++ util_vasprintf(&str, fmt, args); ++ va_end(args); ++ ++ array->str = mrealloc(array->str, sizeof(char *) * (array->num + 2)); ++ array->str[array->num + 1] = NULL; ++ array->str[array->num] = str; ++ array->num++; ++} ++ ++/* Add all lines in file at @filename to @array */ ++int add_file_to_strarray(struct strarray *array, const char *filename) ++{ ++ FILE *fd; ++ char *line = NULL; ++ size_t line_size; ++ int rc = EXIT_OK; ++ ++ fd = fopen(filename, "r"); ++ if (!fd) { ++ mwarn("%s: Cannot open file", filename); ++ return EXIT_RUNTIME; ++ } ++ ++ while (!feof(fd) && !ferror(fd)) { ++ if (getline(&line, &line_size, fd) == -1) ++ continue; ++ chomp(line, "\n"); ++ add_str_to_strarray(array, line); ++ } ++ if (ferror(fd)) ++ rc = EXIT_RUNTIME; ++ free(line); ++ ++ fclose(fd); ++ ++ return rc; ++} +--- /dev/null ++++ b/dump2tar/src/tar.c +@@ -0,0 +1,270 @@ ++/* ++ * dump2tar - tool to dump files and command output into a tar archive ++ * ++ * TAR file generation ++ * ++ * Copyright IBM Corp. 2016 ++ */ ++ ++#include "tar.h" ++ ++#include ++#include ++ ++#include "buffer.h" ++#include "idcache.h" ++#include "misc.h" ++ ++#define LONGLINK "././@LongLink" ++#define TYPE_LONGLINK 'K' ++#define TYPE_LONGNAME 'L' ++ ++#define BLOCKSIZE 512 ++ ++/* Basic TAR header */ ++struct tar_header { ++ char name[100]; ++ char mode[8]; ++ char uid[8]; ++ char gid[8]; ++ char size[12]; ++ char mtime[12]; ++ char chksum[8]; ++ char typeflag; ++ char linkname[100]; ++ char magic[6]; ++ char version[2]; ++ char uname[32]; ++ char gname[32]; ++ char devmajor[8]; ++ char devminor[8]; ++ char prefix[155]; ++}; ++ ++/* Store the octal value of @value to at most @len bytes at @dest */ ++static void set_octal(char *dest, size_t len, unsigned long value) ++{ ++ int i; ++ ++ dest[len - 1] = 0; ++ for (i = len - 2; i >= 0; i--) { ++ dest[i] = '0' + (value & 7); ++ value >>= 3; ++ } ++} ++ ++/* Store time @value to at most @len bytes at @dest */ ++static void set_time(char *dest, size_t len, time_t value) ++{ ++ time_t max = (1ULL << (3 * (len - 1))) - 1; ++ ++ if (value >= 0 && value <= max) { ++ set_octal(dest, len, value); ++ return; ++ } ++ ++ for (; len > 0; len--) { ++ dest[len - 1] = value & 0xff; ++ value >>= 8; ++ } ++ ++ dest[0] |= 0x80; ++} ++ ++#define SET_FIELD(obj, name, value) \ ++ set_octal((obj)->name, sizeof((obj)->name), (unsigned long) (value)) ++#define SET_TIME_FIELD(obj, name, value) \ ++ set_time((obj)->name, sizeof((obj)->name), (time_t) (value)) ++#define SET_STR_FIELD(obj, name, value) \ ++ strncpy((obj)->name, (value), sizeof((obj)->name)) ++ ++/* Initialize the tar file @header with the provided data */ ++static void init_header(struct tar_header *header, const char *filename, ++ const char *link, size_t len, struct stat *stat, ++ char type) ++{ ++ unsigned int i, checksum; ++ unsigned char *c; ++ ++ memset(header, 0, sizeof(*header)); ++ ++ /* Fill in header fields */ ++ SET_STR_FIELD(header, name, filename); ++ if (link) ++ SET_STR_FIELD(header, linkname, link); ++ SET_FIELD(header, size, len); ++ if (stat) { ++ SET_FIELD(header, mode, stat->st_mode & 07777); ++ SET_FIELD(header, uid, stat->st_uid); ++ SET_FIELD(header, gid, stat->st_gid); ++ SET_TIME_FIELD(header, mtime, stat->st_mtime); ++ uid_to_name(stat->st_uid, header->uname, sizeof(header->uname)); ++ gid_to_name(stat->st_gid, header->gname, sizeof(header->gname)); ++ } else { ++ SET_FIELD(header, mode, 0644); ++ SET_FIELD(header, uid, 0); ++ SET_FIELD(header, gid, 0); ++ SET_TIME_FIELD(header, mtime, 0); ++ uid_to_name(0, header->uname, sizeof(header->uname)); ++ gid_to_name(0, header->gname, sizeof(header->gname)); ++ } ++ header->typeflag = type; ++ memcpy(header->magic, "ustar ", sizeof(header->magic)); ++ memcpy(header->version, " ", sizeof(header->version)); ++ ++ /* Calculate checksum */ ++ memset(header->chksum, ' ', sizeof(header->chksum)); ++ checksum = 0; ++ c = (unsigned char *) header; ++ for (i = 0; i < sizeof(*header); i++) ++ checksum += c[i]; ++ snprintf(header->chksum, 7, "%06o", checksum); ++} ++ ++/* Emit zero bytes via @emit_cb to pad @len to a multiple of BLOCKSIZE */ ++static int emit_padding(emit_cb_t emit_cb, void *data, size_t len) ++{ ++ size_t pad = BLOCKSIZE - len % BLOCKSIZE; ++ char zeroes[BLOCKSIZE]; ++ ++ if (len % BLOCKSIZE > 0) { ++ memset(zeroes, 0, BLOCKSIZE); ++ return emit_cb(data, zeroes, pad); ++ } ++ ++ return 0; ++} ++ ++/* Emit @len bytes at @addr via @emit_cb and pad data to BLOCKSIZE with zero ++ * bytes */ ++static int emit_data(emit_cb_t emit_cb, void *data, void *addr, size_t len) ++{ ++ int rc; ++ ++ if (len == 0) ++ return 0; ++ ++ rc = emit_cb(data, addr, len); ++ if (rc) ++ return rc; ++ return emit_padding(emit_cb, data, len); ++} ++ ++/* Emit a tar header via @emit_cb */ ++static int emit_header(emit_cb_t emit_cb, void *data, char *filename, ++ char *link, size_t len, struct stat *stat, char type) ++{ ++ struct tar_header header; ++ size_t namelen = strlen(filename); ++ size_t linklen; ++ int rc; ++ ++ /* /proc can contain unreadable links which causes tar to complain ++ * during extract - use a dummy value to handle this more gracefully */ ++ if (link && !*link) ++ link = " "; ++ ++ linklen = link ? strlen(link) : 0; ++ if (linklen > sizeof(header.linkname)) { ++ rc = emit_header(emit_cb, data, LONGLINK, NULL, linklen + 1, ++ NULL, TYPE_LONGLINK); ++ if (rc) ++ return rc; ++ rc = emit_data(emit_cb, data, link, linklen + 1); ++ if (rc) ++ return rc; ++ } ++ if (namelen > sizeof(header.name)) { ++ rc = emit_header(emit_cb, data, LONGLINK, NULL, namelen + 1, ++ NULL, TYPE_LONGNAME); ++ if (rc) ++ return rc; ++ rc = emit_data(emit_cb, data, filename, namelen + 1); ++ if (rc) ++ return rc; ++ } ++ ++ init_header(&header, filename, link, len, stat, type); ++ return emit_data(emit_cb, data, &header, sizeof(header)); ++} ++ ++struct emit_content_cb_data { ++ emit_cb_t emit_cb; ++ void *data; ++ size_t len; ++ int rc; ++}; ++ ++/* Callback for emitting a single chunk of data of a buffer */ ++static int emit_content_cb(void *data, void *addr, size_t len) ++{ ++ struct emit_content_cb_data *cb_data = data; ++ ++ if (len > cb_data->len) ++ len = cb_data->len; ++ cb_data->len -= len; ++ ++ cb_data->rc = cb_data->emit_cb(cb_data->data, addr, len); ++ ++ if (cb_data->rc || cb_data->len == 0) ++ return 1; ++ ++ return 0; ++} ++ ++/* Emit at most @len bytes of contents of @buffer via @emit_cb and pad output ++ * to BLOCKSIZE with zero bytes */ ++static int emit_content(emit_cb_t emit_cb, void *data, struct buffer *buffer, ++ size_t len) ++{ ++ struct emit_content_cb_data cb_data; ++ ++ cb_data.emit_cb = emit_cb; ++ cb_data.data = data; ++ cb_data.len = len; ++ cb_data.rc = 0; ++ buffer_iterate(buffer, emit_content_cb, &cb_data); ++ if (cb_data.rc) ++ return cb_data.rc; ++ ++ return emit_padding(emit_cb, data, buffer->total); ++} ++ ++/* Convert file meta data and content specified as @content into a ++ * stream of bytes that is reported via the @emit_cb callback. @data is ++ * passed through to the callback for arbitrary use. */ ++int tar_emit_file_from_buffer(char *filename, char *link, size_t len, ++ struct stat *stat, char type, ++ struct buffer *content, emit_cb_t emit_cb, ++ void *data) ++{ ++ int rc; ++ ++ DBG("emit tar file=%s type=%d len=%zu", filename, type, len); ++ rc = emit_header(emit_cb, data, filename, link, len, stat, type); ++ if (rc) ++ return rc; ++ if (content) ++ rc = emit_content(emit_cb, data, content, len); ++ ++ return rc; ++} ++ ++/* Convert file meta data and content specified as @addr and @len into a ++ * stream of bytes that is reported via the @emit_cb callback. @data is ++ * passed through to the callback for arbitrary use. */ ++int tar_emit_file_from_data(char *filename, char *link, size_t len, ++ struct stat *stat, char type, void *addr, ++ emit_cb_t emit_cb, void *data) ++{ ++ int rc; ++ ++ DBG("emit tar file=%s type=%d len=%zu", filename, type, len); ++ rc = emit_header(emit_cb, data, filename, link, len, stat, type); ++ if (rc) ++ return rc; ++ if (addr) ++ rc = emit_data(emit_cb, data, addr, len); ++ ++ return rc; ++} diff --git a/s390-tools-sles12sp3-dbginfo-03-dbginfo.sh-Make-use-of-sysinfo-collection-helper.patch b/s390-tools-sles12sp3-dbginfo-03-dbginfo.sh-Make-use-of-sysinfo-collection-helper.patch new file mode 100644 index 0000000..e37fd0a --- /dev/null +++ b/s390-tools-sles12sp3-dbginfo-03-dbginfo.sh-Make-use-of-sysinfo-collection-helper.patch @@ -0,0 +1,72 @@ +Subject: [PATCH] [FEAT RTL1601] dbginfo.sh: Make use of sysfs collection helper +From: Peter Oberparleiter + +Summary: dbginfo.sh: Make use of sysfs collection helper +Description: If available, use dump2tar in dbginfo.sh for sysfs + file collection to significantly speed up dbginfo.sh + processing. Example speedup on an LPAR with ~190k + sysfs files: + + Unpatched: + # time ./dbginfo.sh + real 1m19.624s + user 0m44.985s + sys 0m45.173s + + Patched: + # time ./dbginfo.sh + real 0m5.822s + user 0m4.523s + sys 0m2.636s +Upstream-ID: - +Problem-ID: RTL1601 + +Signed-off-by: Peter Oberparleiter +--- + scripts/dbginfo.sh | 33 +++++++++++++++++++++------------ + 1 file changed, 21 insertions(+), 12 deletions(-) + +--- a/scripts/dbginfo.sh ++++ b/scripts/dbginfo.sh +@@ -620,20 +620,29 @@ collect_sysfs() { + fi + fi + +- call_run_command "find /sys -print0 | sort -z | xargs -0 -n 10 ls -ld" "${OUTPUT_FILE_SYSFS}" ++ # Collect sysfs files using multiple threads (-J 1) while excluding ++ # files known to block on read (-x). Stop reading a file that takes ++ # more than 5 seconds (-T 5) such as an active ftrace buffer. ++ dump2tar /sys -z -o "${WORKPATH}/sysfs.tgz" -x '*/tracing/trace_pipe*' \ ++ -x '*/tracing/per_cpu/*' --ignore-failed-read -J 1 -T 5 + +- find /sys -noleaf -type d 2>/dev/null | while IFS= read -r dir_name; do +- mkdir -p "${WORKPATH}${dir_name}" +- done ++ if [ $? -ne 0 ] ; then ++ echo "${SCRIPTNAME}: Warning: dump2tar failed or is unavailable - falling back to slow path" ++ call_run_command "find /sys -print0 | sort -z | xargs -0 -n 10 ls -ld" "${OUTPUT_FILE_SYSFS}" + +- find /sys -noleaf -type f -perm /444\ +- -a -not -name "*trace_pipe*"\ +- 2>/dev/null | while IFS= read -r file_name; do +- echo " ${file_name}" +- if ! dd if="${file_name}" status=noxfer iflag=nonblock of="${WORKPATH}${file_name}" >/dev/null 2>&1; then +- echo "${SCRIPTNAME}: Warning: failed to copy \"${file_name}\"" +- fi +- done ++ find /sys -noleaf -type d 2>/dev/null | while IFS= read -r dir_name; do ++ mkdir -p "${WORKPATH}${dir_name}" ++ done ++ ++ find /sys -noleaf -type f -perm /444\ ++ -a -not -name "*trace_pipe*"\ ++ 2>/dev/null | while IFS= read -r file_name; do ++ echo " ${file_name}" ++ if ! dd if="${file_name}" status=noxfer iflag=nonblock of="${WORKPATH}${file_name}" >/dev/null 2>&1; then ++ echo "${SCRIPTNAME}: Warning: failed to copy \"${file_name}\"" ++ fi ++ done ++ fi + + if test ${debugfs_mounted} -eq 1; then + umount "${MOUNT_POINT_DEBUGFS}" diff --git a/s390-tools-sles12sp3-lsdasd-tunedasd-Add-channel-path-aware-erp.patch b/s390-tools-sles12sp3-lsdasd-tunedasd-Add-channel-path-aware-erp.patch new file mode 100644 index 0000000..b8a89d3 --- /dev/null +++ b/s390-tools-sles12sp3-lsdasd-tunedasd-Add-channel-path-aware-erp.patch @@ -0,0 +1,558 @@ +Subject: [PATCH] [FEAT LS1502] lsdasd/tunedasd: Add channel path aware erp +From: Stefan Haberland + +Summary: lsdasd/tunedasd: Add channel path aware erp +Description: Add tools support for channel path aware error recovery. + lsdasd shows the newly added IFCC path mask and HPF availability. + tunedasd gets an option to reset channel paths for a device. +Upstream-ID: - +Problem-ID: LS1502 + +Signed-off-by: Stefan Haberland +--- + include/dasd_sys.h | 1 + libdasd/dasd_sys.c | 94 +++++++++++++++++++++++++++++++++++++ + tunedasd/include/disk.h | 3 - + tunedasd/man/tunedasd.8 | 17 ++++++ + tunedasd/src/Makefile | 2 + tunedasd/src/disk.c | 35 ++++++++++++++ + tunedasd/src/tunedasd.c | 120 ++++++++++++++++++++++++++++-------------------- + zconf/lsdasd | 36 +++++++++++--- + 8 files changed, 251 insertions(+), 57 deletions(-) + +--- a/include/dasd_sys.h ++++ b/include/dasd_sys.h +@@ -13,5 +13,6 @@ + #include "u2s.h" + + int dasd_sys_raw_track_access(char *); ++int dasd_reset_chpid(char *, char *); + + #endif /* DASD_SYS_H */ +--- a/libdasd/dasd_sys.c ++++ b/libdasd/dasd_sys.c +@@ -6,6 +6,9 @@ + * Copyright IBM Corp. 2016 + */ + ++#include ++#include ++ + #include "dasd_sys.h" + + /** +@@ -44,3 +47,94 @@ int dasd_sys_raw_track_access(char *devn + + return (rc == 1) ? 1 : 0; + } ++ ++ ++int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask) ++{ ++ unsigned int val; ++ char path[40]; ++ int count, i; ++ FILE *fp; ++ ++ sprintf(path, "/sys/bus/ccw/devices/%s/../chpids", busid); ++ *mask = 0; ++ fp = fopen(path, "r"); ++ if (!fp) ++ return ENODEV; ++ ++ for (i = 0; i < 8; i++) { ++ count = fscanf(fp, " %x", &val); ++ if (count != 1) { ++ fclose(fp); ++ return EIO; ++ } ++ if (val == chpid) ++ *mask = 0x80 >> i; ++ } ++ fclose(fp); ++ ++ return 0; ++} ++ ++/** ++ * reset chpid ++ * ++ * The "devnode" parameter can be any valid relative or absolute path to ++ * a DASD device node, for example: ++ * ++ * - /dev/dasda ++ * - /dev/disk/by-path/ccw-0.0.bf20 ++ * ++ * @param[in] devnode Device node of interest ++ * @param[in] chpid The chpid to reset ++ * If NULL all chpids will be reset ++ * ++ * @return 0 on success, otherwise one of the following error codes: ++ * - EINVAL No valid chpid specified. ++ * - ENODEV Could not open device. ++ * - ENOENT Specified chpid not found. ++ * - EIO Other I/O error ++ * ++ */ ++int dasd_reset_chpid(char *devnode, char *chpid_char) ++{ ++ unsigned int chpid; ++ char path[41]; ++ char busid[9]; ++ int mask, rc; ++ char *endptr; ++ FILE *fp; ++ ++ if (u2s_getbusid(devnode, busid)) ++ return ENODEV; ++ ++ if (!chpid_char) { ++ sprintf(path, "/sys/bus/ccw/devices/%s/path_reset", busid); ++ fp = fopen(path, "w"); ++ if (!fp) ++ return ENODEV; ++ fprintf(fp, "%s", "all\n"); ++ fclose(fp); ++ return 0; ++ } ++ ++ errno = 0; ++ chpid = strtoul(chpid_char, &endptr, 16); ++ if (errno || (endptr && (*endptr != '\0'))) ++ return EINVAL; ++ ++ rc = dasd_get_pm_from_chpid(busid, chpid, &mask); ++ if (rc) ++ return rc; ++ if (!mask) ++ return ENOENT; ++ ++ sprintf(path, "/sys/bus/ccw/devices/%s/path_reset", busid); ++ fp = fopen(path, "w"); ++ if (!fp) ++ return ENODEV; ++ fprintf(fp, "%02x", mask); ++ fclose(fp); ++ ++ return 0; ++} +--- a/tunedasd/include/disk.h ++++ b/tunedasd/include/disk.h +@@ -27,7 +27,8 @@ int disk_release (char* device); + int disk_slock (char* device); + int disk_query_reserve_status(char* device); + int disk_profile (char* device, char* prof_item); +-int disk_reset_prof (char* device); ++int disk_reset_prof(char *device); ++int disk_reset_chpid(char *device, char *chpid); + + #endif /* not DISK_H */ + +--- a/tunedasd/man/tunedasd.8 ++++ b/tunedasd/man/tunedasd.8 +@@ -149,6 +149,18 @@ Following rows are supported: + .TP + .BR "\-R" " or " "\-\-reset_prof" + Reset profile info of device. ++.TP ++.BR "\-p" " or " "\-\-path_reset " ++Reset a channel path of a selected device. A channel path ++might be suspended due to high IFCC error rates or a High Performance ++FICON failure. Use this option to resume considering the channel path ++for I/O. ++.TP ++.BR "\-\-path_reset_all" ++Reset all channel paths of the selected device. The channel paths ++might be suspended due to high IFCC error rates or a High Performance ++FICON failure. Use this option to resume considering all defined ++channel paths for I/O. + .\" + .\".TP + .\".BR "\-o" " or " "\-\-online" +@@ -166,8 +178,13 @@ Reset profile info of device. + .br + + tunedasd -c prestage -n 1 /dev/dasdc ++ ++.br ++3. Scenario: Reset failed channel path with CHPID 45 + .br + ++ tunedasd -p 45 /dev/dasdc ++.br + .SH "SEE ALSO" + .BR dasdview (8), + .BR dasdfmt (8), +--- a/tunedasd/src/Makefile ++++ b/tunedasd/src/Makefile +@@ -5,7 +5,7 @@ includes = $(wildcard ../include/*.h) + + all: tunedasd + +-objects = tunedasd.o disk.o ++objects = tunedasd.o disk.o ../../libdasd/dasd_sys.o ../../libu2s/u2s.o + $(objects): $(includes) + + tunedasd: $(objects) +--- a/tunedasd/src/disk.c ++++ b/tunedasd/src/disk.c +@@ -9,6 +9,7 @@ + + #include "disk.h" + #include "tunedasd.h" ++#include "dasd_sys.h" + + #include + #include +@@ -682,3 +683,37 @@ disk_reset_prof (char* device) + return 0; + } + ++int disk_reset_chpid(char *device, char *chpid) ++{ ++ int rc; ++ ++ if (chpid) ++ printf("Resetting chpid %s for device <%s>...\n", chpid, ++ device); ++ else ++ printf("Resetting all chpids for device <%s>...\n", device); ++ ++ rc = dasd_reset_chpid(device, chpid); ++ switch (rc) { ++ case 0: ++ printf("Done.\n"); ++ return 0; ++ case ENODEV: ++ error_print("%s: %s", device, strerror(errno)); ++ break; ++ case EINVAL: ++ error_print("%s: Could not reset chpid %s: Invalid CHPID", ++ device, chpid); ++ break; ++ case ENOENT: ++ error_print("%s: Could not reset chpid %s: CHPID not defined for device", ++ device, chpid); ++ break; ++ default: ++ error_print("%s: Could not reset chpid %s", ++ device, chpid); ++ break; ++ } ++ ++ return -1; ++} +--- a/tunedasd/src/tunedasd.c ++++ b/tunedasd/src/tunedasd.c +@@ -34,28 +34,30 @@ static const char* usage_text[] = { + "(e.g. '/dev/dasda') or a list of devices separated by a space " + "character.", + "", +- "-h, --help Print this help, then exit", +- "-v, --version Print version information, then exit", +- "-g, --get_cache Get current storage server caching behaviour", +- "-c, --cache Define caching behavior on storage server", +- " (normal/bypass/inhibit/sequential/prestage/" +- "record)", +- "-n, --no_cyl Number of cylinders to be cached ", +- " (only valid together with --cache)", +- "-S, --reserve Reserve device", +- "-L, --release Release device", +- "-O, --slock Unconditional reserve device", +- " Note: Use with care, this breaks an existing " +- "lock", +- "-Q, --query_reserve Print reserve status of device ", +- "-P, --profile Print profile info of device", +- "-I, --prof_item Print single profile item", +- " (reqs/sects/sizes/total/totsect/start/irq/", +- " irqsect/end/queue)", +- "-R, --reset_prof Reset profile info of device" ++ "-h, --help Print this help, then exit", ++ "-v, --version Print version information, then exit", ++ "-g, --get_cache Get current storage server caching behaviour", ++ "-c, --cache Define caching behavior on storage server", ++ " (normal/bypass/inhibit/sequential/prestage/" ++ "record)", ++ "-n, --no_cyl Number of cylinders to be cached ", ++ " (only valid together with --cache)", ++ "-S, --reserve Reserve device", ++ "-L, --release Release device", ++ "-O, --slock Unconditional reserve device", ++ " Note: Use with care, this breaks an existing " ++ "lock", ++ "-Q, --query_reserve Print reserve status of device ", ++ "-P, --profile Print profile info of device", ++ "-I, --prof_item Print single profile item", ++ " (reqs/sects/sizes/total/totsect/start/irq/", ++ " irqsect/end/queue)", ++ "-R, --reset_prof Reset profile info of device", ++ "-p, --path_reset Reset channel path of a device", ++ " --path_reset_all Reset all channel paths of a device" + }; + +-#define CMD_KEYWORD_NUM 12 ++#define CMD_KEYWORD_NUM 14 + #define DEVICES_NUM 256 + + enum cmd_keyword_id { +@@ -71,6 +73,8 @@ enum cmd_keyword_id { + cmd_keyword_prof_item = 9, + cmd_keyword_reset_prof = 10, + cmd_keyword_query_reserve = 11, ++ cmd_keyword_path = 12, ++ cmd_keyword_path_all = 13, + }; + + +@@ -79,18 +83,20 @@ static const struct { + char* keyword; + enum cmd_keyword_id id; + } keyword_list[] = { +- { "help", cmd_keyword_help }, +- { "version", cmd_keyword_version }, +- { "get_cache", cmd_keyword_get_cache }, +- { "cache", cmd_keyword_cache }, +- { "no_cyl", cmd_keyword_no_cyl }, +- { "reserve", cmd_keyword_reserve }, +- { "release", cmd_keyword_release }, +- { "slock", cmd_keyword_slock }, +- { "profile", cmd_keyword_profile }, +- { "prof_item", cmd_keyword_prof_item }, +- { "reset_prof", cmd_keyword_reset_prof }, +- { "query_reserve", cmd_keyword_query_reserve } ++ { "help", cmd_keyword_help }, ++ { "version", cmd_keyword_version }, ++ { "get_cache", cmd_keyword_get_cache }, ++ { "cache", cmd_keyword_cache }, ++ { "no_cyl", cmd_keyword_no_cyl }, ++ { "reserve", cmd_keyword_reserve }, ++ { "release", cmd_keyword_release }, ++ { "slock", cmd_keyword_slock }, ++ { "profile", cmd_keyword_profile }, ++ { "prof_item", cmd_keyword_prof_item }, ++ { "reset_prof", cmd_keyword_reset_prof }, ++ { "query_reserve", cmd_keyword_query_reserve }, ++ { "path_reset", cmd_keyword_path }, ++ { "path_reset_all", cmd_keyword_path_all } + }; + + +@@ -103,22 +109,24 @@ enum cmd_key_state { + + /* Determines which combination of keywords are valid */ + enum cmd_key_state cmd_key_table[CMD_KEYWORD_NUM][CMD_KEYWORD_NUM] = { +- /* help vers get_ cach no_c rese rele sloc prof prof rese quer +- * ion cach e yl rve ase k ile _ite t_pr y_re ++ /* help vers get_ cach no_c rese rele sloc prof prof rese quer path path ++ * ion cach e yl rve ase k ile _ite t_pr y_re _all + * e m of serv + */ +- /* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv }, +- /* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, +- /* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv }, +- /* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv }, +- /* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv }, +- /* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv }, +- /* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv }, +- /* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv }, +- /* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv }, +- /* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv }, +- /* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv }, +- /* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req }, ++ /* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv }, ++ /* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, ++ /* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, ++ /* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv }, ++ /* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv }, ++ /* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv }, ++ /* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv }, ++ /* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv }, ++ /* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv }, ++ /* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv }, ++ /* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv }, ++ /* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv }, ++ /* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv }, ++ /* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req }, + }; + + struct parameter { +@@ -146,11 +154,13 @@ static struct option options[] = { + { "prof_item", required_argument, NULL, 'I'}, + { "reset_prof", no_argument, NULL, 'R'}, + { "query_reserve", no_argument, NULL, 'Q'}, ++ { "path_reset", required_argument, NULL, 'p'}, ++ { "path_reset_all", no_argument, NULL, 'A'}, + { NULL, 0, NULL, 0 } + }; + + /* Command line option abbreviations */ +-static const char option_string[] = "hvgc:n:SLOPI:RQ"; ++static const char option_string[] = "hvgc:n:SLOPI:RQp:"; + + + /* Error message string */ +@@ -348,6 +358,14 @@ get_command_line (int argc, char* argv[] + optarg); + } + break; ++ case 'p': ++ rc = store_option(&cmdline, cmd_keyword_path, ++ optarg); ++ break; ++ case 'A': ++ rc = store_option(&cmdline, cmd_keyword_path_all, ++ optarg); ++ break; + case 'S': + rc = store_option (&cmdline, cmd_keyword_reserve, + optarg); +@@ -400,7 +418,6 @@ get_command_line (int argc, char* argv[] + return 0; + } + +- + /* + * Execute the command. + */ +@@ -444,6 +461,13 @@ do_command (char* device, struct command + case cmd_keyword_query_reserve: + rc = disk_query_reserve_status(device); + break; ++ case cmd_keyword_path: ++ rc = disk_reset_chpid(device, ++ cmdline.parm[cmd_keyword_path].data); ++ break; ++ case cmd_keyword_path_all: ++ rc = disk_reset_chpid(device, NULL); ++ break; + default: + error_print ("Unknown command '%s' specified", + get_keyword_name (i)); +--- a/zconf/lsdasd ++++ b/zconf/lsdasd +@@ -368,13 +368,15 @@ function extended() + CABLEPM=0 + CUIRPM=0 + HPFPM=0 ++ IFCCPM=0 + + # additional information + read DIAG 2> /dev/null < $DEVPATH/use_diag || continue + read EER 2> /dev/null < $DEVPATH/eer_enabled || continue + read ERP 2> /dev/null < $DEVPATH/erplog || continue ++ read HPF 2> /dev/null < $DEVPATH/hpf + # in case the path_masks do not exist simply ignore it +- read OPM NPPM CABLEPM CUIRPM HPFPM 2> /dev/null < $DEVPATH/path_masks ++ read OPM NPPM CABLEPM CUIRPM HPFPM IFCCPM 2> /dev/null < $DEVPATH/path_masks + read -a C 2> /dev/null < $DEVPATH/../chpids || continue + read PIM PAM POM 2> /dev/null < $DEVPATH/../pimpampom || continue + +@@ -385,6 +387,7 @@ function extended() + CABLEPM=0x$CABLEPM + CUIRPM=0x$CUIRPM + HPFPM=0x$HPFPM ++ IFCCPM=0x$IFCCPM + + #-----------------------------------------------------------# + # aggregate chpids and path mask to useful information # +@@ -397,6 +400,7 @@ function extended() + CUIR_PATHS=(" " " " " " " " " " " " " " " ") + CABLE_PATHS=(" " " " " " " " " " " " " " " ") + HPF_PATHS=(" " " " " " " " " " " " " " " ") ++ IFCC_PATHS=(" " " " " " " " " " " " " " " ") + + # installed paths + j=0 +@@ -470,13 +474,25 @@ function extended() + (( mask>>=1 )) + done + ++ # IFCC unusable paths ++ j=0 ++ mask=0x80 ++ for (( i=0; i<8; i++ )) ;do ++ PM=$(($IFCCPM&$mask)) ++ if [ $PM -gt 0 ] ;then ++ IFCC_PATHS[j]=${C[$i]} ; ++ ((j++)) ; ++ fi ++ (( mask>>=1 )) ++ done ++ + #-------------------------------------------# + # format data for output # + #-------------------------------------------# + + if [[ "$ONLINE" == 0 ]]; then + ACTIVE="offline" +- printf "%s:%s:%s# status:\t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s#\n" \ ++ printf "%s:%s:%s# status:\t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \ + "$SORTKEYLEN" "$SORTKEY" \ + "$BUSID" \ + "$ACTIVE" \ +@@ -484,18 +500,20 @@ function extended() + "$READONLY" \ + "$EER" \ + "$ERP" \ ++ "$HPF" \ + "$DEV_UID" \ + "${INSTALLED_PATHS[@]}" \ + "${USED_PATHS[@]}" \ + "${NP_PATHS[@]}" \ + "${CABLE_PATHS[@]}" \ + "${CUIR_PATHS[@]}" \ +- "${HPF_PATHS[@]}" ; ++ "${HPF_PATHS[@]}" \ ++ "${IFCC_PATHS[@]}" ; + continue + elif [[ "$ALIAS" == 1 ]]; then + if [[ "$BASEONLY" == "false" ]]; then + ACTIVE="alias" +- printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s # uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s#\n" \ ++ printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \ + "$SORTKEYLEN" "$SORTKEY" \ + "$BUSID" \ + "$ACTIVE" \ +@@ -504,13 +522,15 @@ function extended() + "$READONLY" \ + "$EER" \ + "$ERP" \ ++ "$HPF" \ + "$DEV_UID" \ + "${INSTALLED_PATHS[@]}" \ + "${USED_PATHS[@]}" \ + "${NP_PATHS[@]}" \ + "${CABLE_PATHS[@]}" \ + "${CUIR_PATHS[@]}" \ +- "${HPF_PATHS[@]}" ; ++ "${HPF_PATHS[@]}" \ ++ "${IFCC_PATHS[@]}" ; + continue + else + continue +@@ -533,7 +553,7 @@ function extended() + COLON=":" + fi + +- printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s#\n" \ ++ printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \ + "$SORTKEYLEN" "$SORTKEY" \ + "$BUSID" \ + "$BLOCKNAME" \ +@@ -549,13 +569,15 @@ function extended() + "$READONLY" \ + "$EER" \ + "$ERP" \ ++ "$HPF" \ + "$DEV_UID" \ + "${INSTALLED_PATHS[@]}" \ + "${USED_PATHS[@]}" \ + "${NP_PATHS[@]}" \ + "${CABLE_PATHS[@]}" \ + "${CUIR_PATHS[@]}" \ +- "${HPF_PATHS[@]}" ; ++ "${HPF_PATHS[@]}" \ ++ "${IFCC_PATHS[@]}" ; + } + + function host() diff --git a/s390-tools-sles12sp3-util_proc-fix-memory-allocation-error-messages.patch b/s390-tools-sles12sp3-util_proc-fix-memory-allocation-error-messages.patch new file mode 100644 index 0000000..8b19b8a --- /dev/null +++ b/s390-tools-sles12sp3-util_proc-fix-memory-allocation-error-messages.patch @@ -0,0 +1,30 @@ +util_proc: Fix memory allocation error messages + +Signed-off-by: Michael Holzheu +--- + libutil/util_proc.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/libutil/util_proc.c ++++ b/libutil/util_proc.c +@@ -54,8 +54,7 @@ util_proc_read_special_file(const char * + count = 0; + data = (char *) malloc(current_size); + if (data == NULL) { +- printf("Could not allocate %lld bytes of memory", +- (unsigned long long) size); ++ printf("Could not allocate %zu bytes of memory", current_size); + fclose(file); + return -1; + } +@@ -69,8 +68,8 @@ util_proc_read_special_file(const char * + if (count >= current_size) { + new_data = (char *) malloc(current_size * 2); + if (new_data == NULL) { +- printf("Could not allocate %lld bytes of memory", +- (unsigned long long) size); ++ printf("Could not allocate %zu bytes of memory", ++ current_size * 2); + free(data); + fclose(file); + return -1; diff --git a/s390-tools-zdsfs.caution.txt b/s390-tools-zdsfs.caution.txt new file mode 100644 index 0000000..8c5681d --- /dev/null +++ b/s390-tools-zdsfs.caution.txt @@ -0,0 +1,19 @@ +We strongly recommend that you get your z/OS support teams involved before installing this package. + +The zdsfs command is a new feature provided by IBM with the s390-tools package in SLES12. The zdsfs command allows Linux systems to mount z/OS DASD volumes as a Linux file system. The zdsfs file system translates the z/OS data sets into Linux semantics. + +Through the zdsfs file system, applications on Linux can read z/OS physical sequential data sets (PS) and partitioned data sets (PDS) on the DASD. If implemented improperly, or without the knowledge and cooperation of the systems programmers and information security professionals responsible for the z/OS system, the zdsfs command represents a potentially very serious security and data integrity exposure. + +There are a number of factors to consider if you choose to install this package. A necessarily incomplete list of these would be: +- Through the zdsfs file system, whole DASD volumes are accessible to Linux +- This access is not controlled or detectable by any z/OS security or auditing mechanisms. +- This access is not controlled by any z/OS "locking" facility such as provided by ENQ, GRS, etc. +- To avoid data inconsistencies, ensure the DASD volumes are offline to z/OS before you mount them in Linux. +- To minimize security problems, you should dedicate the z/OS DASD volumes for the sole purpose of providing data to Linux. +- To share z/OS data with Linux, copy it to a dataset on that separate volume. +- Because the datasets will be accessed outside of z/OS, they will appear to have never been read after creation. +- You should ensure the datasets that Linux is to access are on a separate volume that is not used for automatic dataset allocation and that is not under System Managed Storage (SMS) control. This prevents dataset migration since they will appear to never be used (except when you update them), and it avoids unaudited access to datasets that are not intended for access by the Linux server. +- When running Linux native in an LPAR, ensure that the LPAR has access only to the specific z/OS volumes that contain the data to be accessed by Linux. +- By default, only the Linux user who mounts the zdsfs file system has access to it. + +By confirming this caution, you are acknowledging that you are aware there are potential data security and integrity exposures involved in the use of this package, and that you want to install it anyway. diff --git a/s390-tools.changes b/s390-tools.changes new file mode 100644 index 0000000..e96aa32 --- /dev/null +++ b/s390-tools.changes @@ -0,0 +1,2566 @@ +------------------------------------------------------------------- +Mon Feb 20 17:05:45 UTC 2017 - mpost@suse.com + +- Added s390-tools-sles12sp3-util_proc-fix-memory-allocation-error-messages.patch + (bsc#1025247) + +------------------------------------------------------------------- +Thu Feb 16 21:06:41 UTC 2017 - mpost@suse.com + +- Added the following patches for Fate # 322377: + - s390-tools-sles12sp3-dbginfo-01-libutil-Add-utility-functions.patch + - s390-tools-sles12sp3-dbginfo-02-dump2tar-Add-sysfs-collection-helper-for-dbginfo.sh-v2.patch + - s390-tools-sles12sp3-dbginfo-03-dbginfo.sh-Make-use-of-sysinfo-collection-helper.patch + +- Added the following patches for Fate # 322374: + - s390-tools-sles12sp3-lsdasd-tunedasd-Add-channel-path-aware-erp.patch + +- Added the following patches for Fate # 321643: + - s390-tools-sles12sp3-dasdfmt-01-Fix-behaviour-of-t-combined-with-y.patch + - s390-tools-sles12sp3-dasdfmt-02-Fix-trailing-whitespace.patch + - s390-tools-sles12sp3-dasdfmt-03-Apply-coding-convention.patch + - s390-tools-sles12sp3-dasdfmt-04-Use-enhanced-DASD-information.patch + - s390-tools-sles12sp3-dasdfmt-05-Refactor-do_format_dasd.patch + - s390-tools-sles12sp3-dasdfmt-06-Make-the-IOCTL-BLKSSZGET-reusable.patch + - s390-tools-sles12sp3-dasdfmt-07-Add-quick-format-support.patch + - s390-tools-sles12sp3-dasdfmt-08-Make-progress-output-reusable-and-add-ETR.patch + - s390-tools-sles12sp3-dasdfmt-09-Add-command-line-argument-check.patch + - s390-tools-sles12sp3-dasdfmt-10-Add-expand-format-mode.patch + +------------------------------------------------------------------- +Wed Feb 1 22:00:35 UTC 2017 - mpost@suse.com + +- Added s390-tools-sles12sp2-lscss-allow-to-specify-devices-from-ssid-3.patch + (bsc#1023022) + +------------------------------------------------------------------- +Wed Dec 14 16:09:52 UTC 2016 - Thomas.Blume@suse.com + +- cio_ignore.service: change After dependency to local-fs.target to + Before and remove Wants dependency (bsc#965263) + +------------------------------------------------------------------- +Fri Sep 30 16:48:03 UTC 2016 - mpost@suse.com + +- Added s390-tools-sles12sp2-chzdev-disable-root-update.patch + (bsc#1002188) +- Updated cputype to recognize z13s processors. +- Updated boot.cpi to redirect stderr to /dev/null when trying to + set the CPI parameters. (bsc#997479) + +------------------------------------------------------------------- +Wed Jul 20 19:03:26 UTC 2016 - mpost@suse.com + +- Added s390-tools-sles12sp2-chreipl-virtio.patch (bsc#989797) + chreipl/virtio: fix chreipl node for virtio-blk disks + +------------------------------------------------------------------- +Fri Jul 1 16:37:29 UTC 2016 - mpost@suse.com + +- Added s390-tools-sles12sp2-zipl-fix-failed-start-subchannel.patch + (bsc#987385) +- Modified lgr_check script to do a better job of checking: + - Disconnected state of the guest + - Whether a 3270 terminal is active + - Tape ASSIGNment + +------------------------------------------------------------------- +Tue May 24 17:51:02 UTC 2016 - mpost@suse.com + +- Added the following files for Fate#318552 and Fate#320123 + - detach_disks + - killcdl + - lgr_check + - sysconfig.virtsetup + - virtsetup.service + - virtsetup.sh +- Added the following two patches (bsc#981427) + - s390-tools-sles12sp2-chiucvallow-verify.patch + - s390-tools-sles12sp2-libu2s-Fix-busid-parsing.patch +- Some spec file cleanup of macro calls. + +------------------------------------------------------------------- +Wed May 18 20:04:10 UTC 2016 - mpost@suse.com + +- Added s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch + (bsc#931634). + +------------------------------------------------------------------- +Fri Apr 22 17:20:49 UTC 2016 - mpost@suse.com + +- Modified 59-zfcp-compat rules to include continuation characters + on rules that are continued across multiple lines (bsc#972110) +- Added 59-dasd.rules-wait_for.patch (bsc#972110) +- Don't install 60-readahead.rules (bsc#972110) +- Removed redundant architecture check from the %prep section +- Removed various %service_* calls for iucvtty-login@.service + and ttyrun-getty@.service because they generate "unit name is + not valid" messages from systemctl. + +------------------------------------------------------------------- +Wed Mar 23 21:21:39 UTC 2016 - mpost@suse.com + +- Upgraded to version 1.34.0 + Added libpfm-devel to the list of BuildRequires + Removed references to chzdev that was never implemented by IBM +- Added 59-zfcp-compat.rules (bsc#972110) +- Removed the following obsolete scripts/files + mkinitrd-boot-dasd.sh + mkinitrd-boot-qeth.sh + mkinitrd-boot-zfcp.sh + mkinitrd-setup-dasd.sh + mkinitrd-setup-qeth.sh + mkinitrd-setup-zfcp.sh + zfcpdump.config +- Added s390-tools-sles12sp2-feat-01-dasd-query-host.patch (Fate#319604) +- Reworked s390-tools-sles12-pardasdfmt.patch to fit. +- Reworked dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch to fit. +- Added file /etc/modprobe.d/90-s390-tools.conf to ensure + dasd_diag_mod and dasd_fba_mod kernel modules get loaded together + (bsc#966477). +- Updated zfcp_san_disc so that breaking out of it won't leave + "well known LUNs" in use preventing others from using them. + (bsc#961372) +- Removed the following obsolete patches + s390-tools-sles12-cpuplugd-allow-more-than-64-CPUs.patch + s390-tools-sles12-dasdstat-avoid-inconsistent-data.patch + s390-tools-sles12-dbginfo-collect-journalctl.patch + s390-tools-sles12-dbginfo-libvirt-multipath-extension.patch + s390-tools-sles12-dbginfo-option-for-output-directory.patch + s390-tools-sles12-dbginfo-q-v-nic.patch + s390-tools-sles12-dbginfo-systemd-data-collection.patch + s390-tools-sles12-dumpconf-fix-delay-minutes.patch + s390-tools-sles12-init-scripts-do-not-use-subsys.patch + s390-tools-sles12-ipl_tools-fcp-loadparm.patch + s390-tools-sles12-lsqeth-put-grep-regex-in-quotes.patch + s390-tools-sles12-lsreipl-fix-fcp-reipl-type.patch + s390-tools-sles12-lszcrypt-ep11-support.patch + s390-tools-sles12-qetharp-iface-arg-limit.patch + s390-tools-sles12-qetharp-q-format.patch + s390-tools-sles12-qethqoat-and-qetharp-return-codes-fixed.patch + s390-tools-sles12-qethqoat-fix-buffer-overflow-for-interface-parameter.patch + s390-tools-sles12-remove-FBA-detection-for-virtblk-devices.patch + s390-tools-sles12-systemd-iucvterm-units.patch + s390-tools-sles12-ziorep-busid-fix.patch + s390-tools-sles12-zipl-dump-part-check.patch + s390-tools-sles12-zipl-fix-kernel-parameter-line.patch + s390-tools-sles12-zipl-fix-parmline-zero-termination.patch + s390-tools-sles12-znetconf-r-format.patch + s390-tools-sles12sp1-cmsfs-fuse-time-fix.patch + s390-tools-sles12sp1-feat-01-hyptop-diag0c.patch + s390-tools-sles12sp1-feat-02-hyptop-lpar-smt.patch + s390-tools-sles12sp1-feat-03-zipl-mt-dump.patch + s390-tools-sles12sp1-feat-04-zipl-zgetdump-simd-dump.patch + s390-tools-sles12sp1-feat-05-cpumf.patch + s390-tools-sles12sp1-feat-06-lscpumf-disp-ctrs.patch + s390-tools-sles12sp1-feat-07-lscpumf-cf-sf-check.patch + s390-tools-sles12sp1-feat-08-chreipl-support-virtio_ccw.patch + s390-tools-sles12sp1-feat-09-lsqeth_display_switch_attrs.patch + s390-tools-sles12sp1-feat-10-qethqoat_OSA_Express_5S_support.patch + s390-tools-sles12sp1-feat-11-lszcrypt-CEX5S-support.patch + s390-tools-sles12sp1-feat-12-hmcdrvfs.patch + s390-tools-sles12sp1-lsluns-check-fcp-device-state.patch + s390-tools-sles12sp1-lszfcp-incorrect-device-types.patch + s390-tools-sles12sp1-znetconf-check-ccwgroup-devices-fix.patch + +------------------------------------------------------------------- +Fri Nov 6 18:59:20 UTC 2015 - mpost@suse.com + +- Added 59-prng.rules so that /dev/prandom will have permissions + of 0444. This will allow anyone to access the CPACF hardware + pseudo-random number generator. (bsc#946349) +- Updated the comments in 59-graf.rules to reflect the correct + location for the rule to be installed. + +------------------------------------------------------------------- +Fri Nov 6 00:27:17 UTC 2015 - mpost@suse.com + +- Modified dasd_reload to take HyperPAV alias devices offline + before the "normal" DASD and base devices, and then activate + the "normal" DASD and base devices before the alias devices. + (bsc#942373). + +------------------------------------------------------------------- +Fri Oct 30 22:47:12 UTC 2015 - mpost@suse.com + +- Updated read_values.c to point to the location IBM's makefile + for qclib puts the include file. (bsc#951518). +- Added a filter to s390-tools-rpmlintrc to mask a warning + about read_values being statically linked. This was intentional + since we didn't want to include the qclib-devel shared library + in the distribution since this is the only programt that uses + qclib-devel. + +------------------------------------------------------------------- +Fri Oct 23 16:12:53 CEST 2015 - hare@suse.de + +- Updated zfcp_host_configure to return '10' if the system + is set up for automatic LUN scanning (bsc#951547) + +------------------------------------------------------------------- +Tue Oct 13 21:51:59 UTC 2015 - mpost@suse.com + +- Replaced read_values.c with a newer version that uses the + query capacity library (qclib) from IBM. (FATE#319342) + +------------------------------------------------------------------- +Wed Sep 9 17:55:19 UTC 2015 - mpost@suse.com + +- Updated s390-tools-sles12-pardasdfmt.patch to fix error messages + that didn't have a "\n" on the end. (bsc#940818) +- Updated the spec file to install 40-z90crypt.rules into + /usr/lib/udev/rules.d/ (bsc#943777) +- Added the following patches from IBM (bsc#944390) + - s390-tools-sles12sp1-lszfcp-incorrect-device-types.patch + lszfcp: display of incorrect device types + - s390-tools-sles12sp1-znetconf-check-ccwgroup-devices-fix.patch + znetconf: cannot handle that no device is there + - s390-tools-sles12sp1-lsluns-check-fcp-device-state.patch + lsluns: do not scan FCP devices no longer online or in bad state + - s390-tools-sles12sp1-cmsfs-fuse-time-fix.patch + cmsfs-fuse: Fix time stamp handling for data sets + +------------------------------------------------------------------- +Wed Jul 22 19:17:39 UTC 2015 - mpost@suse.com + +- Removed s390-tools-sles12sp1-feat-13-lsdasd-add-path-information.patch + at the request of IBM. To be re-introduced for SLES12 SP2. +- Added s390-tools-sles12-dumpconf-fix-delay-minutes.patch (bsc#939054) + +------------------------------------------------------------------- +Wed Jun 17 21:28:15 UTC 2015 - mpost@suse.com + +- Split out the SE/HMC file access pieces into a new sub-package + (bsc#934372). + +------------------------------------------------------------------- +Thu Jun 11 22:07:37 UTC 2015 - mpost@suse.com + +- Added the following feature updates for SLES12 SP1 + - s390-tools-sles12sp1-feat-01-hyptop-diag0c.patch (bsc#934359, Fate#318069) + hyptop: Exploit diag 0c data + - s390-tools-sles12sp1-feat-02-hyptop-lpar-smt.patch (bsc#934324, Fate#318054) + hyptop: Support for SMT (SMT base support) + - s390-tools-sles12sp1-feat-03-zipl-mt-dump.patch (bsc#934371, Fate#318047) + zipl: Add MT dump support for zipl dump tools + - s390-tools-sles12sp1-feat-04-zipl-zgetdump-simd-dump.patch (bsc#934360, Fate#318057) + zipl: Add vector register support + - Add support for hardware sampling to the perf tool (bsc#934321, Fate#318025) + - s390-tools-sles12sp1-feat-05-cpumf.patch + s390/perf: add support for the CPU-measurement sampling Facility + - s390-tools-sles12sp1-feat-06-lscpumf-disp-ctrs.patch + cpumf: display counters only if the facility is available + - s390-tools-sles12sp1-feat-07-lscpumf-cf-sf-check.patch + cpumf: lscpumf erroneously reports sampling support + - s390-tools-sles12sp1-feat-08-chreipl-support-virtio_ccw.patch (bsc#934370, Fate#318962) + zipl/chreipl: Basic guest support for KVM hypervisors + - s390-tools-sles12sp1-feat-09-lsqeth_display_switch_attrs.patch (bsc#934364, Fate#318473) + lsqeth: Add support for switch port attributes + - s390-tools-sles12sp1-feat-10-qethqoat_OSA_Express_5S_support.patch (bsc#934350, Fate#318033) + qethqoat: OSA-Express5S Support + - s390-tools-sles12sp1-feat-11-lszcrypt-CEX5S-support.patch (bsc#934325, Fate#318044) + lszcrypt: Add support for CEX5S crypto adapters. + - s390-tools-sles12sp1-feat-12-hmcdrvfs.patch (bsc#934372, Fate#318067) + hmcdrvfs: SE/HMC file access + - s390-tools-sles12sp1-feat-13-lsdasd-add-path-information.patch (bsc#934352, Fate#318031) + lsdasd: add path information + +------------------------------------------------------------------- +Thu Apr 23 20:54:09 UTC 2015 - mpost@suse.com + +- Added three IBM patches (bsc#924973) + - s390-tools-sles12-dbginfo-libvirt-multipath-extension.patch + dbginfo.sh: Extend data collection for libvirt and multipath + - s390-tools-sles12-dbginfo-q-v-nic.patch + dbginfo.sh: Query virtual network settings for VM guests + - s390-tools-sles12-ziorep-busid-fix.patch + ziomon/ziorep: fix wrong assumption of 0.0.xxxx busids + +------------------------------------------------------------------- +Wed Mar 11 19:27:33 UTC 2015 - mpost@suse.com + +- Updated the cputype script to recognize the new z13 processor. +- Modified read_values.c to handle additional values from + /proc/sysinfo and redirect an error message to stderr (bsc#919293) +- Modified read_values.c to convert as much German to English as I could +- Added read_values.8 man page (bsc#919293) +- Added s390-tools-sles12-dasdstat-avoid-inconsistent-data.patch (bsc#920363) + dasdstat: avoid inconsistent data due to multiple reads/seeks +- Added s390-tools-sles12-qethqoat-and-qetharp-return-codes-fixed.patch (bsc#920363) + qethqoat and qetharp: return codes fixed + +------------------------------------------------------------------- +Mon Jan 19 18:53:34 UTC 2015 - mpost@suse.com + +- Added s390-tools-sles12-zipl-dump-part-check.patch (bsc#909524) + zipl dump tools: Fix end of partition check + +------------------------------------------------------------------- +Wed Dec 10 22:36:09 UTC 2014 - mpost@suse.com + +- Added three IBM patches (bsc#903048) + - s390-tools-sles12-dbginfo-option-for-output-directory.patch + dbginfo.sh: Add option to specify directory for data collection + - s390-tools-sles12-dbginfo-systemd-data-collection.patch + dbginfo.sh: Improve data collection for systemd and lsdasd + - s390-tools-sles12-cpuplugd-allow-more-than-64-CPUs.patch + cpuplugd: allow more than 64 CPUs + +------------------------------------------------------------------- +Thu Sep 4 19:01:52 UTC 2014 - mpost@suse.com + +- Modified zfcp_host_configure to write udev rules and update + /boot/zipl/active_devices.txt even if the HBA is already online. + (bnc#894229) +- Modified zfcp_san_disc to properly filter for remote ports. + (bnc#868494) + +------------------------------------------------------------------- +Wed Sep 3 17:08:55 UTC 2014 - mpost@suse.com + +- Added %conf /boot/zipl/active_devices.txt to the spec file. + (bnc#894480) + +------------------------------------------------------------------- +Wed Sep 3 01:43:27 CEST 2014 - ro@suse.de + +- sanitize release line in specfile + +------------------------------------------------------------------- +Tue Sep 2 17:13:38 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-ipl_tools-fcp-loadparm.patch (bnc#894071) + ipl_tools: Add missing SCSI loadparm support + +------------------------------------------------------------------- +Mon Aug 18 20:46:11 UTC 2014 - mpost@suse.com + +- Added read_values to the package (Fate#313462). + Changed license from GPL-2.0+ to "GPL-2.0+ and BSD2c" + (BSD 2-Clause License) to account for the new command. + +------------------------------------------------------------------- +Wed Aug 13 16:08:27 UTC 2014 - mpost@suse.com + +- Modified dasd_reload script to deactivate any MD arrays before + trying to take any DASD offline. (bnc#876570) + +------------------------------------------------------------------- +Mon Aug 11 16:01:12 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-zipl-fix-parmline-zero-termination.patch (bnc#891090) + zipl: fix zero termination of parmline + +------------------------------------------------------------------- +Mon Jul 28 17:03:39 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-init-scripts-do-not-use-subsys.patch (bnc#888592) + init scripts: Do not use /var/lock/subsys + +------------------------------------------------------------------- +Fri Jul 25 14:23:02 CEST 2014 - hare@suse.de + +- Fixup script issues in zfcp_san_disc (bnc#868494) + +------------------------------------------------------------------- +Tue Jul 22 18:08:29 UTC 2014 - mpost@suse.com + +- Updated %post script to remove the warning about running zipl after + installing this package. That hasn't been necessary for quite a + while. (bnc#888248) + +------------------------------------------------------------------- +Fri Jul 11 11:25:53 UTC 2014 - mpost@suse.com + +- Implement cio_ignore.service (bnc#882685, bnc#886833) + Added cio_ignore.service and setup_cio_ignore.sh + Fixup dependencies for cio_ignore service + Fixup setup_cio_ignore.sh to correctly enable devices +- Added s390-tools-sles12-remove-FBA-detection-for-virtblk-devices.patch + (bnc#883989) + zipl: remove heuristic FBA detection for virtblk devices +- Updated mkdump script (bnc#884786): + - Don't create a file system on SCSI disks + - Use GPT partition tables instead of MSDOS to allow dumps > 2TB + - Use "zipl -d" instead of "zipl -D" for partition dumping +- Added a check for the existence of /boot/zipl/active.devices.txt + before trying to write to it in: + ctc_configure, dasd_configure, qeth_configure, and + zfcp_host_configure. +- Modified zfcp_host_configure to completely take the HBA offline + (bnc#872229). + +------------------------------------------------------------------- +Wed Jul 9 14:57:31 UTC 2014 - jjolly@suse.com + +- Now obtaining zfcpdump-part.image from kernel-zfcpdump package + +------------------------------------------------------------------- +Mon Jun 16 17:13:39 UTC 2014 - mpost@suse.com + +- Added a "udevadm settle" command to qeth_configure. + +------------------------------------------------------------------- +Mon Jun 16 13:40:05 CEST 2014 - pth@suse.de + +- Merge the work of John and Mark. + +------------------------------------------------------------------- +Fri Jun 13 23:34:58 UTC 2014 - mpost@suse.com + +- Updated the following scripts to add tracking for the devices + configured on the system for the cio_ignore kernel parameter: + - ctc_configure + - dasd_configure + - qeth_configure + - zfcp_host_configure + - Added an empty /boot/zipl/active_devices.txt file for the + tracking function (bnc#874902). + +------------------------------------------------------------------- +Fri Jun 13 19:33:51 UTC 2014 - jjolly@suse.com + +- zfcpdump.config - Configuration for zfcpdump kernel build +- series.conf - Added kernel build and removed post and postun + scripting to copy image + +------------------------------------------------------------------- +Thu Jun 12 16:27:10 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-lsqeth-put-grep-regex-in-quotes.patch. (bnc#877138) + lsqeth: put grep regex in quotes + +------------------------------------------------------------------- +Wed May 28 20:25:49 UTC 2014 - mpost@suse.com + +- Add s390-tools-sles12-qethqoat-fix-buffer-overflow-for-interface-parameter.patch + qethqoat: buffer overflow (bnc#880378) + +------------------------------------------------------------------- +Tue May 13 19:45:59 UTC 2014 - mpost@suse.com + +- Removed all the patches related to the persistent device configuration + tools. The feature in FATE was withdrawn. + s390-tools-sles12-chzdev-creates-invalid-zFCP-udev-rules.patch + s390-tools-sles12-chzdev-fails-to-configure-IUCV.patch + s390-tools-sles12-chzdev-fails-to-group-layer-3-nics.patch + s390-tools-sles12-chzdev-fix-output.patch + s390-tools-sles12-chzdev-Improved-error-handling.patch + s390-tools-sles12-chzdev-lszdev-Compilation-warnings.patch + s390-tools-sles12-chzdev-lszdev-new-tools.1.patch + s390-tools-sles12-chzdev-lszdev-new-tools.2.patch + s390-tools-sles12-chzdev-lszdev-new-tools.3.patch + s390-tools-sles12-chzdev-lszdev-new-tools.4.patch + s390-tools-sles12-chzdev-lszdev-new-tools.5.patch + s390-tools-sles12-chzdev-lszdev-new-tools.6.patch + s390-tools-sles12-chzdev-lszdev-new-tools.7.patch + s390-tools-sles12-chzdev-lszdev-restore-makefile.patch + s390-tools-sles12-chzdev-lszdev-temp-fix.patch + s390-tools-sles12-chzdev-lszdev-temporary-makefile-revert.patch + s390-tools-sles12-chzdev-lun-and-wwpn-now-must-be-16-hex-digits.patch + s390-tools-sles12-chzdev-missing-online.patch + s390-tools-sles12-chzdev-optimize-css-search.patch + s390-tools-sles12-chzdev-revoke-to-specify-no-category.patch + s390-tools-sles12-chzdev-segfault-creating-netiucv-on-lpar.patch + s390-tools-sles12-chzdev-set-online-state-correctly.patch + s390-tools-sles12-chzdev-unable-to-enable-dasd-diag-access.patch + s390-tools-sles12-lszdev-chzdev-corrected-man-page.patch + s390-tools-sles12-lszdev-chzdev-misc-patches.patch + s390-tools-sles12-lszdev-corrected-device-lookup-for-btrfs.patch + s390-tools-sles12-lszdev-manual-page-update.patch + s390-tools-sles12-install-manpages.patch +- Added patch s390-tools-sles12-systemd-iucvterm-units.patch (bnc#877346) + Removed iucvtty@.service file, since the above patch replaces it. +- Added util-linux, gawk, and procps packages to the list of Requires + just to be safe (bnc#86736). + +------------------------------------------------------------------- +Mon May 5 18:53:08 UTC 2014 - mpost@suse.com + +- Added the following patches (bnc#876334) + - s390-tools-sles12-lsreipl-fix-fcp-reipl-type.patch + lsreipl: Show "fcp" instead of "fcp_dump" for fcp re-IPL target + - s390-tools-sles12-chzdev-Improved-error-handling.patch + chzdev: Improved error handling + - s390-tools-sles12-lszdev-corrected-device-lookup-for-btrfs.patch + lszdev: corrected lookup for filesystem on btrfs + - s390-tools-sles12-chzdev-lun-and-wwpn-now-must-be-16-hex-digits.patch + chzdev: LUN and WWPN now must be 16 hex digits + - s390-tools-sles12-chzdev-revoke-to-specify-no-category.patch + chzdev: Revoke to specify no category if needed + - s390-tools-sles12-lszdev-chzdev-corrected-man-page.patch + lszdev/chzdev: Update man page description for FCP LUNs + +------------------------------------------------------------------- +Mon Apr 21 16:28:01 UTC 2014 - mpost@suse.com + +- Added the following patches (bnc#874143) + - s390-tools-sles12-dbginfo-collect-journalctl.patch + dbginfo.sh: Add collection of journalctl + - s390-tools-sles12-chzdev-set-online-state-correctly.patch + chzdev: Did not get the online state correctly + - s390-tools-sles12-lszdev-chzdev-misc-patches.patch + lszdev/chzdev: Miscellaneous patches + +------------------------------------------------------------------- +Mon Apr 14 06:18:41 UTC 2014 - mpost@suse.com + +- Added the following patches (bnc#873239) + - s390-tools-sles12-chzdev-fix-output.patch + chzdev: tools generates numerous error messages + - s390-tools-sles12-lszdev-manual-page-update.patch + lszdev: Update of the manpage + - s390-tools-sles12-chzdev-optimize-css-search.patch + chzdev: Performance optimization to get css information + - s390-tools-sles12-chzdev-missing-online.patch + chzdev: Add missing online attribute +- Updated cputype to also display the IBM model number + +------------------------------------------------------------------- +Thu Apr 10 19:09:22 UTC 2014 - mpost@suse.com + +- Added cputype and cputype.8. Fate#317195. +- Updated and reformatted README.SUSE. It is no longer obsolete. +- Check to see if systemd is running before executing + systemctl daemon-reload in %post and %postun. + +------------------------------------------------------------------- +Mon Apr 7 19:50:41 UTC 2014 - mpost@suse.com + +- Moved the "Requires: perl" back to osasnmpd. +- Added "Requires: perl-base" to the main package. (bnc#871830). + +------------------------------------------------------------------- +Fri Apr 4 22:11:17 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-chzdev-segfault-creating-netiucv-on-lpar.patch + chzdev: Segfault when creating netiucv device in lpar (bnc#872092) + +------------------------------------------------------------------- +Thu Apr 3 18:56:58 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-chzdev-creates-invalid-zFCP-udev-rules.patch + chzdev: invalid udev rules for zFCP (bnc#871292) +- Added s390-tools-sles12-chzdev-fails-to-group-layer-3-nics.patch + chzdev: fails to create grouped Layer 3 NICs (bnc#871222) (bnc#871223) +- Added s390-tools-sles12-chzdev-fails-to-configure-IUCV.patch + chzdev: fails to configure/deconfigure IUCV interfaces (bnc#871230) +- Added s390-tools-sles12-chzdev-unable-to-enable-dasd-diag-access.patch + chzdev: fails to enable DIAG access mode for DASD (bnc#871226) +- Added s390-tools-sles12-chzdev-lszdev-Compilation-warnings.patch + chzdev/lszdev: warnings about unused functions and others (bnc#871220) + +------------------------------------------------------------------- +Mon Mar 31 15:49:52 UTC 2014 - mpost@suse.com + +- Modified the content of s390-tools-zdsfs.caution.txt slightly to + convey just where the zdsfs feature originated. +- Added "SUSE-NonFree" as the license for the zdsfs sub-package to get + the caution displayed when the package is installed. + +------------------------------------------------------------------- +Sat Mar 29 15:51:02 UTC 2014 - mpost@suse.com + +- Moved the "Requires: perl" from osasnmpd to the main package +- Added, coreutils, rsync, and tar to the list of "Requires." + +------------------------------------------------------------------- +Fri Mar 28 23:42:37 UTC 2014 - mpost@suse.com + +- Add s390-tools-sles12-qetharp-iface-arg-limit.patch (bnc#870948). + qetharp: limit interface name argument to 15 characters +- Added s390-tools-sles12-chzdev-lszdev-new-tools.7.patch (bnc849864). + Reduced the number of supported devices and some options. + The tools have a stripped down but better tested functionality. + +------------------------------------------------------------------- +Thu Mar 27 23:36:10 UTC 2014 - mpost@suse.com + +- Renamed the package containing zdsfs to s390-tools-zdsfs +- Replaced the dummy LICENSE file with s390-tools-zdsfs.caution.txt +- Modified the spec file to rename s390-tools-zdsfs.caution.txt to CAUTION + so it will get installed in /usr/share/doc/packages/s390-tools-zdsfs +- Fixed a bug with iucv_configure that caused any IUCV interfaces past + iucv9 to be ignored. +- Modified dasd_configure so that instead of simply exiting with a + return code of 8 when an unformatted DASD volume was found, it + would continue with writing the udev rules for it. (bnc#864719) + +------------------------------------------------------------------- +Wed Mar 26 00:19:08 UTC 2014 - mpost@suse.com + +- Modified zfcp_san_disc to work with the output from the latest lsscsi + command. (bnc#864417) +- Re-added DISTRELEASE=%{release} to the make and make install commands + in the spec file so that the version number output meets IBM's expectations. + (bnc#869982) + +------------------------------------------------------------------- +Fri Mar 7 06:57:12 UTC 2014 - mpost@suse.com + +- Modified zfcp_san_disc to add a timing loop to wait for the remote + FCP port to appear in sysfs. (bnc#864119) +- Moved the location of zipl.conf.sample from /etc/ to + /usr/share/doc/packages/s390-tools/ now that grub2 is the official + boot loader + +------------------------------------------------------------------- +Fri Feb 28 20:06:14 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-chzdev-lszdev-new-tools.6.patch from IBM. + Many improvements on the formatting of the source files, new + options and man pages. Renamed scsi.c to zfcp.c and scsi.h to + zfcp.h. Cleaned up sources. + +------------------------------------------------------------------- +Thu Feb 27 13:14:47 UTC 2014 - thardeck@suse.com + +- Added a short explanation to the iucvtty template header + +------------------------------------------------------------------- +Sun Feb 23 21:30:34 UTC 2014 - thardeck@suse.com + +- Renamed iucvtty@hvc0.service to iucvtty@.service following the + getty template naming scheme +- Added installation section to iucvtty@.service so a iucvtty + instance can be activated for example with + `systemctl enable iucvtty@lxterm1.service` +- Prevented automatic creation of one default iucvtty instance + +------------------------------------------------------------------- +Thu Feb 20 19:29:39 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-zipl-fix-kernel-parameter-line.patch (bnc#853930) + zipl: Fix potentially invalid argument in kernel parameter line. + +------------------------------------------------------------------- +Tue Feb 18 18:21:38 UTC 2014 - mpost@suse.com + +- Updated zfcp_disk_configure and zfcp_san_disc to work with NPIV + and auto LUN scanning in newer kernels. (bnc#864119) + +------------------------------------------------------------------- +Thu Feb 13 19:48:41 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-chzdev-lszdev-new-tools.5.patch from IBM. + This patch fixes problems with module configuration, check & diff. + +------------------------------------------------------------------- +Tue Feb 11 19:10:15 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-chzdev-lszdev-temp-fix.patch to fix a + segfault until IBM can get an update out. + +------------------------------------------------------------------- +Mon Feb 10 22:19:36 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-znetconf-r-format.patch (bnc#863076) + qetharp: Allow for 16-char network interface names +- Added s390-tools-sles12-znetconf-r-format.patch (bnc#863076) + znetconf: Allow for 16-char network interface names + +------------------------------------------------------------------- +Fri Feb 7 18:42:08 UTC 2014 - mpost@suse.com + +- Updated to s390-tools-1.24.1. This includes (and obsoletes) the + fixes included in s390-tools-sles12-fix-31bit-compile-warnings.patch + as well as the following which were found during the Alpha phase: + Changes of existing tools: + - dbginfo.sh: Cleanup messages of the script + - dbginfo.sh: Reduced log output for sysfs collection + - dbginfo.sh: Adding data collection from journalctl + Bug Fixes: + - lsdasd: Fix device selection for a given busid + - zipl dump tools: Fix dump device size detection + - zipl dump tools: Ensure that last progress message is printed + - zipl: Fix I/O error recovery + - zipl: Fix FBA boot + - znetconf, lsqeth: Allow for 16-char network interface names +- Updated all patches to refer to 1.24.1 instead of 1.24.0 +- Updated s390-tools-sles12-pardasdfmt.patch to fit the new source code. + +------------------------------------------------------------------- +Fri Feb 7 00:21:49 UTC 2014 - mpost@suse.com + +- Replaced s390-tools-sles12-chzdev-lszdev-new-tools.patch with the original + set of patches from IBM, now that everything compiles: + s390-tools-sles12-chzdev-lszdev-new-tools.1.patch + s390-tools-sles12-chzdev-lszdev-new-tools.2.patch + s390-tools-sles12-chzdev-lszdev-new-tools.3.patch +- Added s390-tools-sles12-chzdev-lszdev-temporary-makefile-revert.patch and + s390-tools-sles12-chzdev-lszdev-restore-makefile.patch since the patches + as shipped from IBM are not being built against the current version of + the s390-tools source. +- Added s390-tools-sles12-chzdev-lszdev-new-tools.4.patch from IBM. +- Updated s390-tools-sles12-install-lszdev-manpage.patch to also + install chzdev.8 and renamed it to s390-tools-sles12-install-manpages.patch + Also explicitly set the file permissions to 644. +- Added %dir entries in the spec file for /var/adm/backup/chzdev + and /var/adm/backup/chzdev/udev +- Removed s390-tools-sles12-chzdev-iucv-typo-fix.patch since the lastest + IBM update included the fix. + +------------------------------------------------------------------- +Wed Feb 5 00:29:24 UTC 2014 - mpost@suse.com + +- Updated and re-added s390-tools-sles12-pardasdfmt.patch. +- Modified mkdump.pl to not use the experimental "switch" feature. + (bnc#861954) +- Modified s390-tools-sles12-zipl_boot_msg.patch to add an extra + blank line before and after the "note" to VM users to have it + look like it does today. +- Added "ZFCPDUMP_DIR=/usr/lib/s390-tools/zfcpdump" to the make + command so that zfcpdump would look in the right directory. +- Removed an unnecessary + "mkdir -p $RPM_BUILD_ROOT%{_datadir}/s390-tools/zfcpdump" from + the spec file +- Removed some of the new code from IBM for the Persistent Device + Configuration tool so that it would compile. This means that the + fixes for bnc#861579 and bnc#861581 can be deployed. +- Added s390-tools-sles12-chzdev-iucv-typo-fix.patch to correct a typo + in a sysfs path name. + +------------------------------------------------------------------- +Tue Jan 21 19:58:35 UTC 2014 - mpost@suse.com + +- Added dracut to the list of BuildRequires. +- Commented out all references to mkinitrd, since we might not have + to do anything in that area with the introduction of dracut. + +------------------------------------------------------------------- +Tue Jan 21 19:53:06 UTC 2014 - mpost@suse.com + +- Changed the licensing of mkdump.pl and mkdump.8 from "GPL2 or GPL3" + to GPL2 or later as requested. + +------------------------------------------------------------------- +Wed Jan 15 17:51:43 UTC 2014 - mpost@suse.com + +- Added s390-tools-sles12-fix-31bit-compile-warnings.patch. (bnc#851123) + +------------------------------------------------------------------- +Wed Dec 18 16:52:10 UTC 2013 - mpost@suse.com + +- Added s390-tools-sles12-lszcrypt-ep11-support.patch + lszcrypt: Support EP11 crypto adapters +- Updated s390-tools-sles12-zipl_boot_msg.patch to fit new source. +- Removed s390-tools-sles12-shorten-dump-msgs.patch. +- Updated s390-tools-sles12-chzdev-lszdev-new-tools.patch to fit + new source. + +------------------------------------------------------------------- +Thu Dec 12 17:00:54 UTC 2013 - mpost@suse.com + +- Added /usr/lib/systemd/system/iucvtty@.service for systemd support +- Renamed sles12.chzdev.lszdev.addition.patch to + s390-tools-sles12-chzdev-lszdev-new-tools.patch + +------------------------------------------------------------------- +Tue Nov 19 19:51:15 UTC 2013 - mpost@suse.com + +- First attempt at building s390-tools 1.24.0 +- Removed the blktrace_api.h as it is no longer needed. +- Removed vmlogrdr.hotplug since that was for Linux 2.4 kernels. + +------------------------------------------------------------------- +Fri Nov 8 21:45:33 UTC 2013 - mpost@suse.com + +- IBM s390-tools-1.15.0 Maintenance Patches (#2) + - s390-tools-sles11sp3-zipl-zfcpdump-possible-cpus.patch + zipl: Use "possible_cpus" kernel parameter + - s390-tools-sles11sp3-dbginfo-missing_man_page.patch + dbginfo.sh: Add missing man page +- qeth_configure: Ensure any user-input hexidecimal numbers are in lower case. (bnc#829513) + +------------------------------------------------------------------- +Fri Sep 6 17:01:23 UTC 2013 - mpost@suse.com + +- [CIO] Add robustness against missing interrupts to non-path-grouped internal IO requests - s390-tools part (bnc#837742) + - s390-tools-sles11sp3-lscss-add_vpm.patch + +------------------------------------------------------------------- +Mon Aug 19 19:45:40 UTC 2013 - mpost@suse.com + +- IBM s390-tools-1.15.0 Maintenance Patches (#1) (bnc#824766) + - s390-tools-sles11sp3-zipl-mvdump-fix-force.patch + zipl: Fix zipl "--force" option for DASD multi-volume dump + - s390-tools-sles11sp3-zgetdump-elf-hdr-alloc-fix.patch + zgetdump: Fix ELF header size calculation + +------------------------------------------------------------------- +Fri Aug 9 17:39:10 UTC 2013 - mpost@suse.com + +- IBM s390-tools-1.15.0 Maintenance Patches (#1) (bnc#824766) + - s390-tools-sles11sp3-dbginfo-handle-pipes-in-sysfs.patch + dbginfo.sh: Avoiding eclusion list for pipes in sysfs + +------------------------------------------------------------------- +Wed Jul 31 21:20:29 UTC 2013 - mpost@suse.com + +- Updated ctc_configure, dasd_configure, iucv_configure, qeth_configure, + zfcp_disk_configure and zfcp_host_configure so that DEBUG is usable as + an environment variable, and not hardcoded in the script. +- Updated ctc_configure to correct some typos. +- Updated iucv_configure + - Changed all instances of ROUTER to PEER_USERID to better reflect + what the value respresents. + - Updated the _iucv_dev loops to point to $_iucv_dir/netiucv?* to avoid + picking up entries for the new hvc_iucv* consoles. (bnc#749094) + - Convert the user-entered PEER_USERID to all upper case so the user + doesn't have to. (bnc#749094) +- Updated qeth_configure + - Changed all references of "control channel" to "data channel" to + match what it's called in the driver code and documentation. + - Fixed a few typos. +- Updated zfcp_host_configure to add a missing udev rule. (bnc#830321) +- Updated mkinitrd-setup-qeth.sh + - It now handles both VLAN and bonded channel interfaces + - Restructured the code to better handle the new functionality. +- Updated zpxe.rexx to correct some whitespace inconsistencies and to + uncomment a screen clearing that wasn't desired during testing, and + left that way by mistake. +- Modified %post script to wipe out any dangling symlinks before + creating new ones. (bnc#830288) +- Added the shadow package to the RPM PreReq list. (bnc#832428) +- Added man pages for ctc_configure, dasd_configure, iucv_configure, + qeth_configure, zfcp_disk_configure and zfcp_host_configure. + +------------------------------------------------------------------- +Tue Jul 30 14:49:01 UTC 2013 - mpost@suse.com + +- Added the shadow package to the list of PreReqs, per problem report from + Duncan Mac-Vicar P. + +------------------------------------------------------------------- +Thu Jun 13 18:33:14 UTC 2013 - mpost@suse.com + +- IBM s390-tools-1.15.0 Maintenance Patches (#1) (bnc#824766) + - dbginfo.sh: Improvements on logging, content and collecting sysfs. + - dbginfo.sh: enhancement for cryptograhic adapters + +------------------------------------------------------------------- +Wed May 8 15:03:22 UTC 2013 - mpost@suse.com + +- Added udev rules (59-graf.rules) for 3270 devices. (bnc#792991) + +------------------------------------------------------------------- +Thu May 2 16:03:07 UTC 2013 - mpost@suse.com + +- Updated qeth_configure to not create a udev entry for the layer2 + attribute on OSN devices. OSN devices don't support Layer 2. (bnc#788924) + +------------------------------------------------------------------- +Fri Apr 26 21:41:37 UTC 2013 - mpost@suse.com + +- Enabled kdump over the network (bnc#807794) + - Updated mkinitrd-setup-qeth to look at $static_interfaces $dhcp_interfaces + instead of $interfaces. + - Changed installation location of mkinitrd-boot-qeth.sh and mkinitrd-setup-qeth.sh + to /lib/mkinitrd/scripts instead of /usr/lib/s390-tools/mkinitrd/scripts. + +------------------------------------------------------------------- +Wed Apr 17 19:03:01 UTC 2013 - mpost@suse.com + +- Updated qeth_configure with the fix in bnc#794577, comment #9. + +------------------------------------------------------------------- +Wed Apr 17 18:31:25 UTC 2013 - mpost@suse.com + +- IBM s390-tools-1.15.0 Maintenance Patches (#13) (bnc#815053) + - zfcpdbf: fix offset and length of fields in trace records with + s390-tools-sles11sp3-zfcpdbf-offset-length-fields-trace-records.patch + +------------------------------------------------------------------- +Tue Apr 2 19:50:38 UTC 2013 - mpost@suse.com + +- Updated mkinitrd-setup-dasd.sh script to include udev rules for DASD + in DIAG mode. (bnc#808256) + +------------------------------------------------------------------- +Tue Mar 26 16:59:03 UTC 2013 - mpost@suse.com + +- Updated zpxe.rexx file. + - Lots more comments and error checking + - Made it more in the style a z/VM systems programmer would expect. + - Made it more generic than just for Cobbler + +------------------------------------------------------------------- +Fri Mar 22 20:36:13 UTC 2013 - mpost@suse.com + +- Updated License entries to GPL-2.0+ to conform with SPDX format (bnc#733581) + +------------------------------------------------------------------- +Mon Mar 18 21:30:34 UTC 2013 - mpost@suse.com + +- Changed all comments and message output in zfcp_host_configure and zfcp_disk_configure wit +h ZFCP to zFCP (3/18/2013) +- Updated ctc_configure, dasd_configure, iucv_configure, qeth_configure, zfcp_disk_configure +, zfcp_host_configure to replace $SYSFS with /sysfs in the one instance where $SYSFS would b +e null.- + +------------------------------------------------------------------- +Fri Mar 15 10:57:54 UTC 2013 - rmilasan@suse.com + +- Add/change links in /dev/disk/by-id on 'change' and 'add' udev + trigger (bnc#808042). + add: s390-tools-sles11sp2-update-by_id-links-on-change-and-add-action.patch + +------------------------------------------------------------------- +Mon Feb 18 18:22:34 UTC 2013 - mpost@suse.com + +- Added s390-tools-sles11sp3-add_lsscm.patch (bnc#792709) + +------------------------------------------------------------------- +Thu Feb 7 18:31:33 UTC 2013 - mpost@suse.com + +- Updated usage information on + - ctc_configure + - dasd_configure + - iucv_configure + - qeth_configure + - zfcp_disk_configure + - zfcp_host_configure (bnc#769561) +- Fixed ctc_configure to not try to bind a CTC or LCS interface + to the right driver module if it already is bound to the right one. + +-------------------------------------------------------------------- +Wed Feb 6 23:55:53 UTC 2013 - mpost@suse.com + +- s390-tools SP2/SP3 patchset #12 (bnc#795513): + - ziomon: follow symlinks to find multipath devices + - dbginfo.sh: Improvements on data collection and speed + - zfcpdump: Release HSA early if Linux kernel supports it + - ziomon: cope with scsi disks not part of multipath device + - zfcpdbf: fix decoding of deferred errors + +------------------------------------------------------------------- +Wed Jan 16 21:10:00 UTC 2013 - mpost@suse.com + +- lszcrypt: Add support for CEX4 crypto cards (bnc#794511, fate#314245) + +------------------------------------------------------------------- +Mon Dec 10 14:46:11 UTC 2012 - uli@suse.com + +- Fuzzy live dump for System z (bnc#789801, fate#314099) +- Add new zconf tool dasdstat (bnc#789803, fate#314076) +- Allow SCM access via EADM subchannels (bnc#792709, fate#314244) +- dasd: add safe offline interface (bnc#792967, fate#312679) + +------------------------------------------------------------------- +Thu Dec 6 13:09:51 UTC 2012 - uli@suse.com + +- kdump: Add s390-tools kdump support (bnc#786472, fate#314079) + +------------------------------------------------------------------- +Wed Nov 28 14:41:59 UTC 2012 - uli@suse.com + +- zfcp_san_disc: added fix for listing of LUNs on SVC/V7000 by + hare (bnc#742352) + +------------------------------------------------------------------- +Thu Nov 22 14:13:20 UTC 2012 - uli@suse.com + +- qeth_configure: add option to udev rule if setting it succeeds, + not if it fails (bnc#744317) + +------------------------------------------------------------------- +Fri Nov 16 14:24:02 UTC 2012 - uli@suse.com + +- zfcp_host_configure: handle non-numeric "online" argument + properly (bnc#769290) + +------------------------------------------------------------------- +Thu Nov 15 14:00:00 UTC 2012 - uli@suse.com + +- *_configure: print meaningful error messages on failure + (bnc#746660) + +------------------------------------------------------------------- +Thu Nov 15 13:50:06 UTC 2012 - uli@suse.com + +- s390-tools-1.15.0 Maintenance Patches #11 (bnc#780272) + - zipl: Flush disk buffers before installing IPL record + +------------------------------------------------------------------- +Fri Jul 20 13:40:01 UTC 2012 - uli@suse.com + +- s390-tools-1.15.0 Maintenance Patches #10 (bnc#760339) + - ziomon: Fix handling of multiple multipath devices + - lsluns: Fix checks for scsi generic (sg) functionality. + - lsluns: Check SCSI registration in loop, after LUN0&WLUN unit_add + +------------------------------------------------------------------- +Thu Apr 12 11:44:15 UTC 2012 - uli@suse.com + +- s390-tools-1.15.0 Maintenance Patches #9 (bnc#751477) + - cmsfs-fuse: Use pread/pwrite if mmap'ing the whole disk fails + - znetconf: layer autodetection not working for IP VSWITCH + - mon_statd: fix error "udevsettle: command not found" + - mon_statd: fix stopping of unused records + +------------------------------------------------------------------- +Tue Mar 27 16:05:33 UTC 2012 - jjolly@suse.com + +- Added /sbin/udevadm settle to zfcp_disk_configure (bnc#593773) + +------------------------------------------------------------------- +Mon Feb 6 10:35:41 CET 2012 - ihno@suse.de + +- Fix CTC device setup (reassigning channels from lcs to ctcm) (bnc#745034) + +------------------------------------------------------------------- +Thu Feb 2 15:55:00 UTC 2012 - uli@suse.com + +- fix LCS device setup in ctc_configure (bnc#741071) +- from SP1: + - updated qeth_configure and dasd_configure to support SUSE Studio Onsite + (bnc#699047) + - qeth_configure: Proper IP takeover during layer 3 operation (bnc#694124) + +------------------------------------------------------------------- +Wed Feb 1 12:02:54 UTC 2012 - uli@suse.com + +- more fixes: (bnc#743407) + - qethconf: fix/improve IPv6 address handling + - znetconf: layer autodetection not working under z/VM 6.x + +------------------------------------------------------------------- +Fri Jan 13 12:19:12 UTC 2012 - stefan.fent@suse.com + +- s390-tools-1.15.0 Maintenace Patches #7 (bnc #740749) + - ttyrun: Introduce verbose option for syslog messages + - HiperSockets Network Concentrator: correct warning + - HiperSockets Network Concentrator: adapt to kernel level + +------------------------------------------------------------------- +Thu Jan 12 21:59:49 UTC 2012 - jjolly@suse.com + +- qeth_configure: Added udevadm trigger to help rewrite necessary + network scripts (bnc#728059) + +------------------------------------------------------------------- +Fri Dec 16 16:49:56 UTC 2011 - uli@suse.com + +- dasdfmt: use proper way to detect DASD cylinder count (bnc#733787) +- build system fix (bnc#737189) + +------------------------------------------------------------------- +Mon Dec 5 12:16:03 UTC 2011 - uli@suse.com + +- dasdfmt: fix cylinder count for large disks in YaST mode + (bnc#733787) + +------------------------------------------------------------------- +Mon Dec 5 10:51:13 UTC 2011 - uli@suse.com + +- qetharp: Man page improvements (bnc#732669) + +------------------------------------------------------------------- +Tue Nov 29 13:05:01 UTC 2011 - uli@suse.com + +- fix dasdfmt usage text (bnc#732503) + +------------------------------------------------------------------- +Tue Nov 8 22:12:41 UTC 2011 - jjolly@suse.com + +- rules.xpram: Added rule to create xpram nodes for each slram + node (bnc#723521,LTC#75884) +- rules.hw_random: Added rule to create hw_random node when hwrng + is created (bnc#724083,LTC#75951) + +------------------------------------------------------------------- +Fri Nov 4 16:10:34 UTC 2011 - uli@suse.com + +- lsdasd: Improve performance when used with many DASDs (bnc#728041) + +------------------------------------------------------------------- +Fri Nov 4 13:02:25 UTC 2011 - uli@suse.com + +- qeth_configure: recognize 1731/02 as qeth device (bnc#720082) + +------------------------------------------------------------------- +Mon Oct 24 10:58:51 UTC 2011 - uli@suse.com + +- more fixes: (bnc#725132) + - zfcpdbf: Include and exclude messages display problem + - zfcpdbf: help option does not list version '-v' option + - cmsfs-fuse: Fix file size calculation for files larger than 2 GB + - cmsfs-fuse: Fix big write requests + - cmsfs-fuse: Multiple write requests for fixed record format files + - cmsfs-fuse: Fix EOF detection for fixed record format files + - zipl: fix scsi dump + - cmsfs-fuse: Fix block allocation on large disks + - cmsfs-fuse: Update the number of records on disk full condition + - cmsfs-fuse: Add support for FBA-512 disks + - dumpconf: Add full path of executable for killproc invocation + - zfcpdbf: Messages with round-trip processing timediff problem + - lsmem/chmem: Fix memory device size calculation + +------------------------------------------------------------------- +Thu Oct 13 12:36:16 UTC 2011 - thardeck@suse.com + +- moved iucvconn_on_login from doc to /usr/bin +- added rcdumpconf link + +------------------------------------------------------------------- +Fri Oct 7 14:08:38 UTC 2011 - uli@suse.com + +- more fixes: (bnc#722508) + - lsmem/chmem: Fix handling of memory holes + - dasdview: fix printing of random characters after busid + +------------------------------------------------------------------- +Fri Sep 16 10:02:32 UTC 2011 - uli@suse.com + +- more fixes: (bnc#718024) + - qetharp: fix buffer overflow + - lsqeth: add hsuid attribute + - af_iucv manpage: add HiperSockets transport + - dbginfo.sh: does not run under kernel 3.x + - lsdasd,lscss: suppress error messages when working on unsettled + sysfs tree. + - lsluns: check for required SCSI generic (sg) functionality. + - zipl: Prevent unsupported parmfile address. + +------------------------------------------------------------------- +Tue Sep 6 17:10:17 CEST 2011 - uli@suse.de + +- update dumpconf patches (bnc#716118) + +------------------------------------------------------------------- +Mon Sep 5 16:23:53 CEST 2011 - uli@suse.de + +- update -> 1.15.0 (obsoletes most patches, bnc#unknown) + +------------------------------------------------------------------- +Mon Aug 29 08:21:38 UTC 2011 - thardeck@suse.de + +- updated mkdump script + - fixed DASD dump device recognition (bnc#713801) + - fixed allow creating dump devices on unformatted DASDs (bnc#713677) +- dumpconf restart doesn't trigger delay minutes + - s390-tools-sles11sp2-01-dumpconf-restart.patch +- dumpconf support for eight vmcmd commands + - s390-tools-sles11sp2-02-dumpconf-8cmds.patch +- updated dumpconf sysconfig accordingly + - s390-tools-sles11sp2-sysconfig-compatible-dumpconf.patch + + +------------------------------------------------------------------- +Tue Aug 12 09:44:54 UTC 2011 - thardeck@novell.com + +- added new mkdump script (fate#304024) + - mkdump.pl: new version - backward compatible with mkdump.sh + - s390-tools-sles11sp2-mkdump-manpage.patch: man page for mkdump +- add sysconfig meta data to /etc/sysconfig/dumpconf + - s390-tools-sles11sp2-sysconfig-compatible-dumpconf.patch: add sysconfig + metadata to dumpconf + +------------------------------------------------------------------- +Fri Aug 12 08:38:04 UTC 2011 - uli@suse.de + +- fdasd: fix generation of disk label for option 'auto' and 'config' + (bnc#708534) +- restored corrupted patch s390-tools-sle11sp1-04-lscss-fix-tr-quoting.patch + +------------------------------------------------------------------- +Wed Aug 3 11:37:22 CEST 2011 - hare@suse.de + +- qeth_configure: Properly deregister with collect during + chpid vary off (bnc#474627) + +------------------------------------------------------------------- +Thu Jul 28 12:16:01 UTC 2011 - uli@suse.de + +- dasd_configure: deactivate DIAG mode properly when told to do so + (bnc#591037) + +------------------------------------------------------------------- +Thu Jul 28 11:47:02 UTC 2011 - uli@suse.de + +- bug fixes (bnc#708534): + - cpuplugd: Fix check for existing variable names + - cpuplugd: Fix typos and wording in man page + +------------------------------------------------------------------- +Fri Jul 22 11:28:55 UTC 2011 - uli@suse.de + +- hyptop didn't build because ncurses-devel was missing from + BuildRequires (bnc#698740) + +------------------------------------------------------------------- +Thu Jul 14 13:56:45 CEST 2011 - uli@suse.de + +- build hyptop and cmsfs-fuse (bnc#698740) +- maintenance patches (bnc#698755): + - dasdinfo: return error code in case of failure. + - lsluns: Fix showing all active LUNs not just well known LUNs. + - lsreipl: Prevent error messages for empty sysfs files + - cpuplugd: add cpu/cmm_min/max sanity checks + - cpuplugd: fix daemon startup race + +------------------------------------------------------------------- +Tue Jun 20 15:39:12 CEST 2011 - thardeck@suse.de + +- added zpxe.rexx script (fate#312134) + +------------------------------------------------------------------- +Tue Jun 14 15:32:29 CEST 2011 - uli@suse.de + +- s390-tools patchset #12 for SP2 (bnc#698740) + - s390-tools-12-sles11sp2-infrastructure.patch: Add infrastructure code + for new features + - s390-tools-12-sles11sp2-ttyrun.patch: ttyrun: run a program if a + terminal device is available (fate#312296) + - s390-tools-12-sles11sp2-hyptop.patch: hyptop: Show hypervisor + performance data on System z (fate#311766) + - s390-tools-12-sles11sp2-chreipl-enhancements.patch: chreipl: Re-IPL tool + "chreipl" enhancements (fate#311861) + - s390-tools-12-sles11sp2-tunedasd-query-reservation-status.patch: + tunedasd: add new option -Q / --query_reserve (fate#311910) + - s390-tools-12-sles11sp2-znetconf-osxosm.patch: znetconf: support for OSA + CHPID types OSX and OSM (fate#311898) + - s390-tools-12-sles11sp2-use-cio_settle.patch: chccwdev,chchp: Use + /proc/cio_settle (fate#311763) + - s390-tools-12-sles11sp2-cio_ignore.patch: cio_ignore: manage the I/O + exclusion list (fate#311763) + - s390-tools-12-sles11sp2-qethconf-msgexpl.patch: qethconf: Indicate + command failure and show message list. (fate#312067) + - s390-tools-12-sles11sp2-zipl-calculate_ramdisk_address.patch: zipl: + Remove DEFAULT_RAMDISK_ADDRESS (fate#311877) + - s390-tools-12-sles11sp2-zipl-automenu.patch: zipl: Add support for + automatic menus (fate#311908) + - s390-tools-12-sles11sp2-fdasd-partition_types.patch: fdasd: Implement + new partition types (fate#311921) + - s390-tools-12-sles11sp2-qetharp-ipv6-support.patch: qetharp: support + ipv6 for query arp cache for HiperSockets (fate#311912) + - s390-tools-12-sles11sp2-zgetdump-zipl-mkdump.patch: zgetdump/zipl: Add + ELF dump support (needed for makedumpfile) (fate#311893, fate#311895) + - s390-tools-12-sles11sp2-dumpconf-prevent-loop.patch: dumpconf: Prevent + re-IPL loop for dump on panic. (fate#311757) + - s390-tools-12-sles11sp2-cmsfs-fuse.patch: cmsfs-fuse: support for CMS + EDF filesystems via fuse. (fate#311847, fate#311858) + - s390-tools-12-sles11sp2-cpuplugd-cmm-improvements.patch: cpuplugd: + Improve memory ballooning with cpuplugd (fate#312069) + +------------------------------------------------------------------- +Tue May 10 15:32:37 UTC 2011 - jjolly@novell.com + +- s390-tools patchset #11 (bnc#689579) + - s390-tools-11-01-fdasd-buffer-overflow-in-error-message.patch: + fdasd: buffer overflow when writing to read-only device + (LTC#70680) + - s390-tools-11-02-cpuplugd-multiplication.patch: cpuplugd: Fix + incorrect multiplication in rules evaluation (LTC#71166) + - s390-tools-11-03-ziomon-outfile-invalid-option.patch: ziomon: + Option '--output' should be '--outfile' as documented + (LTC#71566) + - s390-tools-11-04-ziomon-debugfs-mount-path-checking.patch: + ziomon: Debugfs mount path check at /sys/kernel/debug + (LTC#71749) + +------------------------------------------------------------------- +Tue Apr 26 22:46:39 UTC 2011 - jjolly@novell.com + +- fdasd: added -f options to force execution on non-dasd devices + (bnc#689018) + +------------------------------------------------------------------- +Tue Feb 22 23:37:52 UTC 2011 - jjolly@novell.com + +- s390-tools patchset #10 (bnc#652287) + - s390-tools-10-01-ziomon-returncodes.patch: ziomon: ziomon + tools return 1 when using option -h, --help and -v (LTC#66507) + - s390-tools-10-02-qethconf-subchset.patch: qethconf: process + devices with subchannel set != 0 (LTC#66662) + - s390-tools-10-03-iucvtty-login-h.patch: iucvtty: do not + specify z/VM user ID as argument to login -h (LTC#66393) + - s390-tools-10-04-fdasd-format7-label.patch: fdasd/dasdfmt: fix + format 7 label (LTC#68122) + - s390-tools-10-05-cpuplugd-cmm_pages.patch: cpuplugd: cmm_pages + not set and restored correctly (LTC#68341) + - s390-tools-10-06-lsluns-svc.patch: lsluns: Fix LUN reporting + for SAN volume controller (SVC) (LTC#68559) + - s390-tools-10-07-lsluns-uppercase.patch: lsluns: Accept + uppercase and lowercase hex digits (LTC#68562) + +------------------------------------------------------------------- +Tue Aug 10 15:18:56 CEST 2010 - jjolly@suse.de + +- s390-tools patchset #9 (bnc#621182) + - s390-tools-09-01-ts-shell-group-names.patch: ts-shell: do not + restrict group names to be alphanumeric (LTC#61504) + - s390-tools-09-02-znetconf-driveroption.patch: znetconf: + --drive|-d option returning "unknown driver" for qeth + (LTC#64732) + - s390-tools-09-03-cpuplugd-stack-smash.patch: cpuplugd: fix + stack overwrite (LTC#64733) + - s390-tools-09-04-zfcpdbf-dates.patch: zfcpdbf: Fix --dates + option (LTC#65405) + - s390-tools-09-05-cpuplugd-cmm-limits.patch: cpuplugd: fix + cmm_min/max limit checks (LTC#65220) + - s390-tools-09-06-cpuplugd-cpu_min.patch: cpuplugd: set cpu_min + to 1 by default (LTC#65224) + - s390-tools-09-07-lsluns-adapter-offline.patch: lsluns: + uninitialized value on adapter offline (LTC#65768) + - s390-tools-09-08-zfcpdbf-uninitialized.diff: zfcpdbf: Fix "Use + of uninitialized value" and output issues (LTC#65904) + - s390-tools-09-09-xcec-mc.patch: xcec-bridge: Fix multicast + forwarding (LTC#66141) + +------------------------------------------------------------------- +Wed Jun 2 11:23:55 CEST 2010 - sf@suse.de + +- dasd_reload: iterate over all dasd udev-rules (bnc #606394) + +------------------------------------------------------------------- +Fri May 7 07:26:41 CEST 2010 - jjolly@suse.de + +- s390-tools-08-01-lsqeth-clear-print-array.patch: lsqeth: add + clearing of print array for every qeth device + (bnc#602015,LTC#63091) +- dasd_configure: Properly handling exit when dasd status is + unformatted (bnc#601918) +- dasdfmt.8: removed extra -P reference from man page (bnc#602003) + +------------------------------------------------------------------- +Thu Apr 22 17:11:53 CEST 2010 - jjolly@suse.de + +- s390-tools-07-01-lsdasd-document-option-b.patch: lsdasd: add + missing description of option -b to man page + (bnc#597838,LTC#62575) +- s390-tools-07-02-lsqeth-sysfs.patch: lsqeth: sysfs mount point + not determined (bnc#597838) + +------------------------------------------------------------------- +Mon Apr 19 22:18:40 CEST 2010 - jjolly@suse.de + +- s390-tools-sles11sp1-lsmem-chmem-v2.patch: lsmem/chmem: Tools to + manage memory hotplug. + +------------------------------------------------------------------- +Tue Apr 13 12:48:59 CEST 2010 - ihno@suse.de + +- disabled s390-tools-0001-Zipl-VirtIO-bootloader-code.patch + +------------------------------------------------------------------- +Tue Apr 13 12:30:05 CEST 2010 - agraf@suse.de + +- s390-tools-0001-Zipl-VirtIO-bootloader-code.patch: disable stack + protector (bnc#594445) + +------------------------------------------------------------------- +Fri Apr 9 07:44:50 CEST 2010 - jjolly@suse.de + +- s390-tools-0001-Zipl-VirtIO-bootloader-code.patch: enable virtio + bootloading (bnc#594445) + +------------------------------------------------------------------- +Mon Mar 29 20:33:48 CEST 2010 - jjolly@suse.de + +- IBM 390-tools patchset #6 (bnc#591089) + - s390-tools-sles11sp1-06-01-ziomon_fix_df_output.patch: ziomon: + Fix 'df' command usage (LTC#61794) + - s390-tools-sles11sp1-06-02-ziomon_fix_wrong_install_path.patch: + ziomon: Remove check for ziorep_config availability (LTC#61801) + - s390-tools-sles11sp1-06-03-zipl-force-help.patch: zipl: Option + "--force" is not included in text for "--help" (LTC#61973) + - s390-tools-sles11sp1-06-04-ziomon-fix_multipathing.patch: + ziomon: Fix problem with multipath command output (LTC#61977) + +------------------------------------------------------------------- +Fri Mar 12 04:48:06 CET 2010 - jjolly@suse.de + +- IBM s390-tools patchset #5 (bnc#587152) + - s390-tools-sles11sp1-05-01-zfcpdump-directio.patch: + zfcpdump: Use direct IO in order to increase dump speed + - s390-tools-sles11sp1-05-02-zipl_zfcp_partition.patch: + zipl: zfcp dump partition error + +------------------------------------------------------------------- +Fri Mar 12 04:39:05 CET 2010 - jjolly@suse.de + +- zipl/zfcpdump: Use "cgroup_disable=memory" kernel parameter + (bnc#572716) + +------------------------------------------------------------------- +Fri Mar 12 04:27:08 CET 2010 - jjolly@suse.de + +- mkswap.sh: Using udevadm instead of udevinfo (bnc#585130) + +------------------------------------------------------------------- +Mon Feb 22 07:59:02 CET 2010 - jjolly@suse.de + +- vmconvert: Fix progress bar shows garbage (bnc#580976,LTC#60883) + +------------------------------------------------------------------- +Fri Feb 19 22:05:22 CET 2010 - jjolly@suse.de + +- dasd_configure: do not set unformatted dasd offline (bnc#579584) + +------------------------------------------------------------------- +Mon Feb 8 14:03:39 CET 2010 - uli@suse.de + +- dasd_configure: avoid unnecessary delays (bnc#561876) + +------------------------------------------------------------------- +Tue Feb 2 11:55:58 CET 2010 - jjolly@suse.de + +- Patchset #3 (bnc#575676) including: + - s390-tools-sles11sp1-03-01-zipl-handle-ssch-status.patch: zipl: + handle status during IPL SSCH (LTC#59816) + - s390-tools-sles11sp1-03-02-chshut-disable-panic.patch: chshut: + Mismatch between man and -h (LTC#59864) + - s390-tools-sles11sp1-03-03-znetconf-chpidtypes-hex.patch: + znetconf: index into chpidtype lookup table must be hex. + +------------------------------------------------------------------- +Mon Jan 25 17:16:44 CET 2010 - uli@suse.de + +- add error codes 7 (failed to activate) and 8 (not formatted) + to dasd_configure (bnc#561876) + +------------------------------------------------------------------- +Mon Jan 25 16:59:12 CET 2010 - jjolly@suse.de + +- Add missing check and print NSS name in case an NSS has been + IPLed. (bnc#559509) + - Add missing NULL string termination when reading sysfs attributes + - Fix possible SIGSEGV for "chreipl node /dev/dasdxy" + +------------------------------------------------------------------- +Mon Jan 25 10:54:05 CET 2010 - jjolly@suse.de + +- Patchset #2 (bnc#566684,LTC#59000) including: + - s390-tools-sle11sp1-01-znetconf-returncodes.patch + - s390-tools-sle11sp1-02-ziorep-returncodes.patch (LTC#59379) + - s390-tools-sle11sp1-03-lstape_returncodes.patch (LTC#59386) + - s390-tools-sle11sp1-04-lscss-fix-tr-quoting.patch + - s390-tools-sle11sp1-05-lsqeth-new-attributes.patch +- Init info->yastmode in dasdfmt.c (bnc#571653,LTC#59524) +- zfcpdump: removed static linking (bnc#572716) + +------------------------------------------------------------------- +Tue Jan 12 12:58:03 CET 2010 - uli@suse.de + +- dasd_configure: give DASD some time to warm up (untested, + bnc#561876) + +------------------------------------------------------------------- +Mon Dec 7 12:52:51 CET 2009 - hare@suse.de + +- zipl: Handle device-mapper devices (bnc#556208) + +------------------------------------------------------------------- +Thu Dec 3 16:16:40 CET 2009 - jjolly@suse.de + +- s390-tools, 59-dasd.rules: fix path to vol_id (bnc#554038) +- dasdview, fdasd: fix floating point error for unformatted devices + (bnc#554038) +- ziomon: Fix multipath device detection (bnc#554038) +- zipl: handle status during ipl (bnc#554038) + +------------------------------------------------------------------- +Sat Nov 21 00:26:45 CET 2009 - jjolly@suse.de + +- Reverted last change in order to add s390-tools 1.8.2 features: + - tty terminal server over IUCV (bnc#546431,FATE#307002) + - Large Volume support (bnc#546431,FATE#307003) + - DS8000 Disk Encryption (bnc#546431,FATE#307004) + - show disk encryption status + - FICON - Format Record 0 on ECKD devices (bnc#546431,FATE#307012) + - FCP - Performance data reports (bnc#546431,FATE#307000) + - Automatic IPL after dump (bnc#546431,FATE#307009) + - Add vmconvert option to vmur tool (bnc#546431,FATE#307010) + - Automatic scan of network devices (bnc#546431,FATE#307016) +- Bugfixes: + - general: Fix compile warnings & do minor bugfixes + - general: Adjust code to s390-tools upstream as far as possible + - lsreipl: Show defined vmcmd correctly + - fdasd: Fix auto mode behavior + - general: Corrections to comply with SUSE rpmlint +- Performance enhancements: + - dasd,zfcp: Add udev rule to set increased "default max readahead" + +------------------------------------------------------------------- +Wed Nov 18 17:42:21 CET 2009 - uli@suse.de + +- update -> 1.8.1: + - IUCV terminal server (fate#307002) + - DASD large volume support (fate#307003) + - obsoletes a ton of patches + +------------------------------------------------------------------- +Fri Nov 6 13:24:29 CET 2009 - hare@suse.de + +- Include mkinitrd scripts to setup qeth networking (bnc#541405) +- Fixup vol_id pathname in mkdump.sh (bnc#505553) + +------------------------------------------------------------------- +Sat Oct 17 06:06:07 CEST 2009 - jjolly@suse.de + +- Added s390-tools-sles11sp1-dasdfmt-norecord_r0.patch (bnc#477816) + +------------------------------------------------------------------- +Mon Oct 12 18:20:03 CEST 2009 - jjolly@suse.de + +- s390-tools-02-cpuplugd-cmminit.patch: cpuplugd: fix cmm + configuration file value initialization parser + (bnc#519430,LTC#54629) +- s390-tools-02-cpuplugd-limit.patch: cpuplugd: fix cmm_pages + allocation outside min and max range (bnc#519430,LTC#55472) +- s390-tools-02-cpuplugd-parser.patch: cpuplugd: Daemon does not + work in a memplug only environment (bnc#519430,LTC#54285) +- s390-tools-02-dasdinfo-fix-volume-serial.patch: dasdinfo: spaces + in volume serial break udev device links (bnc#519430,LTC#52881) +- s390-tools-02-dbginfo-remove-cpint.patch: dbginfo.sh: remove + occurences of "cpint" (bnc#519430,LTC#54777) +- s390-tools-02-zipl-fix-unsupported-device-driver.patch: zipl: + zipl does not exit for an unsupported device driver. + (bnc#519430,LTC#53660) + +------------------------------------------------------------------- +Thu Apr 23 21:27:09 CEST 2009 - jjolly@suse.de + +- dasdro: Updated hcp to vmcp (bnc#492504) + +------------------------------------------------------------------- +Tue Mar 31 23:16:37 CEST 2009 - jjolly@suse.de + +- s390-tools-01-dasdfmt-retry-reread-partition-table.patch: + dasdfmt: retry when BLKRRPART fails (bnc#486043,LTC#52233) +- s390-tools-01-dasdinfo_sysfs.patch: dasdinfo: error with new + sysfs layout (bnc#486043,LTC#52309) +- s390-tools-01-dasdview-fix-busid-lookup.patch: dasdview: fix + busid look-up (bnc#486043,LTC#52122) +- s390-tools-01-fdasd-buffer-overflow.patch: fdasd: fix buffer + overflow for long device names (bnc#486043,LTC#51817) +- s390-tools-01-ipl-panic.patch: lsshut: lsshut prints out an + unnecessary error message (bnc#486043) +- s390-tools-01-ziomon-scsi-tapes.patch: ziomon: SCSI tapes do not + work (bnc#486043,LTC#51282) +- s390-tools-01-zipl-fbadump-4gb.patch: zipl: FBA dump tool can + only dump up to 4GB. (bnc#486043,LTC#52257) + +------------------------------------------------------------------- +Tue Feb 24 22:47:45 CET 2009 - ihno@suse.de + +- Add a check in dasd_configure to check environment (LPAR or z/VM) + (bnc#477705) +- Add a general README.SUSE about commands provided by SUSE + (bnc#478009) +- Fix online help of zfcp_san_disc and added online for some + other commands (bnc#471830) + +------------------------------------------------------------------- +Thu Feb 19 14:36:07 CET 2009 - uli@suse.de + +- hsnc: pass OSA IF name to ip_watcher.pl (bnc#472366) + +------------------------------------------------------------------- +Wed Feb 18 11:43:49 CET 2009 - hare@suse.de + +- Fix remaining reference to hard-coded ECKD in dasd_configure + (bnc#470408) + +------------------------------------------------------------------- +Mon Feb 9 16:16:17 CET 2009 - uli@suse.de + +- dasdfmt: propagate child exit codes (bnc#459677) + +------------------------------------------------------------------- +Fri Feb 6 15:44:35 CET 2009 - hare@suse.de + +- Return error code if sg_luns failed in zfcp_san_disc (bnc#472352) +- Correctly configure FBA disks (bnc#470408) + +------------------------------------------------------------------- +Thu Feb 5 13:53:28 CET 2009 - uli@suse.de + +- use sysfs instead of /proc/qeth (bnc#472366) + +------------------------------------------------------------------- +Mon Jan 26 16:11:29 CET 2009 - hare@suse.de + +- Add %triggerin section to create zfcpdump correctly (bnc#446367) + +------------------------------------------------------------------- +Fri Jan 23 14:33:19 CET 2009 - uli@suse.de + +- fix boot.cpi behavior (bnc#457208) +- change CPI_SET default to yes (bnc#455978) + +------------------------------------------------------------------- +Thu Jan 22 15:12:04 CET 2009 - jjolly@suse.de + +- Initialize error value to 0 (bnc#467275) + +------------------------------------------------------------------- +Mon Jan 19 15:29:11 CET 2009 - uli@suse.de + +- run insserv on boot.cpi, write to set attribute to pass CPI + data (bnc#455978) + +------------------------------------------------------------------- +Mon Jan 12 16:26:03 CET 2009 - jjolly@suse.de + +- Added /usr/sbin/osasnmpd link to /usr/sbin/osasnmpd-2.6 + (bnc#458547) + +------------------------------------------------------------------- +Fri Jan 9 17:51:07 CET 2009 - jjolly@suse.de + +- s390-tools-sles11-ziomon-fix-qdio-statistics.patch: Fix qdio + statistics (bnc#417514) + +------------------------------------------------------------------- +Thu Dec 11 17:06:44 CET 2008 - hare@suse.de + +- Create /boot/zipl directory (bnc#457942) + +------------------------------------------------------------------- +Thu Dec 11 12:30:02 CET 2008 - hare@suse.de + +- Update mkinitrd scripts for zfcpdump (bnc#446367) +- Include patches from IBM (bnc#417514): + * Fix lszfcp -P after removal of a port + * Allow zfcpdump to work in more initrds + * tape390_display: Fix stack overwrite + +------------------------------------------------------------------- +Wed Dec 10 20:15:11 CET 2008 - jjolly@suse.de + +- Remove -s option from install sections in Makefiles. (bnc#417514) + +------------------------------------------------------------------- +Wed Dec 10 12:37:25 CET 2008 - hare@suse.de + +- Add mkinitrd requirement [bnc#457945] + +------------------------------------------------------------------- +Mon Dec 8 17:42:51 CET 2008 - kukuk@suse.de + +- Re-enable ExclusiveArchs + +------------------------------------------------------------------- +Fri Dec 5 16:07:01 CET 2008 - hare@suse.de + +- Generate zfcpdump image correctly + +------------------------------------------------------------------- +Fri Dec 5 12:30:04 CET 2008 - hare@suse.de + +- Updated to official 1.8.0 tarball from IBM (bnc#417514) + * lsluns: Do not print full path of tool for error messages - only basename + * ipl_tools: Add some new error messages + * dumpconf: Adjust dumpconf init script to new lsdasd + * ziomon: File header comments cleanup + * dbginfo.sh: Collect more debug info + * lsdasd: Remove CVS $Revision entries + * lszfcp: Throw error message if no devices are configured + * Prevent daemons from starting in single user mode +- Remove rpmlint patch +- Generate correct udev rule for boot from zfcp (bnc#434648) + +------------------------------------------------------------------- +Tue Dec 2 15:14:39 CET 2008 - uli@suse.de + +- fixed broken post/preun scripts (bnc#446367) + +------------------------------------------------------------------- +Fri Nov 21 08:34:29 CET 2008 - hare@suse.de + +- Fixed typo in dasd_configure (bnc#446998) + +------------------------------------------------------------------- +Thu Nov 20 08:32:38 CET 2008 - jjolly@suse.de + +- Moved creation/deletion of zfcpdump.{image,rd} into specfile + %post and %preun sections. (bnc#446367) + +------------------------------------------------------------------- +Thu Nov 20 08:19:33 CET 2008 - jjolly@suse.de + +- Added script to mkdump.sh that creates zfcpdump.{image,rd} + (bnc#446427) + +------------------------------------------------------------------- +Wed Nov 19 14:53:44 CET 2008 - jjolly@suse.de + +- Updated to 1.8.0 v8 tarball from IBM (bnc#417514) + - lstape: Fix problems with new sysfs layout. + - lszfcp: Update search for sysfs mount-point. + - zipl: Fix zipl build process: Copy only text section with objcopy. + - vmconvert: Remove leading newline for error messages. + - ipl_tools: Fix various parser problems. + - cpuplugd: Prevent compile warning. +- Removed link error patch + +------------------------------------------------------------------- +Fri Nov 14 16:18:51 CET 2008 - hare@suse.de + +- Install updated dasd udev rules (bnc#444688) +- Update dasd_configure to call udevadm settle (bnc#444672) +- Install zfcpdump mkinitrd scripts (FATE#304069) + +------------------------------------------------------------------- +Tue Nov 11 16:14:47 CET 2008 - hare@suse.de + +- Updated to 1.8.0 v7 tarball from IBM (bnc#417514) +- Removed obsolete patches +- rpmlint fixes + +------------------------------------------------------------------- +Tue Nov 11 13:40:14 CET 2008 - hare@suse.de + +- Update zfcp_{disk,host}_configure to work with port + auto discovery (bnc#435640) +- Fix zfcp_san_disc to remove the correct sg device + +------------------------------------------------------------------- +Mon Nov 10 11:46:47 CET 2008 - hare@suse.de + +- Update zfcp_san_disc to check for WLUNs first (bnc#437633) + +------------------------------------------------------------------- +Thu Nov 6 15:37:07 CET 2008 - uli@suse.de + +- with all the udev red tape, we forgot to actually set the port + number... (fate #304080) + +------------------------------------------------------------------- +Tue Nov 4 10:35:34 CET 2008 - hare@suse.de + +- Wait for DASD to become online (bnc#436980) + +------------------------------------------------------------------- +Mon Oct 27 14:04:32 CET 2008 - hare@suse.de + +- Update 59-dasd.rules (bnc#436980) +- Use udevadm instead of udevsettle (bnc#437349) + +------------------------------------------------------------------- +Mon Oct 27 13:34:40 CET 2008 - jjolly@suse.de + +- Updated to 1.8.0 v6 tarball from IBM (bnc#417514) + +------------------------------------------------------------------- +Wed Oct 22 10:28:13 CEST 2008 - hare@suse.de + +- Update zfcp_san_disc to work with automatic port discovery + (bnc#433863) + +------------------------------------------------------------------- +Mon Oct 20 15:49:33 CEST 2008 - uli@suse.de + +- restored change in qeth_configure from Sep 11 2008 that was + overwritten by checkin on Sep 23 2008 (bnc #436824) + +------------------------------------------------------------------- +Tue Oct 14 13:15:14 CEST 2008 - uli@suse.de + +- restored change in dasdfmt from May 19 that was overwritten + by subsequent checkins (bnc #368595, #434223) + +------------------------------------------------------------------- +Mon Oct 13 17:42:57 CEST 2008 - jjolly@suse.de + +- Updated to 1.8.0 v5 tarball from IBM (bnc#417514) + +------------------------------------------------------------------- +Thu Oct 9 16:25:50 CEST 2008 - uli@suse.de + +- added init script setting CPI data (fate #304052) + +------------------------------------------------------------------- +Fri Sep 26 15:07:01 CEST 2008 - jjolly@suse.de + +- Patched zipl/boot link to set build-id to none + +------------------------------------------------------------------- +Wed Sep 24 17:48:19 CEST 2008 - jjolly@suse.de + +- Updated to 1.8.0 v4 of the tarball +- Added the blktrace_api.h as it doesn't exist in + linux-kernel-headers at this time. + +------------------------------------------------------------------- +Tue Sep 23 09:52:20 CEST 2008 - hare@suse.de + +- Fix qeth_configure to always set the 'layer2' attribute + (bnc#428352) +- Update ctc_configure to set the protocol number correctly. + +------------------------------------------------------------------- +Fri Sep 19 13:20:28 CEST 2008 - hare@suse.de + +- Update dasd_reload script to work with udev rules (bnc#427458) + +------------------------------------------------------------------- +Thu Sep 18 17:39:46 CEST 2008 - jjolly@suse.de + +- Updated to 1.8.0 v3 of the tarball +- Patched make to remove .note.gnu.build-id header during objcopy + +------------------------------------------------------------------- +Thu Sep 11 15:45:57 CEST 2008 - uli@suse.de + +- qeth_configure: added -n option for specifying the port number + (fate #304080) + +------------------------------------------------------------------- +Wed Sep 3 11:09:34 CEST 2008 - hare@suse.de + +- Call mkinitrd_setup during %post and %postun (bnc#413709) +- Fix qeth_configure script +- Fix iucv_configure script + +------------------------------------------------------------------- +Tue Sep 2 18:08:41 CEST 2008 - jjolly@suse.de + +- Removed lib-zfcp-hbaapi to it's own package. +- Update to 1.8.0 + +------------------------------------------------------------------- +Thu Aug 7 15:26:37 CEST 2008 - hare@suse.de + +- Update ctc_configure to use ctcm module instead of ctc + +------------------------------------------------------------------- +Fri Jul 25 10:42:36 CEST 2008 - hare@suse.de + +- Add network configuration scripts (iucv|ctc|qeth)_configure +- Include mkinitrd scriptlets. +- Fix RPMLint warnings. + +------------------------------------------------------------------- +Tue Jul 22 08:19:02 CEST 2008 - hare@suse.de + +- Compress s390-tools-1.7.0 with bzip2 + +------------------------------------------------------------------- +Mon Jul 21 16:15:57 CEST 2008 - hare@suse.de + +- Update to 1.7.0 +- Build fixes for autobuild +- Build zfcpdump_v2 only + +------------------------------------------------------------------- +Fri Jul 18 16:23:44 CEST 2008 - hare@suse.de + +- Backport from SLES10 SP2 +- Update dasd_configure and zfcp_disk_configure script + +------------------------------------------------------------------- +Mon May 19 13:57:50 CEST 2008 - uli@suse.de + +- make old dasdfmt syntax work again (bnc#368595) + +------------------------------------------------------------------- +Fri Apr 18 10:50:56 CEST 2008 - hare@suse.de + +- Update to 1.6.3-v10 (bnc#380728) + * cpuplugd: cpuplugd could not be stopped + +------------------------------------------------------------------- +Fri Apr 4 09:57:25 CEST 2008 - hare@suse.de + +- Update to 1.6.3-v9 (bnc#376700) + * extend dasdinfo with a new compat-uid option + * cpuplugd: cpuplugd may loop on systems with only 1 cpu + * vmur: Fix man page + +------------------------------------------------------------------- +Mon Mar 17 14:42:33 CET 2008 - hare@suse.de + +- Update to 1.6.3-v8 (bnc#354137) + +------------------------------------------------------------------- +Mon Mar 3 15:02:07 CET 2008 - hare@suse.de + +- Fix build + +------------------------------------------------------------------- +Thu Feb 28 16:34:49 CET 2008 - hare@suse.de + +- Update to 1.6.3-v7 (bnc#365614) +- Update to libzfcp-hbaapi-1.4.2 (bnc#365612) + +------------------------------------------------------------------- +Mon Feb 18 15:44:13 CET 2008 - hare@suse.de + +- update to 1.6.3-v6 tarball +- Install cpuhotplugd (#341388, FATE#302806) +- Add zfcp_san_disc script (#361848) + +------------------------------------------------------------------- +Tue Jan 22 18:15:30 CET 2008 - jjolly@suse.de + +- update to 1.6.3-v3 tarbar (#355355) +- added cpuplugd config file to package (#355355) + +------------------------------------------------------------------- +Tue Nov 20 23:15:40 CET 2007 - jjolly@suse.de + +- update -> 1.6.3 (#341393) + +------------------------------------------------------------------- +Thu Oct 11 19:01:42 CEST 2007 - jjolly@suse.de + +- Modified script to wait for hbaapi module to complete loading + (#332251) + +------------------------------------------------------------------- +Wed Oct 10 14:51:22 CEST 2007 - jjolly@suse.de + +- Added zfcp_san_disc utility (#332458) + +------------------------------------------------------------------- +Thu Sep 13 18:36:46 CEST 2007 - jjolly@suse.de + +- Added priority value for SWAPON within /etc/init.d/xpram + (#308074) + +------------------------------------------------------------------- +Sat Jul 14 00:48:14 CEST 2007 - jjolly@suse.de + +- Correctly return error codes in mkdump.sh (#276429) + +------------------------------------------------------------------- +Thu Mar 8 14:55:03 CET 2007 - hare@suse.de + +- Install mon_fsstatd correctly (#252115) + +------------------------------------------------------------------- +Mon Mar 5 16:24:27 CET 2007 - hare@suse.de + +- update -> 1.6.0 + * Implement dasdinfo and supply own udev rules (#222326) +- Fix major/minor number problem (#245342) +- install mon_fsstatd sysconfig and init scripts + +------------------------------------------------------------------- +Mon Feb 19 14:15:04 CET 2007 - uli@suse.de + +- update -> 1.6.0-v7 (documentation touchups, prevent fs corruption + when running zipl on linear dm targets) + +------------------------------------------------------------------- +Fri Feb 2 14:07:46 CET 2007 - hare@suse.de + +- update -> 1.6.0-v5 + * Expand S390_TOOLS_RELEASE macro correctly (#240667) + * Install the dumpconf utility +- Fix compilation issues. + +------------------------------------------------------------------- +Wed Jan 31 10:29:03 CET 2007 - hare@suse.de + +- update -> 1.6.0-v4: + * tape390_crpyt: Enhanced error handling + * New man page for /dev/prandom + +------------------------------------------------------------------- +Fri Jan 19 15:59:50 CET 2007 - hare@suse.de + +- update -> 1.6.0-v3; + Fixup 3590 crypt support. + +------------------------------------------------------------------- +Tue Jan 16 13:08:28 CET 2007 - hare@suse.de + +- zfcp_host_configure: modify the dev_loss_tmp setting + to 30 (bug #220556) + +------------------------------------------------------------------- +Thu Jan 11 13:18:49 CET 2007 - uli@suse.de + +- update -> 1.6.0-v2 +- fixed regexes in zfcp_disk_configure (bug #185798) + +------------------------------------------------------------------- +Fri Nov 3 15:01:14 CET 2006 - hare@suse.de + +- Fix build against new libsysfs. + +------------------------------------------------------------------- +Mon Jun 19 17:01:59 CEST 2006 - hare@suse.de + +- zfcp_disk_configure: translate the entire WWPN + string (#185798 - LTC24706) + +------------------------------------------------------------------- +Fri Jun 2 13:16:15 CEST 2006 - hare@suse.de + +- mkdump.sh: wait for udev to finish before continuing + (#163258 - LTC22904) + +------------------------------------------------------------------- +Fri May 19 15:26:16 CEST 2006 - hare@suse.de + +- Fix build of zgetdump (#176334 - LTC23955) +- Fix Makefile options +- Fix error messages for zfcp_(disk|host)_configure + (#159552 - LTC22536) + +------------------------------------------------------------------- +Thu May 18 11:44:12 CEST 2006 - hare@suse.de + +- mkdump.sh: fix check_devsize (#165818) + +------------------------------------------------------------------- +Tue May 9 22:31:50 CEST 2006 - ihno@suse.de + +- fixed activation of XPRAM devices. (#161352) + +------------------------------------------------------------------- +Fri Apr 28 13:51:23 CEST 2006 - hare@suse.de + +- mkdump.sh: use sfdisk instead of parted; + Fixup error messages (#165818) + +------------------------------------------------------------------- +Fri Apr 21 15:38:31 CEST 2006 - hare@suse.de + +- dasd_configure: Remove hwcfg file on deconfiguring device even + if no ccw device exists. + +------------------------------------------------------------------- +Wed Apr 19 22:14:54 CEST 2006 - ihno@suse.de + +- create mountpoint, if it does not exist (#157108) +- force the creation of swap/filesystem (#161363) + +------------------------------------------------------------------- +Thu Apr 13 16:06:31 CEST 2006 - uli@suse.de + +- dasdfmt: fixed man page, can now specify >1 device with -n, + support x.x.xxxx notation (bug #160058) + +------------------------------------------------------------------- +Fri Apr 7 11:20:09 CEST 2006 - hare@suse.de + +- Fix zfcp_disk_configure again (#160161 - LTC22622) +- mkdump.sh should wait for udev (#163258 - LTC22904) +- Install all scripts with the rpm (#162939 - LTC22876) + +------------------------------------------------------------------- +Fri Mar 24 16:28:30 CET 2006 - hare@suse.de + +- Update to s390-tools-1.5.3 +- Fix zipl boot message (#145612) +- Fix zfcp_disk_configure to correctly deactivate disks + (#160161 - LTC22622) + +------------------------------------------------------------------- +Thu Mar 23 16:39:39 CET 2006 - uli@suse.de + +- osasnmpd was inadvertently built for ucd-snmp; fixed + (bug #159501) + +------------------------------------------------------------------- +Wed Feb 22 09:58:53 CET 2006 - hare@suse.de + +- Update to s390-tools-1.5.2 +- Update to lib-zfcp-hbaapi-1.4 +- dasd_configure should wait for udev before calling vmcp + (#149490 - LTC21537) +- Fix mkdump to not use blkid +- Minor fixes to mkdump + +------------------------------------------------------------------- +Wed Feb 8 12:40:32 CET 2006 - ihno@suse.de + +- fixed xpram to handle swap and + to keep the existing filesystem (#148662) + +------------------------------------------------------------------- +Wed Jan 25 21:45:00 CET 2006 - mls@suse.de + +- converted neededforbuild to BuildRequires + +------------------------------------------------------------------- +Tue Jan 24 17:02:32 CET 2006 - hare@suse.de + +- Unset DEBUG variable in dasd_configure +- Use 'vmcp' command instead of deprecated 'hcp' + +------------------------------------------------------------------- +Wed Jan 18 14:14:54 CET 2006 - hare@suse.de + +- Adding 'devs' to neededforbuild. + +------------------------------------------------------------------- +Thu Dec 15 16:35:12 CET 2005 - uli@suse.de + +- actually apply e2fsprogs patches +- replace get_user macro in kernel with version from 2.6.15 +- fix C++ errors in vmconvert +- create /boot/zipl directory + +------------------------------------------------------------------- +Tue Dec 6 10:32:00 CET 2005 - hare@suse.de + +- Update package to SLES9 SP3 version. + +------------------------------------------------------------------- +Fri Nov 11 11:41:01 CET 2005 - hare@suse.de + +- Write default values from zfcp_disk_configure (#120657 - LTC18813) +- Update to lib-zfcp-hbaapi-1.3 + +------------------------------------------------------------------- +Tue Nov 8 23:19:37 CET 2005 - ihno@suse.de + +- Update to Developer Codedrop 1.5.1 + +------------------------------------------------------------------- +Tue Oct 25 08:52:23 CEST 2005 - hare@suse.de + +- Fixed inconsistencies with lsdasd man page and online help. +- Check command line parameters of zfcpdbf for validity. + +------------------------------------------------------------------- +Fri Oct 21 13:53:42 CEST 2005 - hare@suse.de + +- Fix dasd_configure to handle DIAG mode correctly + (bugs #120166, #129704). + +------------------------------------------------------------------- +Tue Oct 18 17:25:47 CEST 2005 - uli@suse.de + +- start/killproc can't handle wrapper scripts; worked around + (bugs #127534, #127535) + +------------------------------------------------------------------- +Thu Sep 29 14:30:18 CEST 2005 - hare@suse.de + +- Fix vmlogrdr init script (#118581). + +------------------------------------------------------------------- +Fri Sep 23 15:45:36 CEST 2005 - hare@suse.de + +- Fix build of dasdfmt (#118027). +- Use RPM_OPT_FLAGS for build + +------------------------------------------------------------------- +Tue Sep 20 14:58:36 CEST 2005 - hare@suse.de + +- Update to s390-tools-1.5.0 (#117968). + +------------------------------------------------------------------- +Thu Jun 30 18:32:45 CEST 2005 - uli@suse.de + +- fixed neededforbuild + +------------------------------------------------------------------- +Mon Jun 20 11:48:21 CEST 2005 - hare@suse.de + +- Update to s390-tools-1.4.1 (#88526). + +------------------------------------------------------------------- +Wed Jun 15 16:59:48 CEST 2005 - uli@suse.de + +- add sysconfig file for osasnmpd parameters (bug #86631) +- fixed assembler syntax in zipl (stricter checking in new gas) + +------------------------------------------------------------------- +Wed Jun 15 16:17:25 CEST 2005 - yxu@suse.de + +- fix build with GCC4 +- add prebuild images and ramdisk for zfcp + +------------------------------------------------------------------- +Wed Jun 15 10:56:43 CEST 2005 - hare@suse.de + +- Fix start_hsnc.sh (#88526). + +------------------------------------------------------------------- +Tue Apr 19 16:47:18 CEST 2005 - hare@suse.de + +- Update to s390-tools-1.4.0 +- Include lib-zfcp-hbaapi-1.2 + +------------------------------------------------------------------- +Fri Nov 26 16:51:34 CET 2004 - hare@suse.de + +- Added new CU types 2107 and 1750 to dasd_configure (#48587). + +------------------------------------------------------------------- +Thu Nov 18 12:12:27 CET 2004 - hare@suse.de + +- Added /sbin/mkdump script for creating dump devices (#22182). + +------------------------------------------------------------------- +Wed Nov 10 01:14:35 CET 2004 - ro@suse.de + +- fix typo in specfile + +------------------------------------------------------------------- +Fri Nov 5 11:48:09 CET 2004 - hare@suse.de + +- Update to s390-tools-1.3.2 +- Fix output at formatting of >26 disks (#47699). + +------------------------------------------------------------------- +Wed Jul 14 08:39:45 CEST 2004 - hare@suse.de + +- Fixed default polling interval for appldata (#42694). + +------------------------------------------------------------------- +Mon Jul 5 15:21:46 CEST 2004 - uli@suse.de + +- rename osasnmpd-2.6 -> osasnmpd (bug #42588) + +------------------------------------------------------------------- +Mon Jul 5 15:03:45 CEST 2004 - hare@suse.de + +- Fixed init-scripts for appldata (#42694). +- Updated sysconfig files to correctly display variables. + +------------------------------------------------------------------- +Tue Jun 15 15:46:57 CEST 2004 - hare@suse.de + +- Fix cpint usage in initrd (no hcp available). + +------------------------------------------------------------------- +Mon Jun 14 19:57:10 CEST 2004 - ihno@suse.de + +- enabled and fixed osasnmpd generation (#41893) +- removed unused patch (fix is part of update 9 june) + +------------------------------------------------------------------- +Wed Jun 9 16:46:32 CEST 2004 - hare@suse.de + +- Update to s390-tools 1.3.1 (#41736). + +------------------------------------------------------------------- +Mon Jun 7 16:25:56 CEST 2004 - uli@suse.de + +- added missing %fillup_prereq (bug #41732) + +------------------------------------------------------------------- +Fri Jun 4 11:29:16 CEST 2004 - hare@suse.de + +- Check read-only status from dasd_configure (#38817) + +------------------------------------------------------------------- +Tue Jun 1 18:27:15 CEST 2004 - bk@suse.de + +- xpram script updated regarding checking of config settings(#40733) + +------------------------------------------------------------------- +Tue Jun 1 16:05:11 CEST 2004 - uli@suse.de + +- dasdro: do not rely on automatic loading of cpint module (bug #38817) + +------------------------------------------------------------------- +Thu May 27 21:16:37 CEST 2004 - ihno@suse.de + +- fixed uninitialized variable in fdasd (#40032) + +------------------------------------------------------------------- +Wed May 26 17:28:57 CEST 2004 - hare@suse.de + +- Fixed dasd_reload script to correctly reload any + configured DASD devices. +- Fixed zfcp_disk_configure to handle uppercase WWPNs +- Fixed dasd_configure to correctly handle DIAG devices +- Fixed dasd_configure to generate hwcfg files with correct + SCRIPTDOWN values. + +------------------------------------------------------------------- +Tue May 25 16:39:35 CEST 2004 - hare@suse.de + +- Added dasd_reload script for YaST2. + +------------------------------------------------------------------- +Tue May 18 17:16:14 CEST 2004 - uli@suse.de + +- fixed incorrect use of fillup_and_insserv (bug #40733) + +------------------------------------------------------------------- +Mon Apr 26 13:37:03 CEST 2004 - uli@suse.de + +- added dasdro script +- fixed warning in e2fsprogs code + +------------------------------------------------------------------- +Mon Apr 26 09:37:35 CEST 2004 - hare@suse.de + +- Fixed dasd_configure to not write hwcfg file if the + directory does not exist (#39387) + +------------------------------------------------------------------- +Fri Apr 23 16:38:17 CEST 2004 - hare@suse.de + +- Update to final version s390-tools-1.3.0 +- Fixed zfcp_host_configure to use sh instead of bash +- Fixed zfcp_disk_configure to not try to delete hwcfg-file + if the directory does not exist. + +------------------------------------------------------------------- +Tue Apr 6 14:24:56 CEST 2004 - hare@suse.de + +- Update *_configure scripts to only write hwcfg files + if directory exists +- Fix dasd_configure to load modules. + +------------------------------------------------------------------- +Fri Apr 2 16:47:53 CEST 2004 - hare@suse.de + +- Fixed xpram startup script. + +------------------------------------------------------------------- +Fri Mar 12 15:17:22 CET 2004 - uli@suse.de + +- made YaST mode easier to parse as reqd. by jsrain + +------------------------------------------------------------------- +Fri Mar 5 15:58:20 CET 2004 - hare@suse.de + +- Update to pre-Lobster codedrop. +- Added dasd/zfcp configuration scripts. +- Update to allow for preconfigured builds. + +------------------------------------------------------------------- +Fri Dec 19 16:16:50 CET 2003 - uli@suse.de + +- merged bk's changes from SLES8: + change hsnc to use sysconfig configuration style + +------------------------------------------------------------------- +Wed Dec 17 16:37:05 CET 2003 - uli@suse.de + +- dasdfmt: added parallel formatting +- dasdfmt: added easily parseable output mode ("YaST mode") + +------------------------------------------------------------------- +Tue Dec 16 16:39:45 CET 2003 - bk@suse.de + +- fix path of snmp agent directory in the ucd-snmp case + +------------------------------------------------------------------- +Fri Dec 12 16:58:23 CET 2003 - bk@suse.de + +- Version 1.2.3 with hsnc for SLES8(post-SP3-maint) and SLES9! +- add rc script for the HiperSockets Network Concentrator(hsnc) +- add spec support for using ucdsnmp on SLES8 and net-snmp on SLES9 +- add support to build the zfcpdump kernel in parallel using #jobs + +------------------------------------------------------------------- +Fri Nov 28 16:19:49 CET 2003 - bk@suse.de + +- Update to version 1.2.3 + +------------------------------------------------------------------- +Fri Nov 21 17:07:14 CET 2003 - hare@suse.de + +- Added missing '-lwrap' to osasnmpd. + +------------------------------------------------------------------- +Thu Nov 13 08:45:54 CET 2003 - hare@suse.de + +- Update to version 1.2.2 +- Checked in for STABLE / pre-SLES9. +- Update to use net-snmp instead of ucdsnmp. + +------------------------------------------------------------------- +Fri Oct 31 11:15:08 CET 2003 - ihno@suse.de + +- Update to zfcpdump to the one of version 1.2.2 + +------------------------------------------------------------------- +Tue Sep 2 18:27:41 CEST 2003 - hare@suse.de + +- Fixed changelog entry. + +------------------------------------------------------------------- +Wed Aug 27 18:34:23 CEST 2003 - hare@suse.de + +- Fixed zipl to use the correct path for zfcpdump.[image|rd] + (Bugzilla #29147). + +------------------------------------------------------------------- +Mon Jul 28 15:44:25 CEST 2003 - hare@suse.de + +- update from version 1.2.0 to 1.2.1 + - Fixed zfcpdump with ext2 ramdisk + +------------------------------------------------------------------- +Thu Jul 24 15:25:16 CEST 2003 - hare@suse.de + +- update from version 1.1.5 to 1.2.0 + - new zfcpdump for dumping on FC devices + - zipl now handles config files internally + - removed parsecfg + - included linux-2.4.19, busybox and e2fsprogs for + zfcpdump building + +------------------------------------------------------------------- +Wed Feb 5 15:52:31 CET 2003 - ihno@suse.de + +- update from version 1.1.3 to 1.1.5 + - remote gcc3.3 warnings (tape390_display) + - fixed dasdfmt.8 manpage + - fixed "free track" handling of fdasd + +------------------------------------------------------------------- +Wed Oct 23 15:24:03 CEST 2002 - bk@suse.de + +- add s390-tools-1.1.3-dasdviewfix.diff and manpage for /proc/chandev + +------------------------------------------------------------------- +Fri Sep 27 10:53:02 CEST 2002 - bk@suse.de + +- fix error message which will confuse some clients for sure(IBM) + +------------------------------------------------------------------- +Wed Aug 21 16:39:26 CEST 2002 - froh@suse.de + +- fix rcchandev to no longer source rc.config +- update to s390-tools-1.1.3-may2002.tar.gz from 2002-08-08 drop: + * osasnmpd: added new parameter '-x SOCKADDR' + +------------------------------------------------------------------- +Thu Aug 1 16:58:28 CEST 2002 - bk@suse.de + +- update to s390-tools-1.1.2-may2002.tar.gz from 2002-07-31 drop +- new subpackage osasmpd, only new files, so no split is possible. + +------------------------------------------------------------------- +Mon Jul 15 18:45:56 CEST 2002 - bk@suse.de + +- back to static zipl directory and fix uninstall message for updates + +------------------------------------------------------------------- +Fri Jul 12 00:45:24 CEST 2002 - bk@suse.de + +- loader uses versioned directory to avoid boot problems after update +- fix lib64 build problem + +------------------------------------------------------------------- +Tue Jun 11 18:42:55 CEST 2002 - bk@suse.de + +- update for ucdsnmp-4.2.5: + add tcpd to neededforbuild and add -lwarp to cflags of osasnmpd + define allow_severity and deny_severity for tcpd's libwrap + +------------------------------------------------------------------- +Fri Jun 7 23:40:55 CEST 2002 - bk@suse.de + +- update to may2002 stream, version 1.1.1 + +------------------------------------------------------------------- +Thu Feb 28 11:48:40 CET 2002 - froh@suse.de + +- added silo.sh script for YaST1 from the old package s390utils to + drop that package. + +------------------------------------------------------------------- +Mon Feb 11 18:56:25 CET 2002 - bk@suse.de + +- add s390-tools-5.diff to support newer kernels as well(2.4.17) + +------------------------------------------------------------------- +Mon Jan 28 19:00:09 CET 2002 - bk@suse.de + +- install: add _lib support for lib64 + +------------------------------------------------------------------- +Fri Dec 14 18:57:31 CET 2001 - bk@suse.de + +- Update to the Dec12 2001 drop s390-tools (-2, -3 and -4) patches +- zipl.conf: fix target setting of dumptape, add missing dumpdasd + +------------------------------------------------------------------- +Mon Nov 12 14:09:02 CET 2001 - bk@suse.de + +- add IBM diffs s390-tools-2.tar.gz and s390-tools-3.tar.gz + +------------------------------------------------------------------- +Fri Oct 19 00:52:11 CEST 2001 - bk@suse.de + +- fix error with killing tail in rcchandev verbose-reload + /sbin/rcchandev: line 219: 15941 Terminated tail -0f /var/log/warn 1>&2 + (shown in yast) + +------------------------------------------------------------------- +Fri Oct 12 17:09:51 CEST 2001 - bk@suse.de + +- zipl.conf: change obsolete /boot/zilo-kernel to /boot/kernel + +------------------------------------------------------------------- +Mon Sep 17 14:37:17 CEST 2001 - froh@suse.de + +- added the 2001-09-14 codedrop patches, which include these fixes: +- fdasd: + - added VTOC format 5 & 7 DSCB support + - added command line batch options for one partition, for a config + file and to suppress messages + - fixed OS/390 data set name munging (no more blanks, no more + changes after deleting and re-creating a partition) + - read-only disk access now fails + - fixed free space detection while adding partitions + - added command 'r' to re-create the whole VTOC +- dasdfmt: + - added VTOC format 7 DSCB support + - added blksize >4096 or <512 check (complain & fail) + - added marking of dasds as non-bootable during dasdfmt + - added Hashmarks (for 3270 terminals) and Progress bar +- misc: + - added multi volume support for system dump (tape 3480/90) + - added Tape device display support to system dump + - added 64 bit support for dasd and tape dump. + +------------------------------------------------------------------- +Wed Sep 12 18:54:42 CEST 2001 - bk@suse.de + +- Use the source of the 2001-08-20 codedrop for this version + and update the context of the zipl-reiserfs.diff acordingly. +- Also use the original source, let the spec do the unpacking. + This is less error-prone than doing it by hand and is quicker + to check. + +------------------------------------------------------------------- +Wed Aug 29 10:54:08 CEST 2001 - froh@suse.de + +- integrated 2.4.7-based codedrop, which adds a config file to fdisk + +------------------------------------------------------------------- +Mon Aug 13 21:34:43 CEST 2001 - bk@suse.de + +- better mark /etc/chandev.conf not only %config but also noreplace. +- patch zipl to work with reiserfs too. + +------------------------------------------------------------------- +Fri Aug 10 20:13:29 CEST 2001 - bk@suse.de + +- fix no newline at end of /etc/chandev.conf bug and polish text +- fix insserv recursion due to bogus syslog in Required-Start + +------------------------------------------------------------------- +Tue Aug 7 16:06:50 CEST 2001 - froh@suse.de + +- cleaned up docu in /etc/chandev.conf + +------------------------------------------------------------------- +Mon Aug 6 14:22:40 CEST 2001 - froh@suse.de + +- added support for /proc/chandev + +------------------------------------------------------------------- +Thu Jul 19 20:50:28 CEST 2001 - bk@suse.de + +- added Provides: s390utils:/sbin/dasdfmt (split from s390utils) + +------------------------------------------------------------------- +Fri Jul 13 18:31:30 CEST 2001 - mls@suse.de + +- fixed install section + +------------------------------------------------------------------- +Fri Jul 13 16:15:33 CEST 2001 - bk@suse.de + +- new package based on s390utils + diff --git a/s390-tools.spec b/s390-tools.spec new file mode 100644 index 0000000..4cce35b --- /dev/null +++ b/s390-tools.spec @@ -0,0 +1,484 @@ +# +# spec file for package s390-tools +# +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + + +Name: s390-tools +Version: 1.34.0 +Release: 0 +Url: https://www.ibm.com/developerworks/linux/linux390/ +Summary: S/390 tools like zipl and dasdfmt +License: GPL-2.0+ and BSD-2-Clause +Group: System/Kernel +BuildRequires: dracut +BuildRequires: fuse-devel +BuildRequires: gcc-c++ +BuildRequires: gettext-tools +BuildRequires: glibc-devel-static +BuildRequires: kernel-zfcpdump +BuildRequires: libpfm-devel +BuildRequires: ncurses-devel +BuildRequires: net-snmp-devel +BuildRequires: qclib-devel +BuildRequires: tcpd-devel +BuildRequires: zlib-devel-static +PreReq: shadow %insserv_prereq %fillup_prereq dracut permissions +Requires: coreutils +Requires: gawk +Requires: perl-base +Requires: procps +Requires: rsync +Requires: tar +Requires: util-linux +Provides: s390utils:/sbin/dasdfmt +Source: s390-tools-%{version}.tar.bz2 +Source1: s390-tools-rpmlintrc +Source2: zipl.conf +Source3: hsnc +Source4: sysconfig.hsnc +Source5: xpram +Source6: sysconfig.xpram +Source7: appldata +Source8: sysconfig.appldata +Source9: vmlogrdr +Source10: dasdro +Source11: dasd_reload +Source12: mkdump.pl +Source13: sysconfig.osasnmpd +Source14: zfcp_san_disc +Source15: mkdump.8 +Source16: boot.cpi +Source17: sysconfig.cpi +Source18: zpxe.rexx +Source19: rules.xpram +Source20: rules.hw_random +Source21: 59-graf.rules +Source22: s390-tools-zdsfs.caution.txt +Source23: README.SUSE +Source24: cputype +Source25: cputype.1 +Source26: cio_ignore.service +Source27: setup_cio_ignore.sh +Source28: 59-prng.rules +Source29: 59-zfcp-compat.rules +Source30: 90-s390-tools.conf +Source31: detach_disks.sh +Source32: killcdl +Source33: lgr_check +Source34: sysconfig.virtsetup +Source35: virtsetup.service +Source36: virtsetup.sh + +### Obsolete scripts and man pages to be removed once changes in other tools are made +### That's been delayed to at least SLES12 SP1, but I'm leaving the comments here. +Source86: read_values.c +Source87: read_values.8 +Source88: ctc_configure +Source89: dasd_configure +Source90: iucv_configure +Source91: qeth_configure +Source92: zfcp_disk_configure +Source93: zfcp_host_configure +Source94: ctc_configure.8 +Source95: dasd_configure.8 +Source96: iucv_configure.8 +Source97: qeth_configure.8 +Source98: zfcp_disk_configure.8 +Source99: zfcp_host_configure.8 +### + +Patch1: s390-tools-sles12-zipl_boot_msg.patch +Patch2: s390-tools-sles12-sysconfig-compatible-dumpconf.patch +Patch3: s390-tools-sles12-create-filesystem-links.patch +Patch4: s390-tools-sles12-update-by_id-links-on-change-and-add-action.patch +Patch5: s390-tools-sles12sp2-feat-01-dasd-query-host.patch +Patch6: s390-tools-sles12-pardasdfmt.patch +Patch7: dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch +Patch8: 59-dasd.rules-wait_for.patch +Patch9: s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch +Patch10: s390-tools-sles12sp2-libu2s-Fix-busid-parsing.patch +Patch11: s390-tools-sles12sp2-chiucvallow-verify.patch +Patch12: s390-tools-sles12sp2-zipl-fix-failed-start-subchannel.patch +Patch13: s390-tools-sles12sp2-chreipl-virtio.patch +Patch14: s390-tools-sles12sp2-chzdev-disable-root-update.patch +Patch15: s390-tools-sles12sp2-lscss-allow-to-specify-devices-from-ssid-3.patch +Patch16: s390-tools-sles12sp3-dbginfo-01-libutil-Add-utility-functions.patch +Patch17: s390-tools-sles12sp3-dbginfo-02-dump2tar-Add-sysfs-collection-helper-for-dbginfo.sh-v2.patch +Patch18: s390-tools-sles12sp3-dbginfo-03-dbginfo.sh-Make-use-of-sysinfo-collection-helper.patch +Patch19: s390-tools-sles12sp3-lsdasd-tunedasd-Add-channel-path-aware-erp.patch +Patch20: s390-tools-sles12sp3-dasdfmt-01-Fix-behaviour-of-t-combined-with-y.patch +Patch21: s390-tools-sles12sp3-dasdfmt-02-Fix-trailing-whitespace.patch +Patch22: s390-tools-sles12sp3-dasdfmt-03-Apply-coding-convention.patch +Patch23: s390-tools-sles12sp3-dasdfmt-04-Use-enhanced-DASD-information.patch +Patch24: s390-tools-sles12sp3-dasdfmt-05-Refactor-do_format_dasd.patch +Patch25: s390-tools-sles12sp3-dasdfmt-06-Make-the-IOCTL-BLKSSZGET-reusable.patch +Patch26: s390-tools-sles12sp3-dasdfmt-07-Add-quick-format-support.patch +Patch27: s390-tools-sles12sp3-dasdfmt-08-Make-progress-output-reusable-and-add-ETR.patch +Patch28: s390-tools-sles12sp3-dasdfmt-09-Add-command-line-argument-check.patch +Patch29: s390-tools-sles12sp3-dasdfmt-10-Add-expand-format-mode.patch +Patch30: s390-tools-sles12sp3-util_proc-fix-memory-allocation-error-messages.patch + +BuildRoot: %{_tmppath}/%{name}-%{version}-build +ExclusiveArch: s390 s390x + +%description +This package contains the tools needed to use Linux on IBM z Systems +and exploit many of the various capabilities of the hardware or z/VM. +For example: +dasdfmt - low-level format tool for ECKD DASD +fdasd - partitions ECKD DASDs with z/OS compatible disk layout +zipl - boot loader and dump DASD initializer +zgetdump - tool to get linux system dumps from DASD + +%package -n osasnmpd +Summary: OSA-Express SNMP subagent +License: GPL-2.0+ +Group: Productivity/Networking/Other +Requires: perl + +%description -n osasnmpd +Supports management information bases (MIBs) provided by OSA-Express +Fast Ethernet, Gigabit Ethernet, High Speed Token Ring and ATM Ethernet +LAN Emulation features in QDIO mode. + +It extends the capabilities of the net-snmp master agent (snmpd) and +communicates with him via the AgentX protocol. + + +%package zdsfs +Summary: QSAM access to z/OS data +License: GPL-2.0+ and SUSE-NonFree +Group: Productivity/Networking/Other + +%description zdsfs +Use the zdsfs command for read access to z/OS data sets stored on one or more DASDs. + +The zdsfs file system translates the record-based z/OS data sets to UNIX file system +semantics. After mounting the devices, you can use common Linux tools to access +the files on the disk. Physical sequential data sets are represented as files. +Partitioned data sets are represented as directories, with each member being +represented as a file in that directory. + +%package hmcdrvfs +Summary: HMC drive file system based on FUSE +License: GPL-2.0 +Group: System Environment/Base +Requires: fuse + +%description hmcdrvfs +This package contains a HMC drive file system based on FUSE and a tool +to list files and directories. + +%prep +%setup -q -n %{name}-%{version} + +# SUSE patches +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 + +cp -vi %{S:22} CAUTION + +%build + +# The "DISTRELEASE=%%{release}" needs to be on both the make and make install +# commands, since make install runs sed commands against various scripts to +# modify the "-v" output appropriately. + +export OPT_FLAGS="$RPM_OPT_FLAGS" +export KERNELIMAGE_MAKEFLAGS="%%{?_smp_mflags}" +make ZFCPDUMP_DIR=/usr/lib/s390-tools/zfcpdump DISTRELEASE=%{release} +gcc -static -o read_values ${OPT_FLAGS} %{S:86} -lqc + +%install +mkdir -p $RPM_BUILD_ROOT/boot/zipl +%make_install \ + ZFCPDUMP_DIR=/usr/lib/s390-tools/zfcpdump \ + DISTRELEASE=%{release} \ + SYSTEMDSYSTEMUNITDIR=%{_unitdir} + +install -m 755 read_values $RPM_BUILD_ROOT/%{_bindir}/ +install -m644 -t $RPM_BUILD_ROOT/%{_mandir}/man8 %{S:87} + +export ROOT_BUILD_DIR="$RPM_BUILD_DIR/%{name}-%{version}/zfcpdump/kernel" +install -D -m600 /boot/image-*-zfcpdump $RPM_BUILD_ROOT/usr/lib/s390-tools/zfcpdump/zfcpdump_part.image + +install -D -m644 etc/sysconfig/dumpconf $RPM_BUILD_ROOT/var/adm/fillup-templates/sysconfig.dumpconf +install -D -m755 etc/init.d/dumpconf $RPM_BUILD_ROOT/etc/init.d/dumpconf +install -D -m644 etc/udev/rules.d/40-z90crypt.rules $RPM_BUILD_ROOT/usr/lib/udev/rules.d/40-z90crypt.rules +install -D -m644 etc/udev/rules.d/59-dasd.rules $RPM_BUILD_ROOT/usr/lib/udev/rules.d/59-dasd.rules +install -D -m644 etc/udev/rules.d/57-osasnmpd.rules $RPM_BUILD_ROOT/usr/lib/udev/rules.d/57-osasnmpd.rules +install -D -m644 etc/sysconfig/mon_statd $RPM_BUILD_ROOT/var/adm/fillup-templates/sysconfig.mon_statd +install -D -m755 etc/init.d/mon_statd $RPM_BUILD_ROOT/etc/init.d/mon_statd +install -D -m644 etc/sysconfig/cpuplugd $RPM_BUILD_ROOT/var/adm/fillup-templates/sysconfig.cpuplugd +install -D -m755 etc/init.d/cpuplugd $RPM_BUILD_ROOT/etc/init.d/cpuplugd +mv iucvterm/doc/ts-shell/iucvconn_on_login $RPM_BUILD_ROOT/usr/bin/iucvconn_on_login +install -D -m644 %{S:26} $RPM_BUILD_ROOT/%{_unitdir}/cio_ignore.service +install -D -m755 %{S:27} $RPM_BUILD_ROOT/usr/lib/systemd/scripts/setup_cio_ignore.sh +install -D -m755 %{S:31} $RPM_BUILD_ROOT/usr/lib/systemd/scripts/detach_disks.sh +install -D -m644 %{S:35} $RPM_BUILD_ROOT/%{_unitdir}/virtsetup.service +install -D -m755 %{S:36} $RPM_BUILD_ROOT/usr/lib/systemd/scripts/virtsetup.sh + +cp %{S:18} zpxe.rexx +cp %{S:2} zipl.conf.sample +cp %{S:23} README.SUSE + +cd $RPM_BUILD_ROOT +install -D -m755 %{S:3} etc/init.d/hsnc +install -D -m644 %{S:4} var/adm/fillup-templates/sysconfig.hsnc +install -D -m755 %{S:5} etc/init.d/xpram +install -D -m644 %{S:6} var/adm/fillup-templates/sysconfig.xpram +install -D -m755 %{S:7} etc/init.d/appldata +install -D -m644 %{S:8} var/adm/fillup-templates/sysconfig.appldata +install -D -m755 %{S:9} etc/init.d/vmlogrdr +install -D -m755 %{S:10} sbin/dasdro +install -D -m755 %{S:11} sbin/dasd_reload +install -D -m755 %{S:12} sbin/mkdump +install -D -m644 %{S:13} var/adm/fillup-templates/sysconfig.osasnmpd +install -D -m755 %{S:14} sbin/zfcp_san_disc +install -D -m644 %{S:15} $RPM_BUILD_ROOT/%{_mandir}/man8 +install -D -m755 %{S:16} etc/init.d/boot.cpi +install -D -m644 %{S:17} var/adm/fillup-templates/sysconfig.cpi +install -D -m644 %{S:19} $RPM_BUILD_ROOT/usr/lib/udev/rules.d/52-xpram.rules +install -D -m644 %{S:20} $RPM_BUILD_ROOT/usr/lib/udev/rules.d/52-hw_random.rules +install -D -m644 %{S:21} $RPM_BUILD_ROOT/usr/lib/udev/rules.d/59-graf.rules +install -D -m644 %{S:28} $RPM_BUILD_ROOT/usr/lib/udev/rules.d/59-prng.rules +install -D -m644 %{S:29} $RPM_BUILD_ROOT/usr/lib/udev/rules.d/59-zfcp-compat.rules +install -D -m644 %{S:30} $RPM_BUILD_ROOT/etc/modprobe.d/90-s390-tools.conf +install -D -m755 %{S:32} $RPM_BUILD_ROOT/sbin/killcdl +install -D -m755 %{S:33} $RPM_BUILD_ROOT/sbin/lgr_check +install -D -m644 %{S:34} var/adm/fillup-templates/sysconfig.virtsetup + +if [ ! -d %{_sbindir} ]; then + rm -f %{_sbindir} + mkdir -p %{_sbindir} +fi +(cd usr/sbin; ln -s ../../etc/init.d/appldata rcappldata) +(cd usr/sbin; ln -s ../../etc/init.d/cpuplugd rccpuplugd) +(cd usr/sbin; ln -s ../../etc/init.d/dumpconf rcdumpconf) +(cd usr/sbin; ln -s ../../etc/init.d/hsnc rchsnc) +(cd usr/sbin; ln -s ../../etc/init.d/mon_statd rcmon_statd) +(cd usr/sbin; ln -s ../../etc/init.d/vmlogrdr rcvmlogrdr) +(cd usr/sbin; ln -s ../../etc/init.d/xpram rcxpram) +(cd usr/sbin; ln -s service rccio_ignore) +(cd usr/sbin; ln -s service rccpacfstatsd) +(cd usr/sbin; ln -s service rcvirtsetup) + +if [ ! -d %{_bindir} ]; then + rm -f %{_bindir} + mkdir -p %{_bindir} +fi +install -D -m755 %{S:24} usr/bin/cputype + +install -m644 -t $RPM_BUILD_ROOT/%{_mandir}/man8 %{S:25} + +### Obsolete scripts and man pages to be removed once changes in other tools are made +install -m755 -t sbin/ %{S:88} %{S:89} %{S:90} %{S:91} %{S:92} %{S:93} +install -m644 -t $RPM_BUILD_ROOT/%{_mandir}/man8 %{S:94} %{S:95} %{S:96} %{S:97} %{S:98} %{S:99} +### + +find . ! -type d | + %__sed 's/^.//;\-/man/-s/^.*$/%doc &.gz/' > %{_builddir}/%{name}-filelist +grep -v -E 'osasnmp|*\.conf$' %{_builddir}/%{name}-filelist >%{_builddir}/%{name}.list +grep osasnmp[^-] %{_builddir}/%{name}-filelist >%{_builddir}/%{name}.osasnmp + +touch boot/zipl/active_devices.txt +mkdir -p usr/lib/net-snmp/agents +cd usr/lib/net-snmp/agents +cat <osasnmpd +#!/bin/sh +PIDFILE=/var/run/osasnmpd.pid +function cleanup +{ + rm -f \$PIDFILE + kill \`cat /var/run/osasnmpd.real.pid\` +} +. /etc/sysconfig/osasnmpd +trap cleanup 0 +echo \$\$ >\$PIDFILE +/usr/sbin/osasnmpd -f -P /var/run/osasnmpd.real.pid \$OSASNMPD_PARAMETERS "\$@" +EOT +chmod 755 osasnmpd + +%verifyscript +%verify_permissions -e /var/log/ts-shell + +%pre +# check for ts-shell group or create it +getent group ts-shell >/dev/null 2>&1 || groupadd -r ts-shell +%service_add_pre cio_ignore.service +%service_add_pre cpacfstatsd.service +%service_add_pre virtsetup.service + +%post +read INITPGM < /proc/1/comm +if [ "${INITPGM}" == "systemd" ]; then + echo "Running systemctl daemon-reload." + systemctl daemon-reload +fi + +%set_permissions /var/log/ts-shell + +# Create symbolic links to the scripts from setup and boot directories +%service_add_post cio_ignore.service +%service_add_post cpacfstatsd.service +%service_add_post virtsetup.service +# -i: skip insserv parts - has to be configured before use: +%{fillup_and_insserv -i -n appldata} +%{fillup_and_insserv -i -n cpuplugd} +%{fillup_and_insserv -i -n dumpconf} +%{fillup_and_insserv -i -n hsnc} +%{fillup_and_insserv -i -n mon_statd} +%{fillup_and_insserv -i -n vmlogrdr} +%{fillup_and_insserv -i -n virtsetup} +%{fillup_and_insserv -i -n xpram} +%{fillup_and_insserv -y -n cpi boot.cpi} + +%triggerin -- kernel-default +grep -q '^/usr/bin/ts-shell$' /etc/shells \ + || echo "/usr/bin/ts-shell" >> /etc/shells + +%post -n osasnmpd +%{fillup_and_insserv -i -n osasnmpd} + +%preun +%{stop_on_removal appldata} +%{stop_on_removal cpuplugd} +%{stop_on_removal dumpconf} +%{stop_on_removal hsnc} +%{stop_on_removal mon_statd} +%{stop_on_removal vmlogrdr} +%{stop_on_removal xpram} +%service_del_preun cio_ignore.service +%service_del_preun cpacfstatsd.service +%service_del_preun virtsetup.service + +%postun +%{restart_on_update boot.cpi} +%{restart_on_update appldata} +%{restart_on_update cpuplugd} +%{restart_on_update dumpconf} +%{restart_on_update hsnc} +%{restart_on_update mon_statd} +%{restart_on_update vmlogrdr} +%{restart_on_update xpram} +%service_del_postun cio_ignore.service +%service_del_postun cpacfstatsd.service +%service_del_postun virtsetup.service +read INITPGM < /proc/1/comm +if [ "${INITPGM}" == "systemd" ]; then + echo "Running systemctl daemon-reload." + systemctl daemon-reload +fi + +if [ ! -x /boot/zipl ]; then + echo "Attention, after uninstalling this package," + echo "you will NOT be able to IPL from DASD anymore!!!" +fi +%{insserv_cleanup} +if test x$1 = x0; then + # remove ts-shell from /etc/shells + grep -v '^/usr/bin/ts-shell$' /etc/shells > /etc/shells.ts-new + mv /etc/shells.ts-new /etc/shells + chmod 0644 /etc/shells +fi + +%preun -n osasnmpd +%{stop_on_removal osasnmpd} + +%clean +rm -rf $RPM_BUILD_ROOT + +%files -f %{_builddir}/%{name}.list +%defattr(-,root,root) +%doc README +%doc README.SUSE + +%doc iucvterm/doc/ts-shell +%doc zpxe.rexx +%doc zipl.conf.sample +%dir /etc/iucvterm +%config %attr(0640,root,ts-shell) /etc/iucvterm/ts-audit-systems.conf +%config %attr(0640,root,ts-shell) /etc/iucvterm/ts-authorization.conf +%config %attr(0640,root,ts-shell) /etc/iucvterm/ts-shell.conf +%config %attr(0640,root,ts-shell) /etc/iucvterm/unrestricted.conf +%config /etc/modprobe.d/90-s390-tools.conf +%config /boot/zipl/active_devices.txt +%dir %attr(2770,root,ts-shell) /var/log/ts-shell +%dir /etc/cmsfs-fuse +%config %attr(0640,root,root) /etc/cmsfs-fuse/filetypes.conf +%dir /usr/lib/s390-tools +%dir /usr/lib/s390-tools/zfcpdump +%dir /usr/lib/udev/rules.d +%dir /usr/lib/systemd/scripts +%dir %{_unitdir} +%dir /usr/share/s390-tools +%dir /usr/share/s390-tools/cpumf +%dir /boot/zipl +%dir /lib/s390-tools/ +%exclude /usr/lib/udev/rules.d/57-osasnmpd.rules +%exclude /usr/bin/zdsfs +%exclude /usr/bin/hmcdrvfs +%exclude /usr/sbin/lshmc +%exclude %{_mandir}/man1/zdsfs.1.gz +%exclude %{_mandir}/man1/hmcdrvfs.1.gz +%exclude %{_mandir}/man8/lshmc.8.gz + +%files -n osasnmpd -f %{_builddir}/%{name}.osasnmp +%defattr(-,root,root) +/usr/lib/net-snmp/agents/osasnmpd + +%files zdsfs +%defattr(-,root,root) +%doc CAUTION +/usr/bin/zdsfs +/usr/share/man/man1/zdsfs.1.gz + +%files hmcdrvfs +%defattr(-,root,root) +/usr/bin/hmcdrvfs +/usr/sbin/lshmc +%{_mandir}/man1/hmcdrvfs.1.gz +%{_mandir}/man8/lshmc.8.gz + +%changelog diff --git a/setup_cio_ignore.sh b/setup_cio_ignore.sh new file mode 100644 index 0000000..621e2b1 --- /dev/null +++ b/setup_cio_ignore.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# setup_cio_ignore +# +# Remove the device ids found in /boot/zipl/active_devices.txt +# from cio_ignore +# + +if [ -e /boot/zipl/active_devices.txt ] ; then + while read dev etc ; do + [ "$dev" = "#" -o "$dev" = "" ] && continue; + cio_ignore -r $dev + done < /boot/zipl/active_devices.txt +fi + +exit 0 diff --git a/sysconfig.appldata b/sysconfig.appldata new file mode 100644 index 0000000..4d10342 --- /dev/null +++ b/sysconfig.appldata @@ -0,0 +1,35 @@ +# /etc/sysconfig/appldata + +## Path: Kernel/APPLDATA +## Description: Linux - z/VM Monitor Stream + +## Type: integer +## Default: 10000 +# +# Polling interval in milliseconds +# +APPLDATA_INTERVAL=10000 + +## Type: list(yes,no) +## Default: yes +# +# Load module for collecting data related +# to memory management. +# +APPLDATA_MEM="yes" + +## Type: list(yes,no) +## Default: yes +# +# Load module for collecting OS information +# (CPU utilization, running processes). +APPLDATA_OS="yes" + +## Type: list(yes,no) +## Default: no +# +# Load module for collecting accumulated +# network statistics (Packets received/transmitted, +# dropped, errors, ...) +# +APPLDATA_NET_SUM="no" diff --git a/sysconfig.cpi b/sysconfig.cpi new file mode 100644 index 0000000..33651c8 --- /dev/null +++ b/sysconfig.cpi @@ -0,0 +1,22 @@ +## Path: Kernel/CPI +## Description: set Control Program Indentification data +## Type: list(yes,no) +## Default: no +# +# Set Control Program Identification data +# +CPI_SET="yes" + +## Type: string +## Default: "" +# +# CPI system name +# +CPI_SYSTEM_NAME="" + +## Type: string +## Default: "" +# +# CPI sysplex name +# +CPI_SYSPLEX_NAME="" diff --git a/sysconfig.hsnc b/sysconfig.hsnc new file mode 100644 index 0000000..4b8524a --- /dev/null +++ b/sysconfig.hsnc @@ -0,0 +1,23 @@ +## Path: Hardware/Network +## Description: HiperSockets Network Concentrator Configuration +## Type: list(unicast,full) +## Default: unicast +# +# unicast means, only unicast forwarded between the hsint's and osaint's. +# this is the default mode +# full means, unicast, multicast and broadcast are forwarded, if supported +# by the hardware +# +operating_mode="unicast" +## Type: string +## Default: "" +# +# describes all HiperSockets interfaces involved in the HSN +# +hsi_int="" +## Type: string +## Default: "" +# +# describes the OSA interface connecting to other LANs +# +osa_int="" diff --git a/sysconfig.osasnmpd b/sysconfig.osasnmpd new file mode 100644 index 0000000..eaa3db7 --- /dev/null +++ b/sysconfig.osasnmpd @@ -0,0 +1,14 @@ +## Path: Network/SNMP/OSA Express SNMP agent +## Description: OSA Express SNMP agent parameters +## Type: string +## Default: "" +## ServiceRestart: snmpd +# +# OSA Express SNMP agent command-line parameters +# +# Enter the parameters you want to be passed on to the OSA Express SNMP +# agent. +# +# Example: OSASNMPD_PARAMETERS="-l /var/log/my_private_logfile" +# +OSASNMPD_PARAMETERS="" diff --git a/sysconfig.virtsetup b/sysconfig.virtsetup new file mode 100644 index 0000000..167c79c --- /dev/null +++ b/sysconfig.virtsetup @@ -0,0 +1,48 @@ +## Path: System/Virtualization/Virtsetup +## Description: System preparation for z/VM Live Guest Relocation +## Type: yesno +## Default: no +# +# Whether disks should be automatically detached from the guest or not +# +ZVM_DETACH_DISKS="no" + +## Type: yesno +## Default: no +# +# If detaching disks from the guest, detach all disks not currently +# activated by Linux (as shown by lsdasd)? +ZVM_DETACH_ALL_UNUSED="no" + +## Type: string +## Default: "" +# +# If detaching disks from the guest, which ones should be detached +# +ZVM_DISKS_TO_DETACH="" + +## Type: string +## Default: "" +# +# If detaching disks from the guest, which ones should NOT be detached. +# If a disk is in this and ZVM_DISKS_TO_DETACH, the entry in this +# list takes precedence. +# +ZVM_DISKS_TO_NOT_DETACH="" + +## Type: yesno +## Default: yes +# +# Should we check various conditions that might prevent relocation? +# Only conditions that can be determined by an unprivileged guest +# will be checked. +# +ZVM_WARN_ABOUT_POSSIBLE_LGR_PROBLEMS="yes" + +## Type: yesno +## Default: yes +# +# Should we use the SCLP interface to inform PR/SM of the +# hostname of this system? +# +LPAR_SCLP_HOSTNAME="yes" diff --git a/sysconfig.xpram b/sysconfig.xpram new file mode 100644 index 0000000..edc5a26 --- /dev/null +++ b/sysconfig.xpram @@ -0,0 +1,48 @@ +## Path: Kernel/XPRAM +## Description: configure XPRAM device + +## Type: list(yes,no) +## Default: no +# +# Create an XPRAM device on this machine +# +XPRAM_START="no" + +## Type: list(yes,no) +## Default: no +# +# Create the new device even if there is valid data on the device. +# +XPRAM_FORCE="no" + +## Type: string +## Default: "xpram" +# +# Kernel module to load for the xpram device +# +XPRAM_MODULE="xpram" + +## Type: string +## Default: "/dev/slram0" +# +# Device node for the xpram device +# +XPRAM_DEVNODE="/dev/slram0" + +## Type: string +## Default: "" +# +# Mount point for the xpram device +# +XPRAM_MNTPATH="/abuild" + +## Type: string +## Default: "ext2" +# +# Filesystem type for the xpram device +# +XPRAM_FSTYPE="ext2" + +# Fix for SWAP priority setting +XPRAM_SWAP_PRI="42" + diff --git a/virtsetup.service b/virtsetup.service new file mode 100644 index 0000000..59f3bfe --- /dev/null +++ b/virtsetup.service @@ -0,0 +1,13 @@ +[Unit] +Description=Perform hypervisor-specific setup and cleanup tasks +DefaultDependencies=no +Wants=default.target +After=default.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/systemd/scripts/virtsetup.sh + +[Install] +WantedBy=default.target diff --git a/virtsetup.sh b/virtsetup.sh new file mode 100644 index 0000000..fe7c7b8 --- /dev/null +++ b/virtsetup.sh @@ -0,0 +1,92 @@ +#!/bin/sh +# +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# +# Perform setup tasks based on what hypervisor is in charge. +# + +# Source the sysconfig file +if [ -r /etc/sysconfig/virtsetup ]; then + . /etc/sysconfig/virtsetup +else echo "No /etc/sysconfig/virtsetup file was found." + exit 1 +fi + +# +# Get our hostname +# +my_hostname="$(hostname)" + +# +# Find out the hypervisor we're running on/under. +# +hypervisor="$(/usr/bin/systemd-detect-virt)" + +case "${hypervisor}" in + zvm) + if [ ! -c /dev/vmcp ]; then + modprobe vmcp + sleep 1 + if [ ! -c /dev/vmcp ]; then + echo "Unable to load the vmcp kernel module." + exit 1 + fi + fi + echo "The vmcp device driver is ready." + if [ "${ZVM_DETACH_DISKS}" == "yes" ]; then + echo "Detaching devices to prepare for Live Guest Relocation." + /usr/lib/systemd/scripts/detach_disks.sh + fi + if [ "${ZVM_WARN_ABOUT_POSSIBLE_LGR_PROBLEMS}" == yes ]; then + /sbin/lgr_check + fi + ;; + none) + hypervisor="lpar" + if [ "${LPAR_SCLP_HOSTNAME}" == "yes" ]; then + # If the sclp_cpi module is already loaded, we have to unload it + # so we can be sure it has the correct system name specified + # when we reload it again. + if grep -qw sclp_cpi /proc/modules 2>/dev/null; then + rmmod sclp_cpi + sleep 1 + fi + if grep -qw sclp_cpi /proc/modules 2>/dev/null; then + echo "Unable to unload the sclp_cpi kernel module." + exit 1 + fi + echo "Setting the LPAR name via the sclp_cpi module." + modprobe sclp_cpi system_name="$my_hostname" + if ! grep -qw sclp_cpi /proc/modules 2>/dev/null; then + echo "We were unable to load the sclp_cpi module to set the LPAR name." + exit 2 + fi + fi + ;; + kvm) + ;; + *) + echo "An unknown hypervisor, \"${hypervisor}\" was detected." + echo "Please report this to your support provider." + exit 3 + ;; +esac + +# +# Now let's check for any scripts that other packages may have provided +# to do specific things they need. The scripts must be marked executable +# and have a suffix indicating which hypervisor for which they are to be run. +# Currently that is one of: kvm, lpar, or zvm. +# E.g., 01-test.script.zvm would only be run if the system is a z/VM guest. +# + +for script in $(ls /lib/s390-tools/virtsetup/*.${hypervisor} 2>/dev/null) + do if [ -x "${script}" ]; then + echo "Executing ${script}..." + "${script}" + echo "Done." + echo + fi + done + +exit 0 diff --git a/vmlogrdr b/vmlogrdr new file mode 100644 index 0000000..063bcc6 --- /dev/null +++ b/vmlogrdr @@ -0,0 +1,98 @@ +#!/bin/sh +# Copyright (c) 2003 SUSE LINUX AG Nuernberg, Germany. +# +# Submit feedback to http://www.suse.de/feedback/ +# +# /etc/init.d/vmlogrdr +# +# and symbolic its link +# +# /use/sbin/rcvmlogrdr +# +# +### BEGIN INIT INFO +# Provides: vmlogrdr +# Required-Start: $network $remote_fs +# Required-Stop: $null +# Default-Start: 3 5 +# Default-Stop: 0 1 6 +# Short-Description: Linux - z/VM Log reader +# Description: System startup script for the Linux - z/VM Log reader +### END INIT INFO +# + +# Local settings +SERVICE=LOGREC +DEVNODE=/dev/vmlogrdr_${SERVICE} + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +rc_reset + + +RETVAL=0 + +start() { + echo -n "Starting z/VM log reader for service $SERVICE... " + if [ -e $DEVNODE ]; then + echo -n "(already running)" + rc_status -v + rc_exit + fi + modprobe vmlogrdr 2>&1 + if [ "$?" -ne 0 ] ; then + rc_failed 1 + fi + rc_status -v +} + +stop() { + echo "Stopping z/VM log reader for service $SERVICE... " + rmmod vmlogrdr + rc_status -v +} + +restart() { + stop + start +} + +status() { + echo -n "Checking z/VM log reader for service $SERVICE... " + if [ ! -e $DEVNODE ]; then + rc_failed 1 + fi + rc_status -v +} + +# How are we called? +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + restart|reload) + restart + ;; + *) + echo "Usage: vmlogrdr {start|stop|status|restart|reload}" + RETVAL=1 +esac + +exit $RETVAL + diff --git a/xpram b/xpram new file mode 100644 index 0000000..993bb61 --- /dev/null +++ b/xpram @@ -0,0 +1,278 @@ +#! /bin/sh +# Copyright (c) 2004 SUSE LINUX AG Nuernberg, Germany. +# +# Submit feedback to http://www.suse.de/feedback/ +# +# /etc/init.d/xpram +# +# and symbolic its link +# +# /use/sbin/rcxpram +# +# System startup script for XPRAM device driver +# +### BEGIN INIT INFO +# Provides: xpram +# Required-Start: $remote_fs +# Required-Stop: $null +# Default-Start: 3 5 +# Default-Stop: 0 1 6 +# Short-Description: XPRAM device driver +# Description: Creates an xpram device and mounts it +### END INIT INFO +# + +XPRAM_CONFIG_FILE=/etc/sysconfig/xpram + +read_config_file() { + if [ config_read = 1 ]; then + return 0 + fi + file=$XPRAM_CONFIG_FILE + + if [ -s "$file" ]; then + source $file + config_read=1 + else + echo -ne "Cannot read $file: empty or nonexistant! " + # Means not configured: + rc_failed 6 + rc_status -v + return 6 + fi +} + +prepare_xpram() { + if [ -z "$XPRAM_MNTPATH" -o -z "$XPRAM_DEVNODE" ]; then + echo -n "Cannot mkfs/mount XPRAM: Missing parameters! " + rc_failed 6 + rc_status -v + rc_exit + fi + grep -q $XPRAM_DEVNODE /proc/mounts 2>&1 > /dev/null + if [ $? -eq 0 ] ; then + echo -n "$service: $XPRAM_DEVNODE already mounted! " + return + fi + current_fstype=`vol_id -t $XPRAM_DEVNODE 2> /dev/null` + if [ $? -ne 0 -o "$XPRAM_FORCE" = "yes" ] + then +# Does not contain a valid filesystem/swap space + if [ "$XPRAM_FSTYPE" = swap ] + then + mkswap $XPRAM_DEVNODE + else + mkfs -t "$XPRAM_FSTYPE" -b 4096 "$XPRAM_DEVNODE" + fi + sleep 1 # workaround + current_fstype=$XPRAM_FSTYPE + fi + if [ ! "$current_fstype" = "$XPRAM_FSTYPE" ] + then + echo + echo -n "Warning: current filessystem and configured filesystem are not the same!" + rc_failed 6 + rc_status -v + rc_exit + fi + if [ "$XPRAM_FSTYPE" = swap ] + then + if [ "$XPRAM_SWAP_PRI" = "" ] + then + swapon $XPRAM_DEVNODE + else + swapon -p $XPRAM_SWAP_PRI $XPRAM_DEVNODE + fi + else + if [ ! -d "$XPRAM_MNTPATH" ] + then + mkdir -p "$XPRAM_MNTPATH" + fi + mount "$XPRAM_DEVNODE" "$XPRAM_MNTPATH" + if [ $? -ne 0 ] + then + echo -n "Mount failed with error code $?" + rc_failed 6 + rc_status -v + rc_exit + fi + fi +} + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_failed set local and overall rc status to +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +config_read=0 +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - generic or unspecified error +# 2 - invalid or excess argument(s) +# 3 - unimplemented feature (e.g. "reload") +# 4 - insufficient privilege +# 5 - program is not installed +# 6 - program is not configured +# 7 - program is not running +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signalling is not supported) are +# considered a success. + +check_config () { + if [ -z "$XPRAM_MODULE" ]; then + echo -n "$file: parameters XPRAM_MODULE missing! " + rc_failed 6 + rc_status -v + rc_exit + fi +} + +quit_disabled() { + if [ "$XPRAM_START" != "yes" ]; then + # Config file exists but xpram not enabled, do not complain, + # but note with exit status 6 that we are not configured. + rc_exit + fi +} + +check_enabled() { + if [ "$XPRAM_START" != "yes" ]; then + rc_failed 6 + if [ "$XPRAM_MODULE" ]; then + if grep -q "$XPRAM_MODULE" /proc/modules; then + echo -n "Service $service $_rc_todo " + rc_status -v + fi + fi + rc_exit + fi +} + +service="xpram" +case "$1" in + start) + # Read in configuration + read_config_file || rc_exit + + check_enabled + quit_disabled + check_config + + echo -n "Creating $service device " + modprobe "$XPRAM_MODULE" + if [ $? -ne 0 ]; then + echo -n "- failed to load $XPRAM_MODULE " + rc_failed 1 + else + prepare_xpram + fi + + # Remember status and be verbose + rc_status -v + ;; + stop) + # Read in configuration + read_config_file || rc_exit + + # check_enabled + # quit_disabled + + echo -n "Removing $service device " + + check_config + + if [ "$XPRAM_DEVNODE" ]; then + if grep -q $XPRAM_DEVNODE /proc/mounts; then + umount $XPRAM_DEVNODE + fi + if swapon -s | grep -q $XPRAM_DEVNODE; then + swapoff $XPRAM_DEVNODE + fi + fi + + if grep -q "$XPRAM_MODULE" /proc/modules; then + rmmod "$XPRAM_MODULE" + rc_status + else + rc_failed 7 + fi + + # Remember status and be verbose + rc_status -v + ;; + try-restart) + ## Stop the service and if this succeeds (i.e. the + ## service was running before), start it again. + ## Note: try-restart is not (yet) part of LSB (as of 0.7.5) + $0 status >/dev/null && $0 restart + + # Remember status and be quiet + rc_status + ;; + restart) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + force-reload) + echo -n "Force-reload $service " + + $0 stop && $0 start + rc_status + ;; + reload) + echo -n "Reloading $service not supported." + + ## it does not support reload: + rc_failed 3 + rc_status -v + ;; + status) + echo -n "Checking $service " + + # Status has a slightly different meaning for the status command: + # 0 - service running + # 1 - service dead, but /var/run/ pid file exists + # 3 - service not running + + # Read in configuration + read_config_file || rc_exit + + check_config + + lsmod | grep -q $XPRAM_MODULE + if [ $? -eq 0 ]; then + if [ "$XPRAM_DEVNODE" ]; then + if ! grep -q $XPRAM_DEVNODE /proc/mounts && ! swapon -s | grep -q $XPRAM_DEVNODE; then + xpram_result=3 + echo -n "loaded, but $XPRAM_DEVNODE not used" + rc_failed 3 + fi + fi + else + rc_failed 3 + fi + + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart}" + exit 1 + ;; +esac +rc_exit diff --git a/zfcp_disk_configure b/zfcp_disk_configure new file mode 100644 index 0000000..8de713f --- /dev/null +++ b/zfcp_disk_configure @@ -0,0 +1,319 @@ +#!/bin/sh +# +# zfcp_disk_configure +# +# Configures a zfcp disk +# +# Usage: +# zfcp_disk_configure +# +# ccwid = x.y.ssss where +# x is always 0 until IBM creates something that uses that number +# y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero +# ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros. +# online = 0 to take the device offline +# 1 to bring the device online +# +# Return codes +# 1 sysfs not mounted +# 2 invalid value for +# 3 device does not exist +# 4 WWPN invalid +# 5 Could not activate WWPN for adapter +# 6 Could not activate zFCP disk +# 7 SCSI disk could not be deactivated +# 8 zFCP LUN could not be deregistered +# 9 zFCP WWPN could not be deregistered +# + +if [ "${DEBUG}" != "yes" ]; then + DEBUG="no" +fi + +mesg () { + echo "$@" +} + +debug_mesg () { + case "$DEBUG" in + yes) mesg "$@" ;; + *) ;; + esac +} + +if [ $# -ne 4 ] ; then + echo "Usage: $0 " + echo " ccwid = x.y.ssss where" + echo " x is always 0 until IBM creates something that uses that number" + echo " y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero" + echo " ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros." + echo " online = 0 to take the device offline" + echo " 1 to bring the device online" + exit 1 +fi + +# Get the mount point for sysfs +while read MNTPT MNTDIR MNTSYS MNTTYPE; do + if test "$MNTSYS" = "sysfs"; then + SYSFS="$MNTDIR" + break; + fi +done ${_zfcp_wwpn_dir}/unit_add + /sbin/udevadm settle + fi + # Re-check whether the disk could be activated + if [ ! -d "${_zfcp_wwpn_dir}/0x${FCP_LUN}" ] ; then + mesg "Could not activate FCP disk ${FCP_WWPN}:${FCP_LUN}" + exit 6 + fi + # Check for failed disks + read wwpn_status < ${_zfcp_wwpn_dir}/0x${FCP_LUN}/status + while [ "$wwpn_status" != 0 ] ; do + sleep 1 + read wwpn_status < ${_zfcp_wwpn_dir}/0x${FCP_LUN}/in_recovery + [ "$wwpn_status" = 0 ] && break + done + read wwpn_status < ${_zfcp_wwpn_dir}/0x${FCP_LUN}/failed + if [ "$wwpn_status" = 1 ] ; then + debug_mesg "ERP failed on FCP disk ${FCP_WWPN}:${FCP_LUN}" + exit 7 + fi + fi +else + # Deconfigure SCSI disk + debug_mesg "Deconfiguring FCP disk ${FCP_WWPN}:${FCP_LUN}" + + _zfcp_wwpn_dir="${_zfcp_dir}/0x${FCP_WWPN}" + # Find the correspondig SCSI disk + for host_dir in $_zfcp_dir/host*; do + if [ -d $host_dir ] ; then + _zfcp_scsi_host_dir=$host_dir + break; + fi + done + if [ -d "$_zfcp_scsi_host_dir" ] ; then + # Deregister the disk from SCSI layer + for target in $_zfcp_scsi_host_dir/rport-*/target*/* ; do + [ "$target" != "${target##*/fc_transport}" ] && continue + if [ -d "$target" ] && [ -d "$target/scsi_device" ] ; then + _zfcp_scsi_id=${target##*/} + read _zfcp_tmp_hba < ${target}/hba_id + read _zfcp_tmp_wwpn < ${target}/wwpn + read _zfcp_tmp_lun < ${target}/fcp_lun + if [ "0x${FCP_LUN}" = "$_zfcp_tmp_lun" -a "0x${FCP_WWPN}" = "$_zfcp_tmp_wwpn" ] ; then + if [ "$auto_lun_scan" = 1 ] ; then + mesg "Could not deactivate SCSI disk ${_zfcp_scsi_id}" + exit 7 + else + echo 1 > $target/delete + _zfcp_scsi_dir=$target + fi + break; + fi + fi + done + /sbin/udevadm settle + else + debug_mesg "No SCSI disk found for FCP disk ${FCP_WWPN}:${FCP_LUN}" + fi + + # Re-check whether the SCSI disk is gone + num=$udev_timeout + while [ $num -gt 0 ] ; do + [ -d "${_zfcp_scsi_dir}" ] || break + let num=$num-1 + sleep 1 + done + if [ -d "${_zfcp_scsi_dir}" ]; then + mesg "Could not deactivate SCSI disk ${_zfcp_scsi_id}" + exit 7 + fi + + # Wait for udev to catch up + /sbin/udevadm settle + + # check multipathing + _zfcp_scsi_dev=$(multipathd -k'show paths' 2> /dev/null | sed -n "s/$_zfcp_scsi_id \(sd[a-z]*\).*/\1/p") + [ "$_zfcp_scsi_dev" ] && multipathd -k"del path $_zfcp_scsi_dev" + + # Deconfigure the FCP_LUN + : ${_zfcp_wwpn_dir} + echo "0x${FCP_LUN}" > ${_zfcp_wwpn_dir}/unit_remove + if [ -d "${_zfcp_wwpn_dir}/0x${FCP_LUN}" ]; then + mesg "Could not deregister FCP LUN ${FCP_LUN}" + exit 8 + fi + + # Find all remaining activated disks + ZFCP_LUNS= + for _tmp_wwpn_dir in ${_zfcp_dir}/0x*; do + if [ -d "$_tmp_wwpn_dir" ]; then + tmp_wwpn=$(basename $_tmp_wwpn_dir) + # Find all luns + for _tmp_lun_dir in ${_tmp_wwpn_dir}/0x*; do + if [ -d "$_tmp_lun_dir" ]; then + tmp_lun=$(basename $_tmp_lun_dir) + tmp_port="${tmp_wwpn}:${tmp_lun}" + ZFCP_LUNS="$ZFCP_LUNS +$tmp_port" + fi + done + fi + done +fi + +# And now update the rules file +if test -d ${RULES_DIR}; then + # Find all WWPNs + + read online < ${_zfcp_dir}/online; + if [ $online -eq 0 ] ; then + exit 0 + fi + + for port in ${_zfcp_dir}/0x* ; do + [ -d $port ] || continue; + [ -w $port/unit_remove ] || continue; + port_list="$port_list ${port##*/}" + done + + cat > ${RULES_DIR}/${RULES_FILE} <> ${RULES_DIR}/${RULES_FILE} <.rules +.RS +This file provides the udev rules necessary to activate a specific zFCP adapter and the LUNs associated with it. Rules relating to the zFCP adapter are added by the zfcp_host_configure(8) script. +.RE +.SH ENVIRONMENT +.IP DEBUG +If set to "yes" some minimal debugging information is output during execution. +.SH DIAGNOSTICS +The following messages may be issued on stdout: +.IP +.B /sysfs not present +.RS +The sysfs file system could not be found in /proc/mounts, so there's nothing the script can do. Return code 1 is set. +.RE +.IP +.B No CCW device specified +.RS +This message should never be seen, since the script checks to make sure there are exactly four parameters specified. I.e., it is a sanity check. If it is seen, please open a bug report. Return code 1 is set. +.RE +.IP +.B Invalid device status ${ONLINE} +.RS +A value other than 0 or 1 was specified for the second parameter, online. Return code 2 is set. +.RE +.IP +.B No device ${CCW_CHAN_ID} +.RS +If a non-existent was specified for the first parameter. Remember the x.y.ssss format is necessary. Return code 3 is set. +.RE +.IP +.B WWPN ${FCP_WWPN} invalid +.RS +Activation of the WWPN failed. Return code 4 is set. +.RE +.IP +.B WWPN ${FCP_WWPN} for adapter ${CCW_CHAN_ID} not found +.RS +The WWPN specified isn't being "seen" by the zFCP adapter. This could have a number of different causes, such as an incorrect configuration on the storage array or SAN switch, a typographical error entering this command, etc. Return code 5 is set. +.RE +.IP +.B Could not activate FCP disk ${FCP_WWPN}:${FCP_LUN} +.RS +An attempt was made to activate the specified LUN, which failed. Return code 6 is set. +.RE +.IP +.B Could not deactivate SCSI disk ${_zfcp_scsi_id} +.RS +An attempt was made to deactivate the specified LUN, which failed. Return code 7 is set. +.RE +.IP +.B Could not deregister FCP LUN ${FCP_LUN} +.RS +An attempt was made to remove the specified LUN from the zFCP adapter, which failed. Return code 8 is set. +.RE + +If environment variable DEBUG is set to "yes," the following messages may be issued on stdout: +.IP +.B No configuration file for adapter ${CCW_CHAN_ID} +.RS +The /etc/udev/rules.d/51-zfcp-.rules file does not exist. No return code is set, and execution continues. +.RE +.IP +.B FCP disk ${FCP_WWPN}:${FCP_LUN} already configured +.RS +The parameters specified activating the LUN, but it was already activated. Return code 0 is set. +.RE +.IP +.B FCP disk ${FCP_WWPN}:${FCP_LUN} does not exist +.RS +The parameters specified deactivating the LUN, but it is not currently activated. Return code 0 is set. +.RE +.IP +.B Configuring FCP disk ${FCP_WWPN}:${FCP_LUN} +.RS +Just a little bit of verbosity, since it just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B ERP failed on FCP disk ${FCP_WWPN}:${FCP_LUN} +.RS +An attempt to bring the specified LUN online succeeded, but the device is marked as "failed" by the SCSI layer. Return code 7 is set. +.RE +.IP +.B Deconfiguring FCP disk ${FCP_WWPN}:${FCP_LUN} +.RS +Another bit of verbosity, which also just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B No SCSI disk found for FCP disk ${FCP_WWPN}:${FCP_LUN} +.RS +This indicates that deactivating a SCSI disk was successful. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. +.SH SEE ALSO +zfcp_host_configure(8), zfcp_san_disc(8) diff --git a/zfcp_host_configure b/zfcp_host_configure new file mode 100644 index 0000000..5a4325f --- /dev/null +++ b/zfcp_host_configure @@ -0,0 +1,186 @@ +#!/bin/sh +# +# zfcp_host_configure +# +# Configures a zfcp host adapter +# +# Usage: +# zfcp_host_configure +# +# ccwid = x.y.ssss where +# x is always 0 until IBM creates something that uses that number +# y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero +# ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros. +# online = 0 to take the device offline +# 1 to bring the device online +# +# Return codes +# 1 sysfs not mounted +# 2 invalid value for +# 3 device does not exist +# 4 module zfcp could not be loaded +# 5 adapter status could not be changed +# 6 wwpn ports still active +# 10 adapter active but allow_lun_scan active +# + +if [ "${DEBUG}" != "yes" ]; then + DEBUG="no" +fi + +DATUM=$(date) + +add_channel_for_cio() { + echo "$* # $DATUM" >> /boot/zipl/active_devices.txt +} + +remove_channel_for_cio() { + [ -w /boot/zipl/active_devices.txt ] && sed -i -e "/^$1/d" /boot/zipl/active_devices.txt +} + +mesg () { + echo "$@" +} + +debug_mesg () { + case "$DEBUG" in + yes) mesg "$@" ;; + *) ;; + esac +} + +if [ $# -ne 2 ] ; then + echo "Usage: $0 " + echo " ccwid = x.y.ssss where" + echo " x is always 0 until IBM creates something that uses that number" + echo " y is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero" + echo " ssss is the four digit subchannel address of the device, in hexidecimal, with leading zeros." + echo " online = 0 to take the device offline" + echo " 1 to bring the device online" + exit 1 +fi + +# Get the mount point for sysfs +while read MNTPT MNTDIR MNTSYS MNTTYPE; do + if test "$MNTSYS" = "sysfs"; then + SYSFS="$MNTDIR" + break; + fi +done $_zfcp_dir/online + + # Now wait for the adapter to initialize + /sbin/udevadm settle + fi + + for loop in 1 2 3 4 5 ; do + read status < /sys/bus/ccw/devices/$CCW_CHAN_ID/status + (( $status & 0x10000000 )) && break; + done + read wwpn_status < /sys/bus/ccw/devices/$CCW_CHAN_ID/status + if !(( $wwpn_status & 0x10000000 )) ; then + echo 0 > /sys/bus/ccw/devices/$CCW_CHAN_ID/online + mesg "Could not activate adapter, status $wwpn_status" + exit 5 + fi + + # Write the configuration file + if test -d ${RULES_DIR}; then + cat > ${RULES_DIR}/${RULES_FILE} < ${_zfcp_dir}/online + # Re-read to check whether we have succeeded + _ccw_dev_status=$(cat $_zfcp_dir/online) + if [ "$_ccw_dev_status" -ne "$ONLINE" ]; then + mesg "Could not change status of device ${CCW_CHAN_ID} to $ONLINE" + exit 5 + fi + echo "${CCW_CHAN_ID}" > /sys/bus/ccw/drivers/zfcp/unbind + echo "${CCW_CHAN_ID}" > /sys/bus/ccw/drivers/zfcp/bind + remove_channel_for_cio "${CCW_CHAN_ID}" + + debug_mesg "zFCP adapter at ${CCW_CHAN_ID} deactivated" +fi + +# EOF diff --git a/zfcp_host_configure.8 b/zfcp_host_configure.8 new file mode 100644 index 0000000..c74f1c4 --- /dev/null +++ b/zfcp_host_configure.8 @@ -0,0 +1,91 @@ +.TH zfcp_host_configure "8" "February 2013" "s390-tools" +.SH NAME +zfcp_host_configure \- Configures or deconfigures a zFCP host bus adapter (HBA). +.SH SYNOPSIS +.B zfcp_host_configure ccwid online +.SH DESCRIPTION +.B zfcp_host_configure +is intended to make it easy to persistently add and remove IBM zFCP adapters. In addition to bringing the adapter online or offline, it will also create or delete the necessary udev rules for the adapter. +.SH PARAMETERS +.IP ccwid +The device number of the zFCP adapter. Takes the form x.y.ssss where +.RS +.B x +is always 0 until IBM creates something that uses that number. +.RE +.RS +.B y +is the logical channel subsystem (lcss) number. Most often this is 0, but it could be non-zero. +.RE +.RS +.B ssss +is the four digit subchannel address of the device, in hexidecimal, with leading zeros. If entered in upper/mixed case, this is automatically converted to lower case. +.RE +.IP online +Either a literal 1 to bring the adapter online or a literal 0 to take it offline +.SH FILES +.I /etc/udev/rules.d/51-zfcp-.rules +.RS +This file provides the udev rules necessary to activate a specific zFCP adapter and the LUNs associated with it. Rules relating to the LUNs are added by the zfcp_disk_configure(8) script. +.RE +.SH ENVIRONMENT +.IP DEBUG +If set to "yes" some minimal debugging information is output during execution. +.SH DIAGNOSTICS +The following messages may be issued on stdout: +.IP +.B /sysfs not present +.RS +The sysfs file system could not be found in /proc/mounts, so there's nothing the script can do. Return code 1 is set. +.RE +.IP +.B No CCW device specified +.RS +This message should never be seen, since the script checks to make sure there are exactly two parameters specified. I.e., it is a sanity check. If it is seen, please open a bug report. Return code 1 is set. +.RE +.IP +.B Invalid device status $ONLINE +.RS +A value other than 0 or 1 was specified for the second parameter, online. Return code 2 is set. +.RE +.IP +.B No device ${CCW_CHAN_ID} +.RS +If a non-existent was specified for the first parameter. Remember the x.y.ssss format is necessary. Return code 3 is set. +.RE +.IP +.B Could not load module ${MODULE} +.RS +The zfcp.ko module failed to load. Try "dmesg" to see if there is any indication why. Return code 4 is set. +.RE +.IP +.B Could not activate adapter, status $wwpn_status +.RS +An attempt was made to bring the adapter online, which failed. The $wwpn_status value comes from /sys/bus/ccw/devices/$CCW_CHAN_ID/status. The adapter is explicitly set offline. Return code 5 is set. +.RE +.IP +.B Could not change status of device ${CCW_CHAN_ID} to 0 +.RS +An attempt was made to take the adapter offline, which failed. Return code 5 is set. +.RE + +If environment variable DEBUG is set to "yes," the following messages may be issued on stdout: +.IP +.B zFCP adapter ${CCW_CHAN_ID} already in status ${ONLINE} +.RS +An attempt was made to bring the adapter online when it was already online, or take it offline when it was already offline. +.RE +.IP +.B Configuring device ${CCW_CHAN_ID} +.RS +Just a little bit of verbosity, since it just indicates that we got past certain error checks and will now try to do something useful. +.RE +.IP +.B zFCP adapter at ${CCW_CHAN_ID} deactivated +.RS +Another bit of verbosity, which means that the adapter was taken offline and the udev rules deleted. +.RE +.SH BUGS +Gotta be some, I'm sure. If you find one, please open a bug report. +.SH SEE ALSO +zfcp_disk_configure(8), zfcp_san_disc(8) diff --git a/zfcp_san_disc b/zfcp_san_disc new file mode 100644 index 0000000..ec518e5 --- /dev/null +++ b/zfcp_san_disc @@ -0,0 +1,330 @@ +#!/bin/bash +# +# zfcp_san_disc +# +# Outputs a list of zFCP WWPNs or LUNs +# +# Usage: +# zfcp_san_disc [-h | -W | -L -p ] -b +# +# Return codes +# 1 zFCP sysfs directory not available +# 2 Invalid command line parameter +# 3 Too many commands used +# 4 Error retrieving HBA list +# 5 Bus ID not found +# 6 Error retrieving Port list +# 7 WWPN not found +# 8 Bus ID sysfs directory not available +# 9 WWPN sysfs directory not available/unable to add port to Bus ID +# 10 Error retrieving LUN list +# 11 HBA API device not available +# + +START_DIR=`pwd` +SCRIPT_NAME=`basename $0` +cd `dirname $0` +SCRIPT_DIR=`pwd` +cd "${START_DIR}" + +FCP_SYS_DIR='/sys/bus/ccw/drivers/zfcp' + +# Commands available +LIST_WWPN='-W' +LIST_LUN='-L' + +COMMAND='' +BUSID='' +WWPN='' + +echo_err() +{ + echo "$SCRIPT_NAME: $1" 1>&2 +} + +usage() +{ + echo "$0 [-h | $LIST_WWPN | $LIST_LUN -p ] -b " 1>&2 + echo 1>&2 + echo "Commands:" 1>&2 + echo " $LIST_WWPN List WWPNs for the given BUS_ID" 1>&2 + echo " $LIST_LUN List LUNs for the given BUS_ID and WWPN" 1>&2 + echo " -h This usage information" 1>&2 + echo "Options:" 1>&2 + echo " -b BUSID Bus ID to use for listing" 1>&2 + echo " -p WWPN WWPN to use for listing" 1>&2 +} + +list_lun() +{ + local PRINT_WWPN + local BUSID_DIR + local WWPN_DIR + local ADDED_PORT + +} + +deactivate() +{ + local ccw=$1 + + echo 0 > /sys/bus/ccw/devices/$ccw/online +} + +lun_remove() +{ + local syspath=$1 + local lun=$2 + + echo "$lun" > $syspath/unit_remove +} + +sg_remove() +{ + local sg=$1 + local sgnum + + sgnum=${sg#/dev/sg} + : deactivate /sys/class/scsi_generic/sg$sgnum/device/delete + echo 1 > /sys/class/scsi_generic/sg$sgnum/device/delete + udevadm settle +} + +while [ $# -gt 0 ] +do + case "$1" in + -b* ) + if [ "$1" == "-b" ] + then + shift + BUSID="$1" + else + BUSID="${1:2}" + fi + BUSID=`echo $BUSID | tr A-F a-f` + ;; + -p* ) + if [ "$1" == "-p" ] + then + shift + WWPN="$1" + else + WWPN="${1:2}" + fi + WWPN=`echo $WWPN | tr A-FX a-fx` + ;; + "$LIST_WWPN"|"$LIST_LUN" ) + if [ -z "$COMMAND" -o "$1" == "$COMMAND" ] + then + COMMAND=$1 + else + echo_err "You have already specified the $COMMAND command, and cannot use the $1 command also." + exit 3 + fi + ;; + -h ) + usage + exit 0 + ;; + * ) + usage + echo_err "Unknown command line parameter : $1" + exit 2 + ;; + esac + shift +done + +if [ -z "$BUSID" ] ; then + echo_err "No bus ID given" + exit 2 +fi + +if [ -z "$COMMAND" ] ; then + echo_err "Please specify either -W or -L" + exit 2 +fi + +if [ ! -d /sys/bus/ccw/devices/$BUSID ] ; then + echo_err "Unknown bus ID $BUSID" + exit 2 +fi + +read devtype < /sys/bus/ccw/devices/$BUSID/devtype +read cutype < /sys/bus/ccw/devices/$BUSID/cutype + +if [ "$cutype" != "1731/03" ] ; then + echo_err "Bus ID $BUSID is not an zfcp adapter" + exit 2 +fi + +if [ "$devtype" != "1732/03" -a "$devtype" != "1732/04" ] ; then + echo_err "Bus ID $BUSID is not an zfcp adapter" + exit 2 +fi + +# Now we're sure we're dealing with zfcp devices +if [ ! -d "$FCP_SYS_DIR" ] ; then + modprobe zfcp +fi + +[ "$COMMAND" == "$LIST_LUN" -a -z "$WWPN" ] && usage && exit 2 + +read online < /sys/bus/ccw/devices/$BUSID/online + +if [ "$online" != 1 ] ; then + # Activate adapter + echo 1 > /sys/bus/ccw/devices/$BUSID/online + read online < /sys/bus/ccw/devices/$BUSID/online + + if [ "$online" != 1 ] ; then + echo_err "Cannot activate zfcp adapter at $BUSID" + exit 2 + fi + trapcmd="deactivate $BUSID" + trap "$trapcmd" EXIT +fi + +for loop in 1 2 3 4 5 ; do + read status < /sys/bus/ccw/devices/$BUSID/status + (( $status & 0x10000000 )) && break; +done +read wwpn_status < /sys/bus/ccw/devices/$BUSID/status +if !(( $wwpn_status & 0x10000000 )) ; then + echo_err "Adapter activation failed, status $wwpn_status" + exit 3 +fi + +for host in /sys/bus/ccw/devices/$BUSID/host* ; do + if [ -d $host ] ; then + hba_num=${host##*host} + fi +done +if [ -z "$hba_num" ] ; then + echo_err "No SCSI host allocated" + exit 3 +fi + +if [ "$COMMAND" == "$LIST_WWPN" ] +then + for PRINT_WWPN in /sys/bus/ccw/devices/$BUSID/0x* + do + test -d $PRINT_WWPN && echo ${PRINT_WWPN##*/} + done + exit 0 +elif [ "$COMMAND" != "$LIST_LUN" ] +then + exit 1 +fi + +ERR=0 +read allow_lun_scan < /sys/module/zfcp/parameters/allow_lun_scan +if [ "$allow_lun_scan" = "Y" ] ; then + read port_type < /sys/class/fc_host/host${hba_num}/port_type + if [ "$port_type" = "NPIV VPORT" ] ; then + skip_activation=1 + fi +fi +if [ -z "$skip_activation" ] ; then + WWPN_DIR=/sys/bus/ccw/devices/$BUSID/$WWPN + if [ ! -d "${WWPN_DIR}" ] + then + echo_err "port $WWPN not found on zfcp $BUSID" + exit 9 + fi + + # Activate WLUN + if [ ! -d $WWPN_DIR/0xc101000000000000 ] ; then + echo 0xc101000000000000 > $WWPN_DIR/unit_add + orig_trapcmd="$trapcmd" + trapcmd="lun_remove $WWPN_DIR 0xc101000000000000; $trapcmd" + trap "$trapcmd" EXIT + activated=1 + + # Wait for udev to catch up + udevadm settle + sleep 1 + fi + # Find corresponding sg device + sgdev=$(lsscsi -t -g $hba_num:-:-:49409 | sed -n "s/.* fc:$WWPN.* \(\/dev\/sg[0-9]*\)[[:blank:]]*$/\1/p") + if [ -c "$sgdev" ] ; then + if sg_luns $sgdev > /dev/null 2>&1 ; then + LUN_LIST=`sg_luns $sgdev | sed -n 's/^ \(.*\)/\1/p'` + trapcmd="sg_remove $sgdev; $trapcmd" + trap "$trapcmd" EXIT + wlun=1 + else + wlun= + fi + fi + if [ -z "$wlun" ] ; then + if [ -n "$activated" ] ; then + trapcmd=$orig_trapcmd + trap "$trapcmd" EXIT + lun_remove $WWPN_DIR 0xc101000000000000 + activated= + fi + # Activate LUN 0 + if [ ! -d $WWPN_DIR/0x0000000000000000 ] ; then + echo 0 > $WWPN_DIR/unit_add + orig_trapcmd=$trapcmd + trapcmd="lun_remove $WWPN_DIR 0x0000000000000000; $trapcmd" + trap "$trapcmd" EXIT + activated=1 + # Wait for udev to catch up + udevadm settle + sleep 1 + fi + + # Find corresponding sg device + sgdev=$(lsscsi -t -g $hba_num:-:-:0 | sed -n "s/.* fc:$WWPN.* \(\/dev\/sg[^[:blank:]]*\)[[:blank:]]*$/\1/p") + if [ -c "$sgdev" ] ; then + if sg_luns $sgdev > /dev/null 2>&1 ; then + LUN_LIST=`sg_luns $sgdev | sed -n 's/^ \(.*\)/\1/p'` + fi + if [ -n "$activated" ] ; then + trapcmd="sg_remove $sgdev; $trapcmd" + trap "$trapcmd" EXIT + fi + else + echo_err "Unable to activate LUN 0" + trap "$trapcmd" EXIT + lun_remove $WWPN_DIR 0x0000000000000000 + activated= + sgdev= + ERR=10 + fi + fi + + for LUN in $LUN_LIST ; do + echo 0x$LUN + done + exit $ERR +else + for loop in 1 2 3 4 5 ; do + if [ -n "$(ls -d /sys/class/fc_remote_ports/rport-${hba_num}:* 2>/dev/null)" ] ; then + break + else + sleep 1 + fi + done + + if [ -z "$(ls -d /sys/class/fc_remote_ports/rport-${hba_num}:* 2>/dev/null)" ]; then + echo "The remote Fiber Channel port has not become available. Exiting" + exit 1 + fi + + for rport in /sys/class/fc_remote_ports/rport-${hba_num}:* ; do + [ -f ${rport}/port_name ] || continue + read port_name < ${rport}/port_name + if [ "$port_name" = "$WWPN" ] ; then + for t in ${rport}/device/target* ; do + [ -f ${t}/uevent ] || continue + targetid=${t#*target} + targetid=${targetid##*:} + break + done + fi + done + lsscsi -xx ${hba_num}:0:${targetid}:- | sed -n "s/\[${hba_num}:0:${targetid}:\(0x[0-9a-f]*\)\].*/\1/p" +fi diff --git a/zipl.conf b/zipl.conf new file mode 100644 index 0000000..ea77031 --- /dev/null +++ b/zipl.conf @@ -0,0 +1,31 @@ +# +# Example zipl.conf file +# + +[defaultboot] +default = linux + +[linux] +target = "/boot/zipl" +image = "/boot/kernel/image" +#ramdisk=/boot/initrd +parameters = "root=/dev/ram0 ro" + +[customized] +target = "/boot/zipl" +image = "/boot/kernel/image-customized" +parmfile = "/boot/kernel/parmfile-customized" + +[dumpdasd] +target = "/boot/zipl" +dumpto = "/dev/dasd??" + +[dumpzfcp] +target = "/boot/zipl" +dumptofs = "/dev/zfcp??" + +:menu1 +target = "/boot/zipl" +1 = linux +2 = customized +default = 1 diff --git a/zpxe.rexx b/zpxe.rexx new file mode 100644 index 0000000..add1068 --- /dev/null +++ b/zpxe.rexx @@ -0,0 +1,501 @@ +/* zPXE: REXX PXE Client for System z + +zPXE is a PXE client used with Cobbler or a just a plain TFTP server. +It must be run under z/VM. zPXE uses TFTP to first download a +user-specific profile (if one exists), or a list of available profiles. +From the profile a specific kernel, initial RAMdisk, and PARM file are +then downloaded and these files are then punched to start the install +process. + +zPXE does not require a writeable 191 A disk. Files are downloaded to a +temporary disk (VDISK). + +zPXE can also IPL from a DASD volume by default. You can specify the +default DASD device in ZPXE CONF, as well as the hostname or IP address +of the Cobbler or TFTP server. +--- + +Copyright 2006-2009, Red Hat, Inc +Brad Hinson + +Copyright 2012, SUSE Linux, +Mark Post + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA +*/ + + +/* Set the default environment for "safety" reasons. */ +ADDRESS COMMAND + +/* Make it possible to interrupt zPXE and to enter CMS no matter how + the guest was started, if there is a system-specific profile + or not, etc. +*/ +say +say 'Enter a non-blank character and ENTER (or two ENTERs) within 10', + 'seconds to interrupt zPXE.' +ADDRESS CMS 'WAKEUP +00:10 (CONS' +/* Check for the interrupt code */ +if rc = 6 then do + say 'Interrupt received: exiting to CMS...' + pull /* Clear the stack */ + exit +end + +/* Was this script invoked with "debug" as one of the parameters? */ +nodebug=1 +if arg() then do + parse upper arg uparg + if index(uparg,'DEBUG') <> 0 then do + trace i + nodebug=0 + end + else do /* This is a do/end in case we want to add to it later */ + trace e + end +end + +/* Set some defaults */ +userid='' +server='' +iplDisk='' +server_def = 'internal.tftp.server' /* define default TFTP server */ +iplDisk_def = '150' /* define default IPL DASD */ +profilelist = 'PROFILE LIST T' /* VDISK will be defined as T later */ +profiledetail = 'PROFILE DETAIL T' +zpxeparm = 'ZPXE PARM T' +zpxeconf = 'ZPXE CONF T' +config = 'ZPXE CONF A' + +/* For translating strings to lowercase */ +lower = xrange('a','i')xrange('j','r')xrange('s','z') +upper = xrange('A','I')xrange('J','R')xrange('S','Z') + +/* Query user ID. This is used to determine: + 1. Whether a user-specific PXE profile exists. + 2. Whether user is disconnected. + The logic that gets followed will vary based on the results. +*/ +ADDRESS CMS 'QUERY USER' userid() '(STACK' +parse pull userid_def dash dsc +if dsc = 'DSC' then disconnected=1 /* user is disconnected */ +else disconnected=0 + +/* Yeah, this call to translate looks backward, but it's not. Sorry. */ +userid_def = translate(userid_def, lower, upper) + +/* Useful settings normally found in PROFILE EXEC */ +'CP SET RUN ON' +'CP SET PF11 RETRIEVE FORWARD' +'CP SET PF12 RETRIEVE' + +/* Useful setting for a script that may run unattended */ +'CP TERM HOLD OFF' + +/* We want to have a way to figure out what went wrong if something + isn't working. +*/ +'CP SPOOL CONSOLE STOP CLOSE' /* Close any existing spooled console. */ +'CP SPOOL CONSOLE START' /* Start spooling the console for this run. */ + +if nodebug then ADDRESS CMS 'VMFCLEAR' /* clear screen */ + +/* The following two commands that were in the original script are */ +/* almost certainly not going to work for anyone that only has CP */ +/* privilege class G */ +/* 'set vdisk syslim infinite' */ +/* 'set vdisk userlim infinite' */ + +/* Define a temporary disk (VDISK) to store files and CMS FORMAT it */ +/* If your site doesn't allow this, but does allow TDISKs, change the */ +/* DEFINE command to T3390 instead */ +'CP SET EMSG OFF' +if nodebug then trace off +'CP DETACH FFFF' /* detach ffff if present */ +if nodebug then trace e +else trace i +'CP SET EMSG ON' +'CP DEFINE VFB-512 AS FFFF BLK 144000' /* 512 byte block size ~70 MB */ +queue '1' +queue 'tmpdsk' +if nodebug then /* If debug was not specified, then */ + ADDRESS CMS 'set cmstype ht' /* suppress format output */ +ADDRESS CMS 'format ffff t' /* format VDISK as file mode t */ +ADDRESS CMS 'set cmstype rt' /* Resume seeing command output */ +say 'DASD FFFF has been CMS formatted' + +/* Check for the ZPXE CONF A config file and use whatever is there in + preference over the defaults in this script */ +call GetZPXECONF + +/* For any values not found in ZPXE CONF A, or if it doesn't exist, use + the default values specified in this script. */ +if server = '' then do + say 'Setting TFTP server to 'server_def + server = server_def +end +if iplDisk = '' then do + say 'Setting IPL disk to default of 'iplDisk_def + iplDisk = iplDisk_def +end +if userid = '' then do + say 'Setting userid to default of 'userid_def + userid = userid_def +end + +/* Link to TCPMAINT's 592 disk for access to the TFTP command */ +say +ADDRESS CMS 'exec vmlink tcpmaint 592' + +say +say 'Connecting to server 'server /* print server name */ + +/* Check whether a user-specific PXE profile exists. */ +call GetTFTP '/s390x/s_'userid 'profile.detail.t' +if lines(profiledetail) > 0 then call ProcessUserProfile +else do /* no user-specific profile was found */ + say 'No profile found for' userid + if disconnected then do /* user is disconnected */ + ADDRESS CMS 'release t (detach' + ADDRESS CMS 'exec vmlink tcpmaint 592 ' + say 'User is disconnected. Booting from DASD 'iplDisk'...' + 'CP IPL' iplDisk + end + else call ProcessGenericProfiles /* user is interactive -> prompt */ +end /* no user-specific profile was found */ + +exit +/* */ +/* Subroutines called from the main script */ +/* */ + + +/* Procedure GetZPXECONF +*/ +GetZPXECONF: + +if lines(config) > 0 then do + say config "was found" + do while lines(config) > 0 + inputline = linein(config) + parse upper var inputline keyword value . + select + when (keyword = 'HOST') then do /* line is server hostname/IP */ + server = value + if server = '' then say config "didn't have an IP address for", + "the TFTP server." + else say ' Setting TFTP server to 'server + end + + when (keyword = 'IPLDISK') then do /* line is default IPL disk */ + iplDisk = value + if iplDisk = '' then say config "didn't have an IPL Disk parm." + else say ' Setting IPL disk to 'iplDisk + end + + otherwise do /* line is userid to use instead of the default */ + userid = translate(keyword,lower,upper) /* Still not backward */ + say ' Setting userid to 'userid + end + + end /* select */ + end /* do while lines(config) > 0 */ +end /* if lines(config) > 0 */ +return /* GetZPXECONF */ + + +/* Procedure ProcessUserProfile +*/ +ProcessUserProfile: + +say 'Profile for 'userid' found' +say +bootRc = ParseSystemRecord() /* parse file for boot action */ +if bootRc = 0 then do + say 'The profile said we should boot from local disk.' + ADDRESS CMS 'release t (detach' + ADDRESS CMS 'exec vmlink tcpmaint 592 ' + say 'IPLing from' iplDisk + 'CP IPL' iplDisk /* boot from default DASD */ +end /* if bootRc = 0 */ +else do /* The profile should contain pointers to kernel, etc.*/ + abort=0 + + /* Get the user PARM file that contains network info */ + say 'Downloading parameter file [/s390x/s_'userid'_parm]...' + call GetTFTP '/s390x/s_'userid'_parm' 'zpxe.parm.t' + if CheckDownload('s_'userid'_parm' zpxeparm) <> 0 then + abort=1 + + /* Get the user CONF file that currently isn't used for anything */ + say 'Downloading conf file [/s390x/s_'userid'_conf]...' + call GetTFTP '/s390x/s_'userid'_conf' 'zpxe.conf.t' + if CheckDownload('s_'userid'_conf' zpxeconf) <> 0 then + abort=1 + + if abort then do + say 'Aborting PXE boot.' + exit 99 + end + + call DownloadBinaries /* download kernel and initrd */ + say 'Starting install...' + say + call PunchFiles /* punch files to begin install */ + exit +end /* he profile should contain pointers to kernel, etc */ + + +/* ProcessGenericProfiles +*/ +ProcessGenericProfiles: +/* Download the list of generic profiles available */ +say 'Downloading the profile list [/s390x/profile_list]...' +call GetTFTP '/s390x/profile_list' 'profile.list.t' +if CheckDownload('profile_list' profilelist) <> 0 then do + say '** **' + say '** No profile list found **' + say '** Possible error connecting to server? **' + say '** **' + exit 99 +end + +/* Display a menu of the generic profiles */ +say +say 'zPXE MENU' +say '---------' + +/* Display one profile per line */ +do count = 1 by 1 while lines(profilelist) > 0 + inputline = linein(profilelist) + parse var inputline profile.count + say count'. 'profile.count +end + +/* Add two non-profile selections to the menu */ +say count'. Don''t continue, exit to CMS' +say +say +say 'Enter Choice -->' +say 'or press to boot from disk [DASD 'iplDisk']' + +parse pull answer . +select + when answer = count then do /* Exit to CMS was selected */ + say + say 'Exiting to CMS...' + exit + end + + when answer = '' then do /* IPL from default disk */ + ADDRESS CMS 'release t (detach' + ADDRESS CMS 'exec vmlink tcpmaint 592 ' + say 'Booting from DASD 'iplDisk'...' + 'CP IPL' iplDisk + end + + when (answer > 0) & (answer < count) then do /* valid response */ + abort=0 + + say 'Downloading generic profile [/s390x/p_'profile.answer']...' + call GetTFTP '/s390x/p_'profile.answer 'profile.detail.t' + if CheckDownload('p_'profile.answer profiledetail) <> 0 then + abort=1 + + say 'Downloading generic parameter file', + '[/s390x/p_'profile.answer'_parm]...' + call GetTFTP '/s390x/p_'profile.answer'_parm' 'zpxe.parm.t' + if CheckDownload('p_'profile.answer'_parm' zpxeparm) <> 0 then + abort=1 + + say 'Downloading generic conf file', + '[/s390x/p_'profile.answer'_conf]...' + call GetTFTP '/s390x/p_'profile.answer'_conf' 'zpxe.conf.t' + if CheckDownload('p_'profile.answer'_conf' zpxeconf) <> 0 then + abort=1 + + if abort then do + say 'Aborting PXE boot.' + exit 99 + end + +/* We have to add the HostIP parameter to the parm file, since that is + going to vary for each guest, so we can't hard-code it in the generic + profiles. We use the numeric part of the guest name, which starts in + column 6, after "LINUX". But we have to watch out for leading zeros, + since that will appear as an octal number to Linux. So, we use the + fact that Rexx/Regina doesn't care about leading zeros, but will + remove them when used in an arithmetic statement, such as follows. */ + lastoctet=substr(userid,6) + lastoctet=lastoctet+0 /* Adding a zero won't change the value */ + hostipparm=' HostIP=10.121.157.'lastoctet + call lineout zpxeparm, hostipparm + call lineout zpxeparm /* close the output file */ + + if nodebug then ADDRESS CMS 'VMFCLEAR' /* clear screen */ + say + say 'Using profile 'answer' ['profile.answer']' + say + call DownloadBinaries /* download kernel and initrd */ + + say 'Starting install...' + say + + call PunchFiles + + end /* valid response */ + + otherwise do /* The user entered something that wasn't in the list */ + say 'Invalid choice, exiting to CMS...' + exit + end + +end /* Select */ + + +/* Procedure GetTFTP + Use CMS TFTP client to download files + path: remote file location + filename: local file name + transfermode [optional]: 'ascii' or 'octet' +*/ +GetTFTP: + + parse arg path filename transfermode + + if transfermode <> '' then + queue 'mode' transfermode + queue 'get 'path filename + queue 'quit' + + if nodebug then + ADDRESS CMS 'set cmstype ht' /* suppress TFTP output */ + ADDRESS CMS 'tftp' server + ADDRESS CMS 'set cmstype rt' + +return /* GetTFTP */ + + +/* Procedure CheckDownload + TFTP is dumb, so you can't ever tell if a file was actually retrieved + or not from the return code. + path: The filename (including path) that was to be retrieved + via TFTP + filename: The local CMS filename that should have received it. +*/ +CheckDownload: + + parse arg path filename + if lines(filename) = 0 then do + say 'The' path 'file was not successfully retrieved' + return 99 + end + else return 0 + +/* End CheckDownload */ + + +/* Procedure DownloadBinaries + Download kernel and initial RAMdisk. Convert both + to fixed record length 80. +*/ +DownloadBinaries: + + inputline = linein(profiledetail) /* first line is kernel */ + parse var inputline kernelpath + if kernelpath = '' then do + say 'The path to the kernel is null. Aborting...' + exit 99 + end + say 'Downloading kernel ['kernelpath']...' + call GetTFTP kernelpath 'kernel.img.t' octet + if CheckDownload(kernelpath kernel img t) <> 0 then do + say 'Aborting PXE boot.' + exit 99 + end + + inputline = linein(profiledetail) /* second line is initrd */ + parse var inputline initrdpath + if initrdpath = '' then do + say 'The path to the initrd is null. Aborting...' + exit 99 + end + say 'Downloading initrd ['initrdpath']...' + call GetTFTP initrdpath 'initrd.img.t' octet + if CheckDownload(initrdpath initrd img t) <> 0 then do + say 'Aborting PXE boot.' + exit 99 + end + + inputline = linein(profiledetail) /* third line is kernel parms */ + parse var inputline kparms + if kparms <> '' then do /* If there are parms, add them to the end */ + call lineout zpxeparm, kparms /* add ks line to end of parm */ + call lineout zpxeparm /* close file */ + end + + /* Convert to fixed record length since they're going to be run + through the virtual card reader. */ + ADDRESS CMS 'pipe < KERNEL IMG T | fblock 80 00 | > KERNEL IMG T' + ADDRESS CMS 'pipe < INITRD IMG T | fblock 80 00 | > INITRD IMG T' + ADDRESS CMS 'pipe < ' zpxeparm ' | fblock 80 SPACE | > ' zpxeparm + +return /* DownloadBinaries */ + + +/* Procedure PunchFiles + Punch the kernel, initial RAMdisk, and PARM file. + Then IPL to start the install process. +*/ +PunchFiles: + + 'CP SPOOL PUNCH *' + 'CP CLOSE READER' + 'CP PURGE READER ALL' /* clear reader contents */ + + ADDRESS CMS 'punch kernel img t ( noheader' /* punch kernel */ + ADDRESS CMS 'punch zpxe parm t ( noheader' /* punch PARM file */ + ADDRESS CMS 'punch initrd img t ( noheader' /* punch initrd */ + ADDRESS CMS 'release t (detach' /* release and detach the VDISK */ + ADDRESS CMS 'exec vmlink tcpmaint 592 ' /* and this disk */ + + 'CP CHANGE READER ALL KEEP NOHOLD' /* keep files in reader */ + 'CP IPL 00C CLEAR' /* IPL the reader */ + +return /* PunchFiles */ + + +/* Procedure ParseSystemRecord + Open system record file to look for local boot flag. + Return 0 if local flag found (guest will IPL default DASD). + Return 1 otherwise (guest will download kernel/initrd and install). +*/ +ParseSystemRecord: + + inputline = linein(profiledetail) /* get first line */ + parse var inputline systemaction . + /* Close the file to reset the read pointer to the beginning. Yes I + know that calling lineout to close a file seems weird, but it's + how Rexx/Regina works. */ + call lineout profiledetail + + if systemaction = 'local' then + return 0 + else + return 1 + +/* End ParseSystemRecord */