mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60c687238d | ||
|
|
57b992ffa1 | ||
|
|
1f07a41d5a | ||
|
|
512b47c004 | ||
|
|
818ffbc4b0 | ||
|
|
5e65df7375 | ||
|
|
4eb80d14a0 | ||
|
|
7247a61e0b | ||
|
|
c856f28e11 | ||
|
|
ca30cfd341 | ||
|
|
58ecf1f363 | ||
|
|
d36ff82999 | ||
|
|
d4398aea89 | ||
|
|
672548ce30 | ||
|
|
344965bd29 | ||
|
|
d6a96f07c1 | ||
|
|
6a99d95d4f | ||
|
|
3f1bd3bb66 | ||
|
|
0fbc4edd29 | ||
|
|
b8a9f0d1d3 | ||
|
|
d280e5b1fa | ||
|
|
e04acab0ed | ||
|
|
d868ce5ec7 | ||
|
|
dec58c349e | ||
|
|
d82f5e1f49 | ||
|
|
156450f359 | ||
|
|
c0392efa39 | ||
|
|
3c5644ccfd | ||
|
|
3fb356ebd2 | ||
|
|
fe68ec513d | ||
|
|
a86fb8b091 | ||
|
|
f32bff9688 | ||
|
|
7d355b0fec | ||
|
|
ab4445c261 | ||
|
|
e14363373b |
@@ -16,6 +16,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Clemens von Mann
|
||||
- Dan Horak
|
||||
- Despina Papadopoulou
|
||||
- Dimitri John Ledkov
|
||||
- Eberhard Pasch
|
||||
- Einar Lueck
|
||||
- Erwin Vicari
|
||||
@@ -45,6 +46,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Jan Glauber
|
||||
- Jan Hoeppner
|
||||
- Jan Willeke
|
||||
- Javier Martinez Canillas
|
||||
- Jean-Baptiste Joret
|
||||
- Jens Remus
|
||||
- Jochen Roehrig
|
||||
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,5 +1,30 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
* __v2.6.0 (2018-08-10)__
|
||||
|
||||
For Linux kernel version: 4.18
|
||||
|
||||
Add new tool:
|
||||
- zkey: Add zkey-cryptsetup tool
|
||||
Changes of existing tools:
|
||||
- netboot: add BOOTIF support
|
||||
|
||||
Bug Fixes:
|
||||
- mon_procd: fix parsing of /proc/<pid>/stat
|
||||
- netboot: Include compressed kernel modules in initramfs
|
||||
- netboot: Send client architecture and handle path prefix
|
||||
|
||||
* __v2.5.0 (2018-06-08)__
|
||||
|
||||
For Linux kernel version: 4.17
|
||||
|
||||
Changes of existing tools:
|
||||
- zdev: Add support for reading firmware configuration files
|
||||
- zipl: Add BootLoaderSpec support
|
||||
- scripts: Add script to switch zipl config to a BootLoaderSpec setup
|
||||
|
||||
Bug Fixes:
|
||||
- lsluns: Print a message if no adapter or port exists
|
||||
|
||||
* __v2.4.0 (2018-05-07)__
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -265,12 +265,15 @@ build options:
|
||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||
| openssl | `HAVE_OPENSSL` | zkey |
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup |
|
||||
|
||||
This table lists additional build or install options:
|
||||
|
||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||
|----------------|:----------------:|:-------------------------------:|
|
||||
| dracut | `HAVE_DRACUT` | zdev |
|
||||
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
|
||||
|
||||
The s390-tools build process uses "pkg-config" if available and hard-coded
|
||||
compiler and linker options otherwise.
|
||||
@@ -370,9 +373,12 @@ the different tools are provided:
|
||||
|
||||
* zkey:
|
||||
For building the zkey tools you need openssl version 0.9.7 or newer installed
|
||||
(openssl-devel.rpm). Tip: you may skip the zkey build by adding
|
||||
`HAVE_OPENSSL=0` to the make invocation.
|
||||
(openssl-devel.rpm). Also required are cryptsetup version 2.0.3 or newer
|
||||
(cryptsetup-devel.rpm), and json-c version 0.12 or newer (json-c-devel.rpm).
|
||||
Tip: you may skip the zkey build by adding `HAVE_OPENSSL=0`, and you may
|
||||
may skip the zkey-cryptsetup build by adding `HAVE_CRYPTSETUP2=0`, or
|
||||
`HAVE_JSONC=0` to the make invocation.
|
||||
A new group 'zkeyadm' needs to be created and all users intending to use the
|
||||
tool must be added to this group. The owner of the default key repository
|
||||
tool must be added to this group. The owner of the default key repository
|
||||
'/etc/zkey/repository' must be set to group 'zkeyadm' with write permission
|
||||
for this group.
|
||||
for this group.
|
||||
|
||||
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||
VERSION = 2
|
||||
RELEASE = 4
|
||||
RELEASE = 6
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
|
||||
@@ -594,17 +594,18 @@ static void cal_task_pcpu(struct task_t *task, const unsigned long long tics)
|
||||
*/
|
||||
static int read_stat(struct task_t *task)
|
||||
{
|
||||
int ppid, tty, proc;
|
||||
unsigned long flags, pri, nice;
|
||||
unsigned long long maj_flt, utime, stime, cutime, cstime;
|
||||
unsigned long long maj_flt = 0, utime = 0, stime = 0, cutime = 0,
|
||||
cstime = 0;
|
||||
unsigned long flags = 0, pri = 0, nice = 0;
|
||||
char *cmd_start, *cmd_end, *cmdlenp, *cmdp;
|
||||
int ppid = 0, tty = 0, proc = 0, rc;
|
||||
|
||||
snprintf(fname, sizeof(fname), "/proc/%u/stat", task->pid);
|
||||
if (read_file(fname, buf, sizeof(buf) - 1) == -1)
|
||||
return 0;
|
||||
|
||||
cmd_start = strchr(buf, '(') + 1;
|
||||
cmd_end = strchr(cmd_start, ')');
|
||||
cmd_end = strrchr(cmd_start, ')');
|
||||
name_lens.cmd_len = cmd_end - cmd_start;
|
||||
cmdlenp = mon_record + sizeof(struct monwrite_hdr);
|
||||
cmdlenp += sizeof(struct procd_hdr);
|
||||
@@ -625,7 +626,7 @@ static int read_stat(struct task_t *task)
|
||||
memcpy(cmdlenp, &name_lens.cmd_len, sizeof(__u16));
|
||||
|
||||
cmd_end += 2;
|
||||
sscanf(cmd_end,
|
||||
rc = sscanf(cmd_end,
|
||||
"%c %d %*d %*d %d %*d "
|
||||
"%lu %*s %*s %Lu %*s "
|
||||
"%Lu %Lu %Lu %Lu "
|
||||
@@ -642,6 +643,8 @@ static int read_stat(struct task_t *task)
|
||||
&utime, &stime, &cutime, &cstime,
|
||||
&pri, &nice,
|
||||
&proc);
|
||||
if (rc != 12)
|
||||
syslog(LOG_ERR, "bad data in %s \n", fname);
|
||||
task->ppid = (__u32)ppid;
|
||||
task->tty = (__u16)tty;
|
||||
task->flags = (__u32)flags;
|
||||
|
||||
@@ -134,8 +134,8 @@ echo "$cmd: Copying virtio modules"
|
||||
mkdir -p $builddir/$netdir
|
||||
mkdir -p $builddir/$blkdir
|
||||
set +e
|
||||
cp $netdir/virtio_net.ko $builddir/$netdir 2> /dev/null
|
||||
cp $blkdir/virtio_blk.ko $builddir/$blkdir 2> /dev/null
|
||||
cp $netdir/virtio_net.ko* $builddir/$netdir 2> /dev/null
|
||||
cp $blkdir/virtio_blk.ko* $builddir/$blkdir 2> /dev/null
|
||||
set -e
|
||||
|
||||
# Busybox (+ dependencies)
|
||||
@@ -170,7 +170,7 @@ cat <<'EOF' > $builddir/init
|
||||
/bin/mount -t tmpfs none /run
|
||||
|
||||
/sbin/modprobe virtio_net
|
||||
/sbin/udhcpc -O pxeconffile -O pxepathprefix &
|
||||
/sbin/udhcpc -O pxeconffile -O pxepathprefix -x 93:001F &
|
||||
|
||||
/sbin/pxeboot.script
|
||||
EOF
|
||||
@@ -237,6 +237,7 @@ case "$1" in
|
||||
echo " router: $router"
|
||||
echo " domain: $domain $dns"
|
||||
echo " tftp: $siaddr"
|
||||
echo " pxepathprefix: $pxepathprefix"
|
||||
# flush routes
|
||||
/sbin/ip route flush table all
|
||||
# setup if link
|
||||
@@ -272,6 +273,7 @@ case "$1" in
|
||||
echo "siaddr=$siaddr" > $PXECONF
|
||||
echo "interface=$interface" >> $PXECONF
|
||||
echo "ip=$ip" >> $PXECONF
|
||||
echo "pxepathprefix=$pxepathprefix" >> $PXECONF
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -354,7 +356,7 @@ then
|
||||
for c in $CONFIGS
|
||||
do
|
||||
echo "fetching config pxelinux.cfg/$c from $siaddr"
|
||||
if /usr/bin/tftp -g -l /tmp/config -r pxelinux.cfg/$c $siaddr
|
||||
if /usr/bin/tftp -g -l /tmp/config -r ${pxepathprefix}pxelinux.cfg/$c $siaddr
|
||||
then
|
||||
break
|
||||
fi
|
||||
@@ -371,6 +373,7 @@ fi
|
||||
kernel=$(/bin/grep -i "^[[:space:]]*kernel" /tmp/config | sed "s/^[[:space:]]*kernel[[:space:]]*//I")
|
||||
initrd=$(/bin/grep -i "^[[:space:]]*initrd" /tmp/config | sed "s/^[[:space:]]*initrd[[:space:]]*//I")
|
||||
append=$(/bin/grep -i "^[[:space:]]*append" /tmp/config | sed "s/^[[:space:]]*append[[:space:]]*//I")
|
||||
ipappend=$(/bin/grep -i "^[[:space:]]*ipappend" /tmp/config | sed "s/^[[:space:]]*ipappend[[:space:]]*//I")
|
||||
|
||||
if [ -z "$kernel" ]
|
||||
then
|
||||
@@ -378,13 +381,13 @@ then
|
||||
exit
|
||||
else
|
||||
echo fetch kernel $kernel from $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/kernel -r $kernel $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/kernel -r $pxepathprefix$kernel $siaddr
|
||||
fi
|
||||
|
||||
if [ -n "$initrd" ]
|
||||
then
|
||||
echo fetch initrd $initrd from $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/initrd -r $initrd $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/initrd -r $pxepathprefix$initrd $siaddr
|
||||
INITRD="--initrd=/tmp/initrd"
|
||||
else
|
||||
INITRD=""
|
||||
@@ -394,6 +397,9 @@ if [ -z "$append" ]; then
|
||||
echo "Kexec load: kexec -l /tmp/kernel $INITRD"
|
||||
kexec -l /tmp/kernel $INITRD
|
||||
else
|
||||
if [ "$ipappend" = "2" ]; then
|
||||
$append="$append BOOTIF=01-$ifaddr"
|
||||
fi
|
||||
echo "Kexec load: kexec -l /tmp/kernel $INITRD --append=\"$append\""
|
||||
kexec -l /tmp/kernel $INITRD --append="$append"
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
include ../common.mak
|
||||
|
||||
SCRIPTS = dbginfo.sh zfcpdbf scsi_logging_level
|
||||
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1
|
||||
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
|
||||
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1 zipl-switch-to-blscfg.1
|
||||
|
||||
all:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# dbginfo.sh - Tool to collect runtime, configuration, and trace information
|
||||
#
|
||||
# Copyright IBM Corp. 2002, 2017
|
||||
# Copyright IBM Corp. 2002, 2018
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
@@ -21,7 +21,7 @@ readonly SCRIPTNAME="${0##*/}"
|
||||
print_version() {
|
||||
cat <<EOF
|
||||
${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
|
||||
Copyright IBM Corp. 2002, 2017
|
||||
Copyright IBM Corp. 2002, 2018
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -480,6 +480,7 @@ VM_CMDS="q userid\
|
||||
:q cpus\
|
||||
:q srm\
|
||||
:q vtod\
|
||||
:q time full\
|
||||
:q timezone\
|
||||
:q loaddev\
|
||||
:q v osa\
|
||||
@@ -1016,25 +1017,31 @@ environment_setup()
|
||||
# create gzip-ped tar file
|
||||
create_package()
|
||||
{
|
||||
local rc_tar
|
||||
pr_stdout "Finalizing: Creating archive with collected data"
|
||||
cd "${WORKDIR_BASE}"
|
||||
|
||||
if ! tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"; then
|
||||
pr_stdout " "
|
||||
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
|
||||
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
|
||||
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
|
||||
pr_stdout " to provide enough free available space."
|
||||
tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"
|
||||
rc_tar=$?
|
||||
if [ $rc_tar -eq 0 ]; then
|
||||
chmod 0600 "${WORKARCHIVE}"
|
||||
pr_stdout " "
|
||||
pr_stdout "Collected data was saved to:"
|
||||
pr_stdout " >> ${WORKARCHIVE} <<"
|
||||
pr_stdout " "
|
||||
pr_stdout "Review the collected data before sending to your service organization. "
|
||||
pr_stdout " "
|
||||
elif [ $rc_tar -eq 127 ]; then
|
||||
pr_stdout " "
|
||||
pr_stdout "${SCRIPTNAME}: Error: tar command is not available!"
|
||||
pr_stdout " Please install the corresponding package!"
|
||||
else
|
||||
chmod 0600 "${WORKARCHIVE}"
|
||||
pr_stdout " "
|
||||
pr_stdout "Collected data was saved to:"
|
||||
pr_stdout " >> ${WORKARCHIVE} <<"
|
||||
pr_stdout " "
|
||||
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
|
||||
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
|
||||
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
|
||||
pr_stdout " to provide enough free available space."
|
||||
fi
|
||||
|
||||
pr_stdout " "
|
||||
pr_stdout "Review the collected data before sending to your service organization. "
|
||||
pr_stdout " "
|
||||
}
|
||||
|
||||
|
||||
|
||||
213
scripts/zipl-switch-to-blscfg
Executable file
213
scripts/zipl-switch-to-blscfg
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# zipl-switch-to-blscfg - Switch zipl to use BootLoaderSpec configuration
|
||||
#
|
||||
# Copyright 2018 Red Hat, Inc.
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
readonly SCRIPTNAME="${0##*/}"
|
||||
|
||||
declare -A zipl_to_bls
|
||||
zipl_to_bls["image"]="linux"
|
||||
zipl_to_bls["ramdisk"]="initrd"
|
||||
zipl_to_bls["parameters"]="options"
|
||||
|
||||
print_error() {
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function on_exit() {
|
||||
if ! rm -rf $TMP; then
|
||||
echo "Delete temporary files failed!" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if ! TMP="$(mktemp -d)"; then
|
||||
print_error "Creating a temporary dir for config files failed!"
|
||||
fi
|
||||
|
||||
trap 'on_exit' EXIT
|
||||
|
||||
print_version() {
|
||||
cat <<EOF
|
||||
${SCRIPTNAME}: version %S390_TOOLS_VERSION%
|
||||
Copyright Red Hat, Inc. 2018
|
||||
EOF
|
||||
}
|
||||
|
||||
print_usage()
|
||||
{
|
||||
print_version
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Usage: ${SCRIPTNAME} [OPTIONS]
|
||||
|
||||
Switches the zipl boot-loader configuration to use BootLoaderSpec files.
|
||||
|
||||
Options:
|
||||
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information and exit
|
||||
--backup-suffix=SUFFIX suffix used for backup files, defaults to .bak
|
||||
--bls-directory=DIR path to generate BLS files, defaults to /boot/loader/entries
|
||||
--config-file=FILE path to zipl configuration file, defaults to /etc/zipl.conf
|
||||
--ignore-default ignore the default option from the zipl configuration file
|
||||
--use-version-name use the section kernel version as the BLS file name
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
OPTS="$(getopt -o hv --long help,version,backup-suffix:,bls-directory:,config-file:,\
|
||||
ignore-default,use-version-name -n \'$SCRIPTNAME\' -- "$@")"
|
||||
eval set -- "$OPTS"
|
||||
|
||||
BACKUP_SUFFIX=.bak
|
||||
BLS_DIR="/boot/loader/entries"
|
||||
CMDLINE_LINUX_DEBUG=" systemd.log_level=debug systemd.log_target=kmsg"
|
||||
LINUX_DEBUG_VERSION_POSTFIX="_with_debugging"
|
||||
LINUX_DEBUG_TITLE_POSTFIX=" with debugging"
|
||||
CONFIG="/etc/zipl.conf"
|
||||
|
||||
while [ ${#} -gt 0 ]; do
|
||||
case "$1" in
|
||||
--help|-h)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--version|-v)
|
||||
print_version
|
||||
exit 0
|
||||
;;
|
||||
--backup-suffix)
|
||||
BACKUP_SUFFIX=${2}
|
||||
shift
|
||||
;;
|
||||
--bls-directory)
|
||||
BLS_DIR=${2}
|
||||
shift
|
||||
;;
|
||||
--config-file)
|
||||
CONFIG=${2}
|
||||
shift
|
||||
;;
|
||||
--ignore-default)
|
||||
ignore_default=true
|
||||
;;
|
||||
--use-version-name)
|
||||
version_name=true
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo >&2
|
||||
echo "${SCRIPTNAME}: invalid option \"${1}\"" >&2
|
||||
echo "Try '${SCRIPTNAME} --help' for more information" >&2
|
||||
echo >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
TMP_CONFIG="${TMP}/${CONFIG##*/}"
|
||||
|
||||
[[ -d "$BLS_DIR" ]] || mkdir -m 0700 -p "$BLS_DIR"
|
||||
|
||||
if [ -f /etc/machine-id ]; then
|
||||
read MACHINE_ID < /etc/machine-id
|
||||
MACHINE_ID=${MACHINE_ID}-
|
||||
fi
|
||||
|
||||
count=0
|
||||
OUTPUT=""
|
||||
TARGET=""
|
||||
while IFS='= ' read key val; do
|
||||
# for BLS the default kernel is always the latest one
|
||||
if [[ $key == \#* ]] || [[ $key == "default" && $ignore_default == true ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# remove spaces
|
||||
key="$(echo $key | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')"
|
||||
|
||||
if [[ $key = \[*] ]]; then
|
||||
if [[ $key == "[defaultboot]" ]]; then
|
||||
OUTPUT=${TMP_CONFIG}
|
||||
echo $key >> ${OUTPUT}
|
||||
else
|
||||
key="${key%\]}"
|
||||
key="${key#\[}"
|
||||
section=$key
|
||||
OUTPUT=${BLS_DIR}/${MACHINE_ID}${section}.conf
|
||||
if [ -f "${OUTPUT}" ]; then
|
||||
print_error "BLS file ${OUTPUT} already exists"
|
||||
fi
|
||||
fi
|
||||
elif [[ $val ]]; then
|
||||
val="$(echo $val | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')"
|
||||
if [[ $key == "target" ]]; then
|
||||
if [ -z ${TARGET} ]; then
|
||||
echo $key=$val >> ${TMP_CONFIG}
|
||||
TARGET=$val
|
||||
else if [ "${TARGET}" != "${val}" ]; then
|
||||
print_error "BLS is only supported if all sections have the same target"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ -n "${zipl_to_bls[$key]}" ]; then
|
||||
if [[ $key = "image" && $version_name == true ]]; then
|
||||
if [[ $val = *"vmlinuz-"* ]]; then
|
||||
version="${val##*/vmlinuz-}"
|
||||
else
|
||||
version="${val##*/}"
|
||||
fi
|
||||
echo "version $version" >> ${OUTPUT}
|
||||
if [[ $version = *"rescue"* ]]; then
|
||||
FILENAME=${BLS_DIR}/${MACHINE_ID}0-rescue.conf
|
||||
else
|
||||
FILENAME=${BLS_DIR}/${MACHINE_ID}${version}.conf
|
||||
fi
|
||||
|
||||
if [[ ${OUTPUT} != ${FILENAME} ]]; then
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
print_error "BLS file ${FILENAME} already exists"
|
||||
fi
|
||||
mv ${OUTPUT} ${FILENAME}
|
||||
if [ ! $? -eq 0 ]; then
|
||||
print_error "Creating BLS file ${FILENAME} failed"
|
||||
fi
|
||||
OUTPUT=${FILENAME}
|
||||
fi
|
||||
elif [[ $key = "image" ]]; then
|
||||
echo "version $section" >> ${OUTPUT}
|
||||
fi
|
||||
|
||||
echo "${zipl_to_bls[$key]} ${val}" >> ${OUTPUT}
|
||||
else
|
||||
echo $key=$val >> ${TMP_CONFIG}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < "${CONFIG}"
|
||||
|
||||
if [ -f "${CONFIG}${BACKUP_SUFFIX}" ]; then
|
||||
print_error "Backup file ${CONFIG}${BACKUP_SUFFIX} already exists"
|
||||
fi
|
||||
|
||||
cp -af "${CONFIG}" "${CONFIG}${BACKUP_SUFFIX}"
|
||||
mv "${TMP_CONFIG}" "${CONFIG}"
|
||||
|
||||
zipl > /dev/null
|
||||
if [ ! $? -eq 0 ]; then
|
||||
mv "${CONFIG}${BACKUP_SUFFIX}" "${CONFIG}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
45
scripts/zipl-switch-to-blscfg.1
Normal file
45
scripts/zipl-switch-to-blscfg.1
Normal file
@@ -0,0 +1,45 @@
|
||||
.TH ZIPL-SWITCH-TO-BLSCFG 1 "April 2018" "s390-tools"
|
||||
|
||||
.SH NAME
|
||||
zipl-switch-to-blscfg \- Switch zipl to use BootLoaderSpec configuration
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
\fBzipl-switch-to-blscfg\fP [OPTIONS]
|
||||
.br
|
||||
\fBzipl-switch-to-blscfg\fP {\-h|\-v}
|
||||
|
||||
.SH DESCRIPTION
|
||||
This script switches the zipl boot-loader configuration to use BootLoaderSpec files
|
||||
to define IPL sections. For each Linux kernel defined in the zipl.conf config file,
|
||||
a BLS fragment is generated in the BLS directory specified. Also, the zipl.conf is
|
||||
modified it only contains global configurations, all IPL sections comes from BLS.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-h\fP, \fB\-\-help\fP
|
||||
Print this help and exit
|
||||
|
||||
.TP
|
||||
\fB\-v\fP, \fB\-\-version\fP
|
||||
Print version information and exit
|
||||
|
||||
.TP
|
||||
\fB\-\-backup-suffix <SUFFIX>\fP
|
||||
The suffix used for backup files, defaults to .bak.
|
||||
|
||||
.TP
|
||||
\fB\-\-bls-directory <DIRECTORY>\fP
|
||||
The DIRECTORY where the BLS fragments will be generated. The directory is created if it doesn't exists, by default /boot/loader/entries is used.
|
||||
|
||||
.TP
|
||||
\fB\-\-config-file <FILE>\fP
|
||||
The FILE used for zipl configuration file, defaults to /etc/zipl.conf.
|
||||
|
||||
.TP
|
||||
\fB\-\-ignore-default\fP
|
||||
Ignore the default option from the zipl configuration file
|
||||
|
||||
.TP
|
||||
\fB\-\-use-version-name\fP
|
||||
Use the section kernel version as the BLS file name
|
||||
@@ -111,6 +111,10 @@ In rare situations a device might temporarily not be accessible to
|
||||
the subchannel. Then "none" is displayed as the device identifier and the
|
||||
other device attributes are empty.
|
||||
|
||||
For subchannels bound to an alternate driver (most notably vfio_ccw) the
|
||||
device identifier may also be displayed as "none". In this case use the
|
||||
\fB--vfio\fR option to show VFIO specific subchannel information.
|
||||
|
||||
.SH AUTHOR
|
||||
.nf
|
||||
This man-page was written by Stefan Bader <shbader@de.ibm.com>.
|
||||
|
||||
@@ -235,8 +235,15 @@ sub get_env_list
|
||||
my @res ;
|
||||
my %res_hash;
|
||||
|
||||
if (!</sys/bus/ccw/drivers/zfcp/*.*.*/>) {
|
||||
print "$PROGRAM_NAME: No adapter exists\n";
|
||||
return;
|
||||
}
|
||||
@res = </sys/bus/ccw/drivers/zfcp/*.*.*/0x*>;
|
||||
return () if (!@res);
|
||||
if (!@res) {
|
||||
print "$PROGRAM_NAME: No port on any adapter exists\n";
|
||||
return;
|
||||
}
|
||||
foreach my $entry (@res) {
|
||||
my $a = ${[split('/', $entry)]}[-2];
|
||||
my $p = ${[split('/', $entry)]}[-1];
|
||||
|
||||
@@ -8,6 +8,7 @@ install: all
|
||||
$(MAKE) -C src install
|
||||
$(MAKE) -C man install
|
||||
$(MAKE) -C dracut install
|
||||
$(MAKE) -C initramfs install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C src clean
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
# 95zdev/module_setup.sh
|
||||
# This module installs configuration files (udev rules and modprobe.conf
|
||||
# files) required to enable the root device on s390. It will only work when
|
||||
# the root device was configured using the chzdev tool.
|
||||
# the root device was configured using the chzdev tool. In addition,
|
||||
# a hook is installed to parse rd.zdev= kernel parameters.
|
||||
#
|
||||
|
||||
check() {
|
||||
@@ -29,30 +30,27 @@ depends() {
|
||||
}
|
||||
|
||||
installkernel() {
|
||||
local _modules=$(lszdev --by-path / --columns MODULES --no-headings 2>/dev/null)
|
||||
|
||||
[ -z "$_modules" ] && return 0
|
||||
[ ! -z "$_modules" ] && instmods $_modules
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
instmods lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
dasd_diag_mod zfcp
|
||||
}
|
||||
|
||||
install() {
|
||||
local _tempfile
|
||||
|
||||
# Exit early if root device type is unknown
|
||||
if ! lszdev --by-path / >/dev/null 2>&1 ; then
|
||||
return 0
|
||||
fi
|
||||
# Ensure that required tools are available
|
||||
inst_multiple chzdev lszdev vmcp
|
||||
|
||||
# Hook to parse zdev kernel parameter
|
||||
inst_hook cmdline 95 "$moddir/parse-zdev.sh"
|
||||
|
||||
# Obtain early + root device configuration
|
||||
_tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
|
||||
|
||||
if chzdev --export - --persistent --by-path / >/dev/null 2>&1 ; then
|
||||
# Use persistent configuration
|
||||
chzdev --export "$_tempfile" --persistent --by-path / --quiet --type
|
||||
else
|
||||
# Use active configuration
|
||||
chzdev --export "$_tempfile" --active --by-path / --quiet --type
|
||||
sed -i -e 's/active/persistent/g' "$_tempfile"
|
||||
fi
|
||||
chzdev --export "$_tempfile" --persistent --by-path / --quiet \
|
||||
--type 2>/dev/null
|
||||
chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \
|
||||
--type 2>/dev/null >> "$_tempfile"
|
||||
|
||||
# Apply via --import to prevent other devices from being configured
|
||||
chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \
|
||||
|
||||
38
zdev/dracut/95zdev/parse-zdev.sh
Normal file
38
zdev/dracut/95zdev/parse-zdev.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright IBM Corp. 2017
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
# 95zdev/parse-zdev.sh
|
||||
# Parse the kernel command line for rd.zdev kernel parameters. These
|
||||
# parameters are evaluated and used to configure z Systems specific devices.
|
||||
#
|
||||
# Format:
|
||||
# rd.zdev=no-auto
|
||||
#
|
||||
# where
|
||||
#
|
||||
# no-auto: Indicates that firmware-provided I/O configuration data
|
||||
# should not be applied.
|
||||
#
|
||||
|
||||
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
||||
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
||||
|
||||
if [ -e "$zdev_fw_file" ] ; then
|
||||
zdev_auto=1
|
||||
else
|
||||
zdev_auto=0
|
||||
fi
|
||||
|
||||
for zdev_arg in $(getargs rd.zdev); do
|
||||
if [ "$zdev_arg" = "no-auto" ] ; then
|
||||
zdev_auto=0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $zdev_auto -eq 1 ] ; then
|
||||
chzdev --import "$zdev_fw_file" $zdev_base_args
|
||||
fi
|
||||
@@ -11,11 +11,14 @@ ZDEVDIR := 95zdev
|
||||
# performs the following functions when dracut is run:
|
||||
#
|
||||
# - copy the persistent root device configuration to the initial ram disk
|
||||
# - install a boot-time hook to apply firmware-provided configuration data
|
||||
# to the system
|
||||
#
|
||||
ifeq ($(HAVE_DRACUT),1)
|
||||
install:
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)/$(ZDEVDIR)
|
||||
$(INSTALL) -m 755 $(ZDEVDIR)/module-setup.sh \
|
||||
$(ZDEVDIR)/parse-zdev.sh \
|
||||
$(DESTDIR)$(MODDIR)/$(ZDEVDIR)/
|
||||
endif
|
||||
|
||||
@@ -189,6 +189,7 @@ struct value_map {
|
||||
* in the persistent configuration
|
||||
* @nounload: (Device type attributes only) This attribute can be set while
|
||||
* the corresponding kernel module remains loaded.
|
||||
* @internal: This attribute only affects internal handling
|
||||
* @order: A number indicating the order in which to apply attribute
|
||||
* @order_cmp: A function determining if a setting for this attribute should
|
||||
* be applied before (-1) or after (1) another setting, or
|
||||
@@ -216,6 +217,7 @@ struct attrib {
|
||||
unsigned int activerem :1;
|
||||
unsigned int defunset :1;
|
||||
unsigned int nounload :1;
|
||||
unsigned int internal :1;
|
||||
|
||||
/* Optional */
|
||||
int order;
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
#define DASD_H
|
||||
|
||||
struct devtype;
|
||||
struct subtype;
|
||||
|
||||
extern struct devtype dasd_devtype;
|
||||
extern struct subtype dasd_subtype_eckd;
|
||||
extern struct subtype dasd_subtype_fba;
|
||||
|
||||
#endif /* DASD_H */
|
||||
|
||||
@@ -45,6 +45,7 @@ struct device_state {
|
||||
* @node: Node for adding this device to a list
|
||||
* @active: Device state in the active configuration
|
||||
* @persistent: Device state in the persistent configuration
|
||||
* @autoconf: Auto-configured device state
|
||||
* @errors: A strlist of error and warning messages issued for the device
|
||||
* @processed: Device has been processed
|
||||
*/
|
||||
@@ -59,6 +60,7 @@ struct device {
|
||||
|
||||
struct device_state active;
|
||||
struct device_state persistent;
|
||||
struct device_state autoconf;
|
||||
|
||||
unsigned int processed:1;
|
||||
};
|
||||
@@ -94,5 +96,9 @@ void device_list_add(struct device_list *, struct device *);
|
||||
struct device *device_list_find(struct device_list *, const char *,
|
||||
struct device *);
|
||||
void device_list_print(struct device_list *, int);
|
||||
struct setting_list *device_get_setting_list(struct device *dev,
|
||||
config_t config);
|
||||
|
||||
config_t device_get_config(struct device *dev);
|
||||
|
||||
#endif /* DEVICE_H */
|
||||
|
||||
@@ -31,6 +31,7 @@ struct export_object {
|
||||
} ptr;
|
||||
};
|
||||
|
||||
struct export_object *object_new(export_t type, void *ptr);
|
||||
exit_code_t export_write_device(FILE *, struct device *, config_t, int *);
|
||||
exit_code_t export_write_devtype(FILE *, struct devtype *, config_t, int *);
|
||||
exit_code_t export_read(FILE *, const char *, struct util_list *);
|
||||
|
||||
25
zdev/include/firmware.h
Normal file
25
zdev/include/firmware.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef FIRMWARE_H
|
||||
#define FIRMWARE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "exit_code.h"
|
||||
#include "misc.h"
|
||||
|
||||
struct util_list;
|
||||
|
||||
bool firmware_detect(FILE *fd);
|
||||
exit_code_t firmware_read(FILE *fd, const char *filename, long skip,
|
||||
config_t config, struct util_list *objects);
|
||||
|
||||
#endif /* FIRMWARE_H */
|
||||
25
zdev/include/internal.h
Normal file
25
zdev/include/internal.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_H
|
||||
#define INTERNAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
#define INTERNAL_ATTR_PREFIX "zdev:"
|
||||
#define INTERNAL_ATTR_EARLY INTERNAL_ATTR_PREFIX "early"
|
||||
|
||||
extern struct attrib internal_attr_early;
|
||||
|
||||
const char *internal_get_name(const char *name);
|
||||
bool internal_by_name(const char *name);
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
@@ -19,9 +19,14 @@
|
||||
#include "exit_code.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define SCOPE_ACTIVE(x) (((x) == config_active) || ((x) == config_all))
|
||||
#define SCOPE_PERSISTENT(x) (((x) == config_persistent) || \
|
||||
((x) == config_all))
|
||||
#define SCOPE_ACTIVE(x) ((x) & config_active ? 1 : 0)
|
||||
#define SCOPE_PERSISTENT(x) ((x) & config_persistent ? 1 : 0)
|
||||
#define SCOPE_AUTOCONF(x) ((x) & config_autoconf ? 1 : 0)
|
||||
#define SCOPE_ALL(x) ((x) == (config_active | config_persistent |\
|
||||
config_autoconf))
|
||||
#define SCOPE_SINGLE(x) ((x) == config_active || \
|
||||
(x) == config_persistent || \
|
||||
(x) == config_autoconf)
|
||||
|
||||
#define DELAY_INDENT 4
|
||||
|
||||
@@ -34,12 +39,15 @@
|
||||
|
||||
#define EVEN(x) (((x) & 1) == 0)
|
||||
|
||||
/* Enumeration of configuration sets. */
|
||||
typedef enum {
|
||||
config_active,
|
||||
config_persistent,
|
||||
config_all,
|
||||
} config_t;
|
||||
/* Enumeration of configuration sets. Multiple configuration sets can be
|
||||
* combined using bit-wise or. */
|
||||
enum {
|
||||
config_active = 1,
|
||||
config_persistent = 2,
|
||||
config_autoconf = 4,
|
||||
config_all = 7,
|
||||
};
|
||||
typedef int config_t;
|
||||
|
||||
typedef enum {
|
||||
err_ignore,
|
||||
@@ -159,6 +167,7 @@ bool misc_read_dir(const char *, struct util_list *,
|
||||
bool (*)(const char *, void *), void *);
|
||||
bool file_is_devnode(const char *);
|
||||
exit_code_t remove_file(const char *);
|
||||
exit_code_t misc_read_fd(FILE *fd, void **buffer, size_t *size_ptr);
|
||||
char *misc_read_text_file(const char *, int, err_t);
|
||||
char *misc_read_cmd_output(const char *, int, err_t);
|
||||
char *config_read_cmd_output(const char *, int, err_t);
|
||||
@@ -166,7 +175,7 @@ exit_code_t misc_write_text_file(const char *, const char *, err_t);
|
||||
exit_code_t misc_write_text_file_retry(const char *, const char *, err_t);
|
||||
exit_code_t misc_mktemp(char **, int *);
|
||||
char *misc_readlink(const char *path);
|
||||
config_t get_config(int, int);
|
||||
config_t get_config(int act, int pers, int ac);
|
||||
bool is_zvm(void);
|
||||
bool is_terminal(void);
|
||||
const char *config_to_str(config_t);
|
||||
@@ -174,6 +183,7 @@ bool str_to_config(const char *, config_t *);
|
||||
char *quote_str(const char *, int);
|
||||
char *unquote_str(const char *);
|
||||
char *shrink_str(const char *);
|
||||
char *misc_strrstr(const char *haystack, const char *needle);
|
||||
|
||||
struct util_list *strlist_new(void);
|
||||
void strlist_free(struct util_list *);
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
#define UDEV_SUFFIX ".rules"
|
||||
|
||||
#define PATH_MODPROBE_CONF "/etc/modprobe.d"
|
||||
#define PATH_MODPROBE "/usr/sbin/modprobe"
|
||||
#define PATH_MODPROBE "/sbin/modprobe"
|
||||
#define PATH_CCW_BUS "/sys/bus/ccw"
|
||||
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
|
||||
#define PATH_UDEV_RULES "/etc/udev/rules.d"
|
||||
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
|
||||
#define PATH_PROC "/proc"
|
||||
|
||||
#define PATH_UDEVADM "udevadm"
|
||||
@@ -55,8 +56,8 @@ char *path_get_ccw_device(const char *, const char *);
|
||||
char *path_get_ccw_devices(const char *);
|
||||
char *path_get_ccwgroup_device(const char *, const char *);
|
||||
char *path_get_ccwgroup_devices(const char *);
|
||||
char *path_get_udev_rule(const char *, const char *);
|
||||
char *path_get_udev_rules(void);
|
||||
char *path_get_udev_rule(const char *type, const char *id, bool vol);
|
||||
char *path_get_udev_rules(bool vol);
|
||||
char *path_get_proc(const char *);
|
||||
char *path_get_sys_bus_dev(const char *, const char *);
|
||||
char *path_get_sys_bus_drv(const char *, const char *);
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
#define QETH_NUM_DEVS 3
|
||||
|
||||
struct devtype;
|
||||
struct subtype;
|
||||
struct namespace;
|
||||
|
||||
extern struct devtype qeth_devtype;
|
||||
extern struct subtype qeth_subtype_qeth;
|
||||
extern struct namespace qeth_namespace;
|
||||
|
||||
#endif /* QETH_H */
|
||||
|
||||
@@ -94,7 +94,8 @@ void setting_list_map_values(struct setting_list *);
|
||||
void setting_list_mark_default_derived(struct setting_list *);
|
||||
int setting_list_count_set(struct setting_list *);
|
||||
void setting_list_remove_derived(struct setting_list *);
|
||||
char *setting_get_changes(struct setting_list *, struct setting_list *);
|
||||
char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
|
||||
struct setting_list *ac);
|
||||
bool setting_match_value(struct setting *, const char *);
|
||||
|
||||
#endif /* SETTING_H */
|
||||
|
||||
@@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id,
|
||||
*
|
||||
* @exists_active: Check if device exists in active configuration
|
||||
* @exists_persistent: Check if device exists in persistent configuration
|
||||
* @exists_autoconf: Check if device exists in autoconf configuration
|
||||
*
|
||||
* @add_active_ids: Add IDs of all devices existing in active configuration to
|
||||
* specified strlist
|
||||
* @add_persistent_ids: Add IDs of all devices existing in persistent
|
||||
* configuration to specified strlist
|
||||
* @add_autoconf_ids: Add IDs of all devices existing in autoconf
|
||||
* configuration to specified strlist
|
||||
*
|
||||
* @read_active: Read device configuration from active configuration
|
||||
* @read_persistent: Read device configuration from persistent configuration
|
||||
* @read_autoconf: Read device configuration from autoconf configuration
|
||||
*
|
||||
* @configure_active: Apply configuration to active configuration
|
||||
* @configure_persistent: Apply configuration to persistent configuration
|
||||
* @configure_autoconf: Apply configuration to autoconf configuration
|
||||
*
|
||||
* @check_pre_write: Optional: Determine if the given configuration is valid
|
||||
* for the specified device. If not, emit warning messages
|
||||
@@ -150,24 +155,33 @@ struct subtype {
|
||||
|
||||
bool (*exists_active)(struct subtype *, const char *);
|
||||
bool (*exists_persistent)(struct subtype *, const char *);
|
||||
bool (*exists_autoconf)(struct subtype *, const char *);
|
||||
|
||||
void (*add_active_ids)(struct subtype *, struct util_list *);
|
||||
void (*add_persistent_ids)(struct subtype *,
|
||||
struct util_list *);
|
||||
void (*add_autoconf_ids)(struct subtype *,
|
||||
struct util_list *);
|
||||
|
||||
exit_code_t (*read_active)(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t (*read_persistent)(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t (*read_autoconf)(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
|
||||
exit_code_t (*configure_active)(struct subtype *, struct device *);
|
||||
exit_code_t (*configure_persistent)(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t (*configure_autoconf)(struct subtype *,
|
||||
struct device *);
|
||||
|
||||
exit_code_t (*deconfigure_active)(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t (*deconfigure_persistent)(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t (*deconfigure_autoconf)(struct subtype *,
|
||||
struct device *);
|
||||
|
||||
exit_code_t (*check_pre_configure)(struct subtype *,
|
||||
struct device *, int, config_t);
|
||||
@@ -217,23 +231,31 @@ void subtype_exit(struct subtype *);
|
||||
|
||||
bool subtype_device_exists_active(struct subtype *, const char *);
|
||||
bool subtype_device_exists_persistent(struct subtype *, const char *);
|
||||
bool subtype_device_exists_autoconf(struct subtype *st, const char *id);
|
||||
|
||||
void subtype_add_active_ids(struct subtype *, struct util_list *);
|
||||
void subtype_add_persistent_ids(struct subtype *, struct util_list *);
|
||||
void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids);
|
||||
|
||||
exit_code_t subtype_device_read_active(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t subtype_device_read_persistent(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t subtype_device_read_autoconf(struct subtype *st, struct device *dev,
|
||||
read_scope_t scope);
|
||||
|
||||
exit_code_t subtype_device_configure_active(struct subtype *, struct device *);
|
||||
exit_code_t subtype_device_configure_persistent(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t subtype_device_configure_autoconf(struct subtype *st,
|
||||
struct device *dev);
|
||||
|
||||
exit_code_t subtype_device_deconfigure_active(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t subtype_device_deconfigure_persistent(struct subtype *st,
|
||||
struct device *);
|
||||
exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev);
|
||||
|
||||
exit_code_t subtype_check_pre_configure(struct subtype *, struct device *, int,
|
||||
config_t);
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
#include "lib/util_list.h"
|
||||
#include "exit_code.h"
|
||||
|
||||
struct attrib;
|
||||
struct setting_list;
|
||||
|
||||
extern int udev_need_settle;
|
||||
extern int udev_no_settle;
|
||||
|
||||
/* Single key-operator-value entry in a udev rule line.*/
|
||||
struct udev_entry_node {
|
||||
@@ -39,9 +43,14 @@ exit_code_t udev_read_file(const char *, struct udev_file **);
|
||||
void udev_free_file(struct udev_file *);
|
||||
void udev_file_print(struct udev_file *);
|
||||
|
||||
void udev_get_device_ids(const char *, struct util_list *);
|
||||
exit_code_t udev_remove_rule(const char *, const char *);
|
||||
void udev_get_device_ids(const char *type, struct util_list *list,
|
||||
bool autoconf);
|
||||
exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf);
|
||||
|
||||
void udev_settle(void);
|
||||
|
||||
void udev_add_internal_from_entry(struct setting_list *list,
|
||||
struct udev_entry_node *entry,
|
||||
struct attrib **attribs);
|
||||
|
||||
#endif /* UDEV_H */
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
struct device;
|
||||
|
||||
bool udev_ccw_exists(const char *, const char *);
|
||||
exit_code_t udev_ccw_read_device(struct device *);
|
||||
exit_code_t udev_ccw_write_device(struct device *);
|
||||
exit_code_t udev_ccw_write_cio_ignore(const char *);
|
||||
bool udev_ccw_exists(const char *type, const char *id, bool autoconf);
|
||||
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf);
|
||||
|
||||
#endif /* UDEV_CCW_H */
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
struct device;
|
||||
struct util_list;
|
||||
|
||||
bool udev_ccwgroup_exists(const char *, const char *);
|
||||
exit_code_t udev_ccwgroup_read_device(struct device *);
|
||||
exit_code_t udev_ccwgroup_write_device(struct device *);
|
||||
void udev_ccwgroup_add_device_ids(const char *, struct util_list *);
|
||||
exit_code_t udev_ccwgroup_remove_rule(const char *, const char *);
|
||||
bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf);
|
||||
exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf);
|
||||
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
|
||||
bool autoconf);
|
||||
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
|
||||
bool autoconf);
|
||||
|
||||
#endif /* UDEV_CCWGROUP_H */
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
struct device;
|
||||
|
||||
void udev_zfcp_lun_add_device_ids(struct util_list *);
|
||||
bool udev_zfcp_lun_exists(const char *);
|
||||
exit_code_t udev_zfcp_lun_read_device(struct device *);
|
||||
exit_code_t udev_zfcp_lun_write_device(struct device *);
|
||||
exit_code_t udev_zfcp_lun_remove_rule(const char *);
|
||||
void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf);
|
||||
bool udev_zfcp_lun_exists(const char *id, bool autoconf);
|
||||
exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf);
|
||||
|
||||
#endif /* UDEV_ZFCP_LUN_H */
|
||||
|
||||
22
zdev/initramfs/Makefile
Normal file
22
zdev/initramfs/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
INITRAMFSDIR := /usr/share/initramfs-tools
|
||||
HOOKDIR := $(INITRAMFSDIR)/hooks
|
||||
INITTOP := $(INITRAMFSDIR)/scripts/init-top
|
||||
|
||||
# HAVE_INITRAMFS
|
||||
#
|
||||
# This install time parameter determines whether the zdev initramfs support is
|
||||
# installed (HAVE_INITRAMFS=1) or not (default). When installed, the module
|
||||
# performs the following functions when mkinitramfs is run:
|
||||
#
|
||||
# - install a boot-time hook to apply firmware-provided configuration data
|
||||
# to the system
|
||||
#
|
||||
ifeq ($(HAVE_INITRAMFS),1)
|
||||
install:
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)/$(HOOKDIR) $(DESTDIR)/$(INITTOP)
|
||||
$(INSTALL) -m 755 hooks/zdev $(DESTDIR)/$(HOOKDIR)
|
||||
$(INSTALL) -m 755 scripts/init-top/zdev $(DESTDIR)/$(INITTOP)
|
||||
endif
|
||||
56
zdev/initramfs/hooks/zdev
Normal file
56
zdev/initramfs/hooks/zdev
Normal file
@@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright IBM Corp. 2016, 2017
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
# hooks/zdev
|
||||
# This hook script adds files required to apply firmware-provided I/O
|
||||
# configuration data during boot.
|
||||
#
|
||||
|
||||
# Needs to run after udev or resulting udev rules could be overwritten
|
||||
PREREQ="udev"
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
. /usr/share/initramfs-tools/hook-functions
|
||||
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
zdev_modules="lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod dasd_diag_mod zfcp"
|
||||
|
||||
for x in $zdev_modules ; do
|
||||
manual_add_modules ${x}
|
||||
done
|
||||
|
||||
copy_exec /sbin/chzdev
|
||||
copy_exec /sbin/lszdev
|
||||
copy_exec /sbin/vmcp
|
||||
|
||||
_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX)
|
||||
|
||||
# Obtain early + root device configuration
|
||||
chzdev --export "$_tempfile" --persistent --by-path / \
|
||||
--by-attrib "zdev:early=1" --quiet --type 2>/dev/null
|
||||
|
||||
# Apply via --import to prevent other devices from being configured.
|
||||
# Rename the resulting cio-ignore rule to ensure that it does not override
|
||||
# the one copied by the initramfs udev hook to /lib/udev.
|
||||
chzdev --import "$_tempfile" --persistent \
|
||||
--base "/etc/udev/rules.d/41-cio-ignore.rules=$DESTDIR/etc/udev/rules.d/41-cio-ignore-root.rules" \
|
||||
--base "/etc=$DESTDIR/etc" --yes --quiet --no-root-update --force \
|
||||
>/dev/null
|
||||
|
||||
rm -f "$_tempfile"
|
||||
67
zdev/initramfs/scripts/init-top/zdev
Normal file
67
zdev/initramfs/scripts/init-top/zdev
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright IBM Corp. 2017
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
# scripts/init-top/zdev
|
||||
# Parse the kernel command line for rd.zdev kernel parameters. These
|
||||
# parameters are evaluated and used to configure z Systems specific devices.
|
||||
#
|
||||
# Format:
|
||||
# rd.zdev=no-auto
|
||||
#
|
||||
# where
|
||||
#
|
||||
# no-auto: Indicates that firmware-provided I/O configuration data
|
||||
# should not be applied.
|
||||
#
|
||||
|
||||
PREREQ="udev"
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
. /scripts/functions
|
||||
|
||||
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
||||
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
||||
|
||||
if [ -e "$zdev_fw_file" ] ; then
|
||||
zdev_auto=1
|
||||
else
|
||||
zdev_auto=0
|
||||
fi
|
||||
|
||||
for x in $(cat /proc/cmdline); do
|
||||
case ${x} in
|
||||
rd.zdev=*)
|
||||
zdev_arg=${x#*=}
|
||||
if [ "$zdev_arg" = "no-auto" ] ; then
|
||||
zdev_auto=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $zdev_auto -eq 1 ] ; then
|
||||
log_begin_msg "Starting firmware auto-configuration"
|
||||
chzdev --import "$zdev_fw_file" $zdev_base_args
|
||||
log_end_msg
|
||||
|
||||
# Repeat cold-plug after creating udev rules
|
||||
udevadm control --reload
|
||||
udevadm trigger --type=subsystems --action=add
|
||||
udevadm trigger --action=add
|
||||
udevadm settle || true
|
||||
fi
|
||||
@@ -334,6 +334,35 @@ a specific attribute.
|
||||
.PP
|
||||
.
|
||||
.
|
||||
.SS "Special settings"
|
||||
The following special settings affect how devices are handled by chzdev:
|
||||
.PP
|
||||
.
|
||||
.BR zdev:early =0|1
|
||||
.RS 4
|
||||
Control in which stage of the boot process a device is activated:
|
||||
.TP 4
|
||||
.B 0
|
||||
Device is activated normally during boot (default).
|
||||
.PP
|
||||
.TP 4
|
||||
.B 1
|
||||
Device is activated early in the boot process, by the initial RAM-disk.
|
||||
.PP
|
||||
Specify a value of 1 for this attribute in any of the following situations:
|
||||
.TP 4
|
||||
\(bu
|
||||
To ensure that your settings override auto-configuration settings.
|
||||
.PP
|
||||
.TP 4
|
||||
\(bu
|
||||
To ensure that a device required to access the root file system is correctly
|
||||
enabled during boot. An example would be a networking device, or a device that
|
||||
is intended to extend a logical volume that provides the root file system.
|
||||
.PP
|
||||
.RE
|
||||
.
|
||||
.
|
||||
.SH ACTIONS
|
||||
You can use one of the action options listed below to specify the
|
||||
.B main tool action
|
||||
@@ -409,17 +438,27 @@ default value.
|
||||
.PP
|
||||
.
|
||||
.OD import "" "FILENAME" "|-"
|
||||
Import configuration data from a text file.
|
||||
Import configuration data from a text or machine-provided file.
|
||||
|
||||
Reads configuration data from FILENAME and applies it. If a single hyphen ("-")
|
||||
is specified as FILENAME data is read from the standard input stream. The
|
||||
input format of the data read must be the same format as produced by the
|
||||
chzdev \-\-export action.
|
||||
input format must be either in the format as produced by the chzdev \-\-export
|
||||
action, or in the format of a machine-provided I/O configuration data file.
|
||||
|
||||
.B Machine-provided data:
|
||||
Some machine models provide I/O configuration data which is made available
|
||||
by the Linux kernel via a sysfs interface. While this data is intended for
|
||||
automatic consumption during the boot phase, you can also apply it manually
|
||||
using the \-\-import action like in the following example
|
||||
|
||||
.B Example:
|
||||
.CL chzdev --import /sys/firmware/sclp_sd/config/data
|
||||
|
||||
.B Note:
|
||||
By default all configuration data that is read is also applied. To reduce the
|
||||
scope of imported configuration data, you can select specific devices, a device
|
||||
type, or define whether only data for the active or persistent configuration
|
||||
should be imported.
|
||||
type, or define whether only data for the active, persistent or
|
||||
auto-configuration should be imported.
|
||||
.PP
|
||||
.
|
||||
.OD list-attributes "l" ""
|
||||
@@ -462,6 +501,18 @@ on reboot, or when a device becomes unavailable, or when a device driver is
|
||||
unloaded.
|
||||
.PP
|
||||
.
|
||||
.OD auto-conf "" ""
|
||||
Apply changes to the auto-configuration only.
|
||||
|
||||
This option is used internally to apply machine-provided I/O configuration data
|
||||
to a Linux system.
|
||||
|
||||
.B Note:
|
||||
There is typically no need for users to specify this option directly.
|
||||
In particular, user-initiated changes to this configuration will be lost
|
||||
the next time that machine-provided data is obtained (i.e. during boot).
|
||||
.PP
|
||||
.
|
||||
.OD base "" "PATH" | "KEY" = "VALUE"
|
||||
Change file system paths used to access files.
|
||||
|
||||
@@ -518,6 +569,15 @@ device configuration persistent. Typically such steps include rebuilding the
|
||||
initial RAM disk, or modifying the kernel command line.
|
||||
.PP
|
||||
.
|
||||
.OD no-settle "" ""
|
||||
Do not wait for udev processing to complete.
|
||||
|
||||
Skips all calls to the udevadm tool that are intended to wait for udev to
|
||||
finish processing before continuing. There is typically no need to use this
|
||||
option unless chzdev is run in an environment where udev is not fully
|
||||
functional (such as in the early phase of an initial RAM disk).
|
||||
.PP
|
||||
.
|
||||
.OD persistent "p" ""
|
||||
Apply changes to persistent configuration only.
|
||||
|
||||
|
||||
@@ -69,12 +69,13 @@ With no further options specified, the output format defaults to list format.
|
||||
.
|
||||
.
|
||||
.SS "Configurations"
|
||||
There are two sources for configuration information: the active configuration
|
||||
of the currently running system, and the persistent configuration stored in
|
||||
configuration files.
|
||||
There are three sources for configuration information: the active configuration
|
||||
of the currently running system, the persistent configuration stored in
|
||||
configuration files, and the auto-configuration that is provided by some
|
||||
machine types to automatically enable I/O devices.
|
||||
.PP
|
||||
By default lszdev displays information from both the active and the persistent
|
||||
configuration.
|
||||
configuration, and, if available, from the auto-configuration.
|
||||
.PP
|
||||
.
|
||||
.
|
||||
@@ -319,6 +320,19 @@ Restricts output to information obtained from the active configuration, that
|
||||
is information from the running system.
|
||||
.PP
|
||||
.
|
||||
.OD auto-conf "" ""
|
||||
List information from the auto-configuration only.
|
||||
|
||||
Restricts output to information obtained from the auto-configuration.
|
||||
The auto-configuration is the collection of configuration data obtained
|
||||
automatically on some machine models during boot.
|
||||
|
||||
.B Note:
|
||||
This data is refreshed during each boot. Also configuration directives in
|
||||
the auto-configuration only take effect if there is no directive for the
|
||||
same device in the persistent configuration.
|
||||
.PP
|
||||
.
|
||||
.OD base "" "PATH" | "KEY" = "VALUE"
|
||||
Change file system paths used to access files.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
|
||||
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
root.o select.o setting.o subtype.o table.o table_attribs.o \
|
||||
table_types.o net.o
|
||||
table_types.o net.o firmware.o internal.o
|
||||
|
||||
# Devtype Helpers
|
||||
chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
||||
@@ -38,7 +38,7 @@ chzdev_objects += generic_ccw.o
|
||||
lszdev_objects += attrib.o lszdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
root.o select.o setting.o subtype.o table.o table_types.o \
|
||||
net.o
|
||||
net.o internal.o
|
||||
|
||||
# Devtype Helpers
|
||||
lszdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
||||
|
||||
100
zdev/src/ccw.c
100
zdev/src/ccw.c
@@ -73,6 +73,7 @@ struct attrib ccw_attr_cmb_enable = {
|
||||
" 1: Data collection is enabled (rewrite 1 to reset data)\n",
|
||||
.rewrite = 1,
|
||||
.defval = "0",
|
||||
.order_cmp = ccw_offline_only_order_cmp,
|
||||
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
|
||||
};
|
||||
|
||||
@@ -892,12 +893,13 @@ static exit_code_t collect_group_cb(struct subtype *st, const char *id,
|
||||
}
|
||||
|
||||
/* Set bits for all persistently configured CCW devices. */
|
||||
static char ***id_bitmap_collect(void)
|
||||
static char ***id_bitmap_collect(bool autoconf)
|
||||
{
|
||||
char ***id_bitmap;
|
||||
int i, j;
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
config_t config = autoconf ? config_autoconf : config_persistent;
|
||||
|
||||
id_bitmap = id_bitmap_new();
|
||||
|
||||
@@ -906,14 +908,14 @@ static char ***id_bitmap_collect(void)
|
||||
for (j = 0; (st = dt->subtypes[j]); j++) {
|
||||
/* Collect CCW device IDs. */
|
||||
if (st->namespace == &ccw_namespace) {
|
||||
subtype_for_each_id(st, config_persistent,
|
||||
subtype_for_each_id(st, config,
|
||||
collect_cb, id_bitmap);
|
||||
}
|
||||
/* Collect CCWGROUP device IDs. Since there may be
|
||||
* multiple namespaces, we need to make use of this
|
||||
* hack. */
|
||||
if (ccwgroup_compatible_namespace(st->namespace)) {
|
||||
subtype_for_each_id(st, config_persistent,
|
||||
subtype_for_each_id(st, config,
|
||||
collect_group_cb,
|
||||
id_bitmap);
|
||||
}
|
||||
@@ -952,7 +954,7 @@ static void range_add(struct util_list *list, struct ccw_devid *from,
|
||||
free(f_str);
|
||||
}
|
||||
|
||||
static struct util_list *cio_ignore_get_ranges(void)
|
||||
static struct util_list *cio_ignore_get_ranges(bool autoconf)
|
||||
{
|
||||
char ***id_bitmap;
|
||||
unsigned int cssid, ssid, devno;
|
||||
@@ -962,7 +964,7 @@ static struct util_list *cio_ignore_get_ranges(void)
|
||||
|
||||
ranges = strlist_new();
|
||||
|
||||
id_bitmap = id_bitmap_collect();
|
||||
id_bitmap = id_bitmap_collect(autoconf);
|
||||
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
|
||||
if (!id_bitmap[cssid])
|
||||
continue;
|
||||
@@ -1003,24 +1005,34 @@ static struct util_list *cio_ignore_get_ranges(void)
|
||||
}
|
||||
|
||||
/* Persistently configure cio_ignore. */
|
||||
exit_code_t ccw_blacklist_persist(void)
|
||||
static exit_code_t _ccw_blacklist_persist(bool autoconf)
|
||||
{
|
||||
struct util_list *ranges;
|
||||
char *id_list;
|
||||
exit_code_t rc;
|
||||
|
||||
/* Get string to write to /proc/cio_ignore. */
|
||||
ranges = cio_ignore_get_ranges();
|
||||
ranges = cio_ignore_get_ranges(autoconf);
|
||||
id_list = strlist_flatten(ranges, ",");
|
||||
strlist_free(ranges);
|
||||
|
||||
/* Write udev rule to automatically write cio_ignore. */
|
||||
rc = udev_ccw_write_cio_ignore(id_list);
|
||||
rc = udev_ccw_write_cio_ignore(id_list, autoconf);
|
||||
free(id_list);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
exit_code_t ccw_blacklist_persist(void)
|
||||
{
|
||||
exit_code_t rc1, rc2;
|
||||
|
||||
rc1 = _ccw_blacklist_persist(false);
|
||||
rc2 = _ccw_blacklist_persist(true);
|
||||
|
||||
return rc1 ? rc1 : rc2;
|
||||
}
|
||||
|
||||
/*
|
||||
* CCW device ID namespace.
|
||||
*/
|
||||
@@ -1368,7 +1380,13 @@ static bool ccw_st_exists_active(struct subtype *st, const char *id)
|
||||
/* Check if a configuration exists for a CCW device with the specified @id. */
|
||||
static bool ccw_st_exists_persistent(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccw_exists(st->name, id);
|
||||
return udev_ccw_exists(st->name, id, false);
|
||||
}
|
||||
|
||||
/* Check if a configuration exists for a CCW device with the specified @id. */
|
||||
static bool ccw_st_exists_autoconf(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccw_exists(st->name, id, true);
|
||||
}
|
||||
|
||||
static bool get_ids_cb(const char *file, void *data)
|
||||
@@ -1404,7 +1422,14 @@ static void ccw_st_add_active_ids(struct subtype *st, struct util_list *ids)
|
||||
* to strlist @ids. */
|
||||
static void ccw_st_add_persistent_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
udev_get_device_ids(st->name, ids);
|
||||
udev_get_device_ids(st->name, ids, false);
|
||||
}
|
||||
|
||||
/* Add the IDs of all CCW devices for which a autoconf configuration exists
|
||||
* to strlist @ids. */
|
||||
static void ccw_st_add_autoconf_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
udev_get_device_ids(st->name, ids, true);
|
||||
}
|
||||
|
||||
/* Read the configuration of the CCW device with the specified @id from the
|
||||
@@ -1440,7 +1465,16 @@ static exit_code_t ccw_st_read_persistent(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
return udev_ccw_read_device(dev);
|
||||
return udev_ccw_read_device(dev, false);
|
||||
}
|
||||
|
||||
/* Read the configuration of the CCW device with the specified @id from the
|
||||
* autoconf configuration and add the resulting data to @dev. */
|
||||
static exit_code_t ccw_st_read_autoconf(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
return udev_ccw_read_device(dev, true);
|
||||
}
|
||||
|
||||
static int get_online(struct setting_list *list)
|
||||
@@ -1505,7 +1539,14 @@ static exit_code_t ccw_st_configure_active(struct subtype *st,
|
||||
static exit_code_t ccw_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccw_write_device(dev);
|
||||
return udev_ccw_write_device(dev, false);
|
||||
}
|
||||
|
||||
/* Create a autoconf configuration for the specified device @dev. */
|
||||
static exit_code_t ccw_st_configure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccw_write_device(dev, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1552,7 +1593,22 @@ static exit_code_t ccw_st_deconfigure_active(struct subtype *st,
|
||||
static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_remove_rule(st->name, dev->id);
|
||||
return udev_remove_rule(st->name, dev->id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* ccw_st_deconfigure_autoconf - Deconfigure device in autoconf
|
||||
* configuration set
|
||||
* @st: Subtype of target device
|
||||
* @dev: Target device
|
||||
*
|
||||
* Deconfigure device @dev in the autoconf configuration set. Return %EXIT_OK
|
||||
* on success, an error code otherwise.
|
||||
*/
|
||||
static exit_code_t ccw_st_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_remove_rule(st->name, dev->id, true);
|
||||
}
|
||||
|
||||
/* Perform basic sanity checks. */
|
||||
@@ -1589,6 +1645,8 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev,
|
||||
setting_list_apply(dev->active.settings, a, name, value);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
setting_list_apply(dev->persistent.settings, a, name, value);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
setting_list_apply(dev->autoconf.settings, a, name, value);
|
||||
}
|
||||
|
||||
/* Determine the online state of the specified CCW device (0=offline, 1=online,
|
||||
@@ -1596,14 +1654,16 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev,
|
||||
static int ccw_st_online_get(struct subtype *st, struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
int act_online = 1, pers_online = 1;
|
||||
int act_online = 1, pers_online = 1, auto_online = 1;
|
||||
|
||||
if (SCOPE_ACTIVE(config))
|
||||
act_online = get_online(dev->active.settings);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
pers_online = get_online(dev->persistent.settings);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
auto_online = get_online(dev->autoconf.settings);
|
||||
|
||||
return MIN(act_online, pers_online);
|
||||
return MIN(MIN(act_online, pers_online), auto_online);
|
||||
}
|
||||
|
||||
/* Determine if the online state of the specified CCW device was specified */
|
||||
@@ -1622,6 +1682,11 @@ static bool ccw_st_online_specified(struct subtype *st, struct device *dev,
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
|
||||
s = setting_list_find(dev->autoconf.settings, "online");
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1769,18 +1834,23 @@ struct subtype ccw_subtype = {
|
||||
|
||||
.exists_active = &ccw_st_exists_active,
|
||||
.exists_persistent = &ccw_st_exists_persistent,
|
||||
.exists_autoconf = &ccw_st_exists_autoconf,
|
||||
|
||||
.add_active_ids = &ccw_st_add_active_ids,
|
||||
.add_persistent_ids = &ccw_st_add_persistent_ids,
|
||||
.add_autoconf_ids = &ccw_st_add_autoconf_ids,
|
||||
|
||||
.read_active = &ccw_st_read_active,
|
||||
.read_persistent = &ccw_st_read_persistent,
|
||||
.read_autoconf = &ccw_st_read_autoconf,
|
||||
|
||||
.configure_active = &ccw_st_configure_active,
|
||||
.configure_persistent = &ccw_st_configure_persistent,
|
||||
.configure_autoconf = &ccw_st_configure_autoconf,
|
||||
|
||||
.deconfigure_active = &ccw_st_deconfigure_active,
|
||||
.deconfigure_persistent = &ccw_st_deconfigure_persistent,
|
||||
.deconfigure_autoconf = &ccw_st_deconfigure_autoconf,
|
||||
|
||||
.check_pre_configure = &ccw_st_check_pre_configure,
|
||||
|
||||
|
||||
@@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struct subtype *st, struct device *dev,
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
setting_list_apply(dev->persistent.settings, a, name, value);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
setting_list_apply(dev->autoconf.settings, a, name, value);
|
||||
}
|
||||
|
||||
static int get_online(struct setting_list *list)
|
||||
@@ -446,18 +448,20 @@ static int get_online(struct setting_list *list)
|
||||
}
|
||||
|
||||
/* Return -1 if online state is not configured, 0 for offline and 1 for online.
|
||||
* If multiple configurations are specified, return the minimum of both. */
|
||||
* If multiple configurations are specified, return the minimum of all. */
|
||||
static int ccwgroup_st_online_get(struct subtype *st, struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
int act_online = 1, pers_online = 1;
|
||||
int act_online = 1, pers_online = 1, auto_online = 1;
|
||||
|
||||
if (SCOPE_ACTIVE(config))
|
||||
act_online = get_online(dev->active.settings);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
pers_online = get_online(dev->persistent.settings);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
auto_online = get_online(dev->autoconf.settings);
|
||||
|
||||
return MIN(act_online, pers_online);
|
||||
return MIN(MIN(act_online, pers_online), auto_online);
|
||||
}
|
||||
|
||||
/* Determine if the online state of the specified device was modified. */
|
||||
@@ -476,6 +480,11 @@ static bool ccwgroup_st_online_specified(struct subtype *st,
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
|
||||
s = setting_list_find(dev->autoconf.settings, "online");
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -682,7 +691,18 @@ static exit_code_t ccwgroup_st_read_persistent(struct subtype *st,
|
||||
|
||||
expand_id(data->ccwgroupdrv, dev);
|
||||
|
||||
return udev_ccwgroup_read_device(dev);
|
||||
return udev_ccwgroup_read_device(dev, false);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_read_autoconf(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
struct ccwgroup_subtype_data *data = st->data;
|
||||
|
||||
expand_id(data->ccwgroupdrv, dev);
|
||||
|
||||
return udev_ccwgroup_read_device(dev, true);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
|
||||
@@ -693,8 +713,9 @@ static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
|
||||
return device_write_active_settings(dev);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
static exit_code_t _ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev,
|
||||
bool autoconf)
|
||||
{
|
||||
struct ccwgroup_subtype_data *data = st->data;
|
||||
struct ccwgroup_devid *devid = dev->devid;
|
||||
@@ -703,9 +724,22 @@ static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
delayed_err("Incomplete device ID specified\n");
|
||||
return EXIT_INCOMPLETE_ID;
|
||||
}
|
||||
return udev_ccwgroup_write_device(dev);
|
||||
return udev_ccwgroup_write_device(dev, autoconf);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return _ccwgroup_st_configure_persistent(st, dev, false);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return _ccwgroup_st_configure_persistent(st, dev, true);
|
||||
}
|
||||
|
||||
|
||||
static char *ccwgroup_st_get_active_attrib_path(struct subtype *,
|
||||
struct device *, const char *);
|
||||
|
||||
@@ -733,7 +767,13 @@ static exit_code_t ccwgroup_st_deconfigure_active(struct subtype *st,
|
||||
static exit_code_t ccwgroup_st_deconfigure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccwgroup_remove_rule(st->name, dev->id);
|
||||
return udev_ccwgroup_remove_rule(st->name, dev->id, false);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccwgroup_remove_rule(st->name, dev->id, true);
|
||||
}
|
||||
|
||||
/* Check if a CCWGROUP device with the specified ID exists. */
|
||||
@@ -774,7 +814,12 @@ static bool ccwgroup_st_exists_active(struct subtype *st, const char *id)
|
||||
|
||||
static bool ccwgroup_st_exists_persistent(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccwgroup_exists(st->name, id);
|
||||
return udev_ccwgroup_exists(st->name, id, false);
|
||||
}
|
||||
|
||||
static bool ccwgroup_st_exists_autoconf(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccwgroup_exists(st->name, id, true);
|
||||
}
|
||||
|
||||
int ccwgroup_qsort_cmp(const void *a_ptr, const void *b_ptr)
|
||||
@@ -796,7 +841,13 @@ static void ccwgroup_st_add_active_ids(struct subtype *st,
|
||||
static void ccwgroup_st_add_persistent_ids(struct subtype *st,
|
||||
struct util_list *ids)
|
||||
{
|
||||
udev_ccwgroup_add_device_ids(st->name, ids);
|
||||
udev_ccwgroup_add_device_ids(st->name, ids, false);
|
||||
}
|
||||
|
||||
static void ccwgroup_st_add_autoconf_ids(struct subtype *st,
|
||||
struct util_list *ids)
|
||||
{
|
||||
udev_ccwgroup_add_device_ids(st->name, ids, true);
|
||||
}
|
||||
|
||||
/* Check if CCW device ID @b is part of CCW group device ID @a. */
|
||||
@@ -1185,18 +1236,23 @@ struct subtype ccwgroup_subtype = {
|
||||
|
||||
.exists_active = &ccwgroup_st_exists_active,
|
||||
.exists_persistent = &ccwgroup_st_exists_persistent,
|
||||
.exists_autoconf = &ccwgroup_st_exists_autoconf,
|
||||
|
||||
.add_active_ids = &ccwgroup_st_add_active_ids,
|
||||
.add_persistent_ids = &ccwgroup_st_add_persistent_ids,
|
||||
.add_autoconf_ids = &ccwgroup_st_add_autoconf_ids,
|
||||
|
||||
.read_active = &ccwgroup_st_read_active,
|
||||
.read_persistent = &ccwgroup_st_read_persistent,
|
||||
.read_autoconf = &ccwgroup_st_read_autoconf,
|
||||
|
||||
.configure_active = &ccwgroup_st_configure_active,
|
||||
.configure_persistent = &ccwgroup_st_configure_persistent,
|
||||
.configure_autoconf = &ccwgroup_st_configure_autoconf,
|
||||
|
||||
.deconfigure_active = &ccwgroup_st_deconfigure_active,
|
||||
.deconfigure_persistent = &ccwgroup_st_deconfigure_persistent,
|
||||
.deconfigure_autoconf = &ccwgroup_st_deconfigure_autoconf,
|
||||
|
||||
.online_set = &ccwgroup_st_online_set,
|
||||
.online_get = &ccwgroup_st_online_get,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "export.h"
|
||||
#include "firmware.h"
|
||||
#include "inuse.h"
|
||||
#include "misc.h"
|
||||
#include "module.h"
|
||||
@@ -85,6 +86,7 @@ struct options {
|
||||
config_t config;
|
||||
unsigned int active:1;
|
||||
unsigned int persistent:1;
|
||||
unsigned int auto_conf:1;
|
||||
struct util_list *remove; /* List of struct strlist_node */
|
||||
unsigned int remove_all:1;
|
||||
unsigned int force:1;
|
||||
@@ -94,6 +96,7 @@ struct options {
|
||||
struct util_list *base; /* List of struct strlist_node */
|
||||
unsigned int verbose:1;
|
||||
unsigned int quiet:1;
|
||||
unsigned int no_settle:1;
|
||||
};
|
||||
|
||||
/* Makefile converts chzdev_usage.txt into C file which we include here. */
|
||||
@@ -135,6 +138,8 @@ enum {
|
||||
OPT_VERSION = 'v',
|
||||
OPT_VERBOSE = 'V',
|
||||
OPT_QUIET = 'q',
|
||||
OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
};
|
||||
|
||||
static struct opts_conflict conflict_list[] = {
|
||||
@@ -169,11 +174,13 @@ static struct opts_conflict conflict_list[] = {
|
||||
OPTS_CONFLICT(OPT_APPLY,
|
||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
||||
OPT_REMOVE_ALL, OPT_ACTIVE, OPT_PERSISTENT, 0),
|
||||
OPT_REMOVE_ALL, OPT_ACTIVE, 0),
|
||||
OPTS_CONFLICT(OPT_ONLINE,
|
||||
OPT_OFFLINE),
|
||||
OPTS_CONFLICT(OPT_QUIET,
|
||||
OPT_VERBOSE),
|
||||
OPTS_CONFLICT(OPT_AUTO_CONF,
|
||||
OPT_TYPE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES),
|
||||
OPTS_CONFLICT(0, 0),
|
||||
};
|
||||
|
||||
@@ -207,6 +214,7 @@ static const struct option opt_list[] = {
|
||||
/* Options. */
|
||||
{ "active", no_argument, NULL, OPT_ACTIVE },
|
||||
{ "persistent", no_argument, NULL, OPT_PERSISTENT },
|
||||
{ "auto-conf", no_argument, NULL, OPT_AUTO_CONF },
|
||||
{ "remove", required_argument, NULL, OPT_REMOVE },
|
||||
{ "remove-all", no_argument, NULL, OPT_REMOVE_ALL },
|
||||
{ "force", no_argument, NULL, OPT_FORCE },
|
||||
@@ -216,6 +224,7 @@ static const struct option opt_list[] = {
|
||||
{ "base", required_argument, NULL, OPT_BASE },
|
||||
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
||||
{ "quiet", no_argument, NULL, OPT_QUIET },
|
||||
{ "no-settle", no_argument, NULL, OPT_NO_SETTLE },
|
||||
{ NULL, no_argument, NULL, 0 },
|
||||
};
|
||||
|
||||
@@ -879,6 +888,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->persistent = 1;
|
||||
break;
|
||||
|
||||
case OPT_AUTO_CONF:
|
||||
/* --auto-conf */
|
||||
opts->auto_conf = 1;
|
||||
break;
|
||||
|
||||
case OPT_REMOVE:
|
||||
/* --remove ATTRIB */
|
||||
strlist_add(opts->remove, "%s", optarg);
|
||||
@@ -936,6 +950,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->quiet = 1;
|
||||
break;
|
||||
|
||||
case OPT_NO_SETTLE:
|
||||
/* --no-settle */
|
||||
opts->no_settle = 1;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
/* Missing option argument. */
|
||||
syntax("Option '%s' requires an argument\n",
|
||||
@@ -968,7 +987,13 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
goto out;
|
||||
|
||||
/* Determine configuration set. */
|
||||
opts->config = get_config(opts->active, opts->persistent);
|
||||
if (!opts->active && !opts->persistent && !opts->auto_conf) {
|
||||
/* Default configuration targets are active + persistent */
|
||||
opts->config = config_active | config_persistent;
|
||||
} else {
|
||||
opts->config = get_config(opts->active, opts->persistent,
|
||||
opts->auto_conf);
|
||||
}
|
||||
|
||||
/* Handle positional parameters. */
|
||||
rc = parse_positional(opts, argc, argv, optind);
|
||||
@@ -1040,13 +1065,15 @@ static void remove_all_settings(struct setting_list *settings, int active)
|
||||
/* Perform --remove-all operation for specified config on device. */
|
||||
static exit_code_t device_remove_all(struct device *dev, config_t config)
|
||||
{
|
||||
int active, persistent;
|
||||
int active, persistent, autoconf;
|
||||
|
||||
active = SCOPE_ACTIVE(config) ?
|
||||
count_removable(dev->active.settings, 1) : 0;
|
||||
persistent = SCOPE_PERSISTENT(config) ?
|
||||
count_removable(dev->persistent.settings, 0) : 0;
|
||||
if (active == 0 && persistent == 0) {
|
||||
autoconf = SCOPE_AUTOCONF(config) ?
|
||||
count_removable(dev->autoconf.settings, 0) : 0;
|
||||
if (active == 0 && persistent == 0 && autoconf == 0) {
|
||||
delayed_err("No removable settings found\n");
|
||||
return EXIT_SETTING_NOT_FOUND;
|
||||
}
|
||||
@@ -1054,6 +1081,8 @@ static exit_code_t device_remove_all(struct device *dev, config_t config)
|
||||
remove_all_settings(dev->active.settings, 1);
|
||||
if (persistent)
|
||||
remove_all_settings(dev->persistent.settings, 0);
|
||||
if (autoconf)
|
||||
remove_all_settings(dev->autoconf.settings, 0);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
@@ -1123,6 +1152,13 @@ static exit_code_t device_remove_settings(struct device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = remove_settings(dev->autoconf.settings, names, found,
|
||||
notfound, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!util_list_is_empty(notfound)) {
|
||||
flat = strlist_flatten(notfound, " ");
|
||||
delayed_err("Setting not found: %s\n", flat);
|
||||
@@ -1190,7 +1226,8 @@ static void print_dev_config_info(struct device *dev, config_t config)
|
||||
|
||||
changes = setting_get_changes(
|
||||
SCOPE_ACTIVE(config) ? dev->active.settings : NULL,
|
||||
SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL);
|
||||
SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL,
|
||||
SCOPE_AUTOCONF(config) ? dev->autoconf.settings : NULL);
|
||||
if (changes)
|
||||
info(" Changes: %s\n", changes);
|
||||
free(changes);
|
||||
@@ -1248,6 +1285,12 @@ static exit_code_t cfg_mod_existence(struct device *dev, config_t config)
|
||||
dev->persistent.modified = 1;
|
||||
}
|
||||
|
||||
/* Create autoconf config if necessary. */
|
||||
if (SCOPE_AUTOCONF(config) && !dev->autoconf.exists) {
|
||||
dev->autoconf.exists = 1;
|
||||
dev->autoconf.modified = 1;
|
||||
}
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
@@ -1287,11 +1330,14 @@ online:
|
||||
/* Make sure there's an online attribute. */
|
||||
ensure_online(dev, config_active);
|
||||
ensure_online(dev, config_persistent);
|
||||
ensure_online(dev, config_autoconf);
|
||||
|
||||
mand:
|
||||
/* Ensure default values for mandatory attributes. */
|
||||
setting_list_apply_defaults(dev->persistent.settings,
|
||||
dev->subtype->dev_attribs, true);
|
||||
setting_list_apply_defaults(dev->autoconf.settings,
|
||||
dev->subtype->dev_attribs, true);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
@@ -1324,10 +1370,11 @@ static exit_code_t cfg_write(struct device *dev, int prereq, config_t config,
|
||||
struct subtype *st = dev->subtype;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
if (!device_needs_writing(dev, config))
|
||||
if (!device_needs_writing(dev, config) && !force)
|
||||
goto out;
|
||||
|
||||
if (check_active && config == config_persistent &&
|
||||
if (check_active && !SCOPE_ACTIVE(config) &&
|
||||
(SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) &&
|
||||
(!dev->active.exists && !dev->active.definable)) {
|
||||
rc = handle_nonexistent(dev);
|
||||
if (rc)
|
||||
@@ -1368,7 +1415,7 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
|
||||
if (proc_ptr)
|
||||
*proc_ptr = 0;
|
||||
|
||||
/* Read current device data. Note that we read data from both
|
||||
/* Read current device data. Note that we read data from all
|
||||
* configurations to enable QETH autodetection and subtype
|
||||
* detection (e.g. dasd -> dasd_fba).*/
|
||||
dev = NULL;
|
||||
@@ -1389,23 +1436,17 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
|
||||
|
||||
/* Exit here if we're only trying and device cannot be configured. */
|
||||
if (try && !(dev->active.exists || dev->active.definable ||
|
||||
dev->persistent.exists)) {
|
||||
dev->persistent.exists || dev->autoconf.exists)) {
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (config == config_persistent) {
|
||||
/* Abort if a modification action is triggered for a
|
||||
* non-existing persistent device. */
|
||||
if (!dev->persistent.exists &&
|
||||
(!util_list_is_empty(opts->remove) || opts->remove_all))
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
/* Create device if needed by action. */
|
||||
if (opts->enable || !util_list_is_empty(opts->settings)) {
|
||||
rc = cfg_mod_existence(dev, config);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Apply changes to device existence. */
|
||||
rc = cfg_mod_existence(dev, config);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Apply changes to device settings. */
|
||||
rc = cfg_mod_settings(dev, opts, prereq);
|
||||
if (rc)
|
||||
@@ -1417,10 +1458,12 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
|
||||
|
||||
/* Apply persistent configuration to active configuration. */
|
||||
static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
|
||||
struct device **dev_ptr, int *proc_ptr)
|
||||
struct device **dev_ptr, int *proc_ptr,
|
||||
bool autoconf)
|
||||
{
|
||||
exit_code_t rc;
|
||||
struct device *dev;
|
||||
struct device_state *state;
|
||||
|
||||
/* Reset processed flag. */
|
||||
if (proc_ptr)
|
||||
@@ -1443,8 +1486,9 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
|
||||
*proc_ptr = 1;
|
||||
dev->processed = 1;
|
||||
|
||||
state = autoconf ? &dev->autoconf : &dev->persistent;
|
||||
/* Exit here if there is no persistent configuration. */
|
||||
if (!dev->persistent.exists)
|
||||
if (!state->exists)
|
||||
return EXIT_NO_DATA;
|
||||
|
||||
/* Apply changes to device existence. */
|
||||
@@ -1453,8 +1497,7 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
|
||||
return rc;
|
||||
|
||||
/* Copy persistent settings to active configuration. */
|
||||
rc = device_apply_settings(dev, config_active,
|
||||
&dev->persistent.settings->list);
|
||||
rc = device_apply_settings(dev, config_active, &state->settings->list);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -1468,7 +1511,8 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
|
||||
struct device **dev_ptr, int *proc_ptr)
|
||||
{
|
||||
exit_code_t rc;
|
||||
struct setting_list *active = NULL, *persistent = NULL;
|
||||
struct setting_list *active = NULL, *persistent = NULL,
|
||||
*autoconf = NULL;
|
||||
struct device *dev;
|
||||
|
||||
/* Reset processed flag. */
|
||||
@@ -1486,6 +1530,7 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
|
||||
return EXIT_OK;
|
||||
active = setting_list_copy(dev->active.settings);
|
||||
persistent = setting_list_copy(dev->persistent.settings);
|
||||
autoconf = setting_list_copy(dev->autoconf.settings);
|
||||
} else if (!prereq) {
|
||||
/* Should not happen. */
|
||||
return EXIT_OK;
|
||||
@@ -1515,14 +1560,20 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
|
||||
&persistent->list);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = device_apply_settings(dev, config_autoconf,
|
||||
&autoconf->list);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
ensure_online(dev, config_active);
|
||||
ensure_online(dev, config_persistent);
|
||||
ensure_online(dev, config_autoconf);
|
||||
|
||||
/* Write resulting device data. */
|
||||
rc = cfg_write(dev, prereq, config, 0);
|
||||
|
||||
out:
|
||||
setting_list_free(autoconf);
|
||||
setting_list_free(persistent);
|
||||
setting_list_free(active);
|
||||
|
||||
@@ -1600,11 +1651,13 @@ static exit_code_t print_config_result(struct selected_dev_node *sel,
|
||||
if (opts->deconfigure) {
|
||||
op = "deconfigure";
|
||||
verb = "deconfigured";
|
||||
if (dev)
|
||||
if (dev) {
|
||||
already = !dev->active.modified &&
|
||||
!dev->persistent.modified;
|
||||
else if (rc == EXIT_DEVICE_NOT_FOUND &&
|
||||
config == config_persistent) {
|
||||
!dev->persistent.modified &&
|
||||
!dev->autoconf.modified;
|
||||
} else if (rc == EXIT_DEVICE_NOT_FOUND &&
|
||||
(!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
|
||||
SCOPE_AUTOCONF(config)))) {
|
||||
rc = EXIT_OK;
|
||||
already = 1;
|
||||
}
|
||||
@@ -1615,6 +1668,10 @@ static exit_code_t print_config_result(struct selected_dev_node *sel,
|
||||
already = device_needs_writing(dev, config) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Re-do actions if run with --force */
|
||||
if (force)
|
||||
already = 0;
|
||||
|
||||
if (dev) {
|
||||
devname = dev->subtype->devname;
|
||||
devid = dev->id;
|
||||
@@ -1672,9 +1729,10 @@ static exit_code_t cfg_prereqs(struct subtype *st, const char *id,
|
||||
prereqs = selected_dev_list_new();
|
||||
subtype_add_prereqs(st, id, prereqs);
|
||||
util_list_iterate(prereqs, sel) {
|
||||
if (opts->apply)
|
||||
rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc);
|
||||
else if (opts->import) {
|
||||
if (opts->apply) {
|
||||
rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc,
|
||||
opts->auto_conf);
|
||||
} else if (opts->import) {
|
||||
rc = cfg_import(sel->st, sel->id, config, 1, &dev,
|
||||
&proc);
|
||||
} else {
|
||||
@@ -1747,9 +1805,11 @@ static exit_code_t configure_devices(struct options *opts, int specified,
|
||||
struct namespace *ns;
|
||||
const char *param;
|
||||
struct device *dev;
|
||||
config_t config = opts->config;
|
||||
|
||||
/* Determine list of selected devices. */
|
||||
if (opts->config == config_persistent ||
|
||||
if ((!SCOPE_ACTIVE(config) &&
|
||||
(SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config))) ||
|
||||
(opts->select->subtype && opts->select->subtype->support_definable))
|
||||
existing = 0;
|
||||
else
|
||||
@@ -1795,9 +1855,10 @@ static exit_code_t configure_devices(struct options *opts, int specified,
|
||||
goto next;
|
||||
|
||||
/* Configure actual target device. */
|
||||
if (opts->apply)
|
||||
rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc);
|
||||
else {
|
||||
if (opts->apply) {
|
||||
rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc,
|
||||
opts->auto_conf);
|
||||
} else {
|
||||
rc = cfg_configure(sel->st, sel->id, opts, 0,
|
||||
0, &dev, &proc);
|
||||
}
|
||||
@@ -1893,7 +1954,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||
dev->processed = 1;
|
||||
|
||||
if (try && !(dev->active.exists || dev->active.definable ||
|
||||
dev->persistent.exists)) {
|
||||
dev->persistent.exists || dev->autoconf.exists)) {
|
||||
/* Attempt to deconfigure this device will fail. */
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
@@ -1903,7 +1964,8 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||
* dev. */
|
||||
if (SCOPE_ACTIVE(config) &&
|
||||
!(dev->active.exists || dev->active.definable)) {
|
||||
if (!SCOPE_PERSISTENT(config) || !dev->persistent.exists)
|
||||
if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) ||
|
||||
(SCOPE_AUTOCONF(config) && dev->autoconf.exists)))
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -1927,7 +1989,12 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||
dev->persistent.deconfigured = 1;
|
||||
dev->persistent.modified = 1;
|
||||
}
|
||||
if (!dev->active.modified && !dev->persistent.modified)
|
||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) {
|
||||
dev->autoconf.deconfigured = 1;
|
||||
dev->autoconf.modified = 1;
|
||||
}
|
||||
if (!dev->active.modified && !dev->persistent.modified &&
|
||||
!dev->autoconf.modified)
|
||||
return EXIT_OK;
|
||||
|
||||
/* Pre-write check. */
|
||||
@@ -2071,7 +2138,8 @@ static void print_type_config_info(struct devtype *dt, const char *title,
|
||||
|
||||
changes = setting_get_changes(
|
||||
SCOPE_ACTIVE(config) ? dt->active_settings : NULL,
|
||||
SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL);
|
||||
SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL,
|
||||
NULL);
|
||||
if (changes)
|
||||
info(" %s: %s\n", title, changes);
|
||||
free(changes);
|
||||
@@ -2485,6 +2553,8 @@ static void action_note(const char *msg, config_t config)
|
||||
info("%s the active configuration only\n", msg);
|
||||
else if (config == config_persistent)
|
||||
info("%s the persistent configuration only\n", msg);
|
||||
else if (config == config_autoconf)
|
||||
info("%s the auto-configuration only\n", msg);
|
||||
}
|
||||
|
||||
/* Export configuration of selected devices and/or device type to file. */
|
||||
@@ -2500,9 +2570,9 @@ static exit_code_t do_export(struct options *opts)
|
||||
/* Open output stream. */
|
||||
if (strcmp(opts->export, "-") == 0) {
|
||||
fd = stdout;
|
||||
info("Exporting configuration data to standard output\n");
|
||||
info("Exporting data to standard output\n");
|
||||
} else {
|
||||
info("Exporting configuration data to %s\n", opts->export);
|
||||
info("Exporting data to %s\n", opts->export);
|
||||
if (!util_path_exists(opts->export)) {
|
||||
rc = path_create(opts->export);
|
||||
if (rc)
|
||||
@@ -2606,7 +2676,7 @@ static exit_code_t import_device(struct device *dev, struct options *opts)
|
||||
struct subtype *st = dev->subtype;
|
||||
exit_code_t rc;
|
||||
config_t config;
|
||||
int proc = 0, active, persistent;
|
||||
int proc = 0, active, persistent, autoconf;
|
||||
|
||||
if (SCOPE_ACTIVE(opts->config))
|
||||
active = (dev->active.exists || dev->active.definable);
|
||||
@@ -2616,7 +2686,16 @@ static exit_code_t import_device(struct device *dev, struct options *opts)
|
||||
persistent = dev->persistent.exists;
|
||||
else
|
||||
persistent = 0;
|
||||
config = get_config(active, persistent);
|
||||
if (SCOPE_AUTOCONF(opts->config))
|
||||
autoconf = dev->autoconf.exists;
|
||||
else
|
||||
autoconf = 0;
|
||||
|
||||
if (!active && !persistent && !autoconf) {
|
||||
/* Nothing to import */
|
||||
return EXIT_OK;
|
||||
}
|
||||
config = get_config(active, persistent, autoconf);
|
||||
|
||||
/* First check for prerequisite devices that need to be configured. */
|
||||
rc = cfg_prereqs(st, dev->id, opts, config, 0);
|
||||
@@ -2643,17 +2722,9 @@ static bool import_device_selected(struct device *dev, struct options *opts)
|
||||
if (!select_opts_dev_specified(select))
|
||||
return false;
|
||||
|
||||
/* --active */
|
||||
if (opts->config == config_active) {
|
||||
if (!dev->active.exists && !dev->active.definable)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --persistent */
|
||||
if (opts->config == config_persistent) {
|
||||
if (!dev->persistent.exists)
|
||||
return false;
|
||||
}
|
||||
/* Target configuration */
|
||||
if ((device_get_config(dev) & opts->config) == 0)
|
||||
return false;
|
||||
|
||||
/* Devtype */
|
||||
if (select->devtype && dt != select->devtype)
|
||||
@@ -2735,6 +2806,7 @@ static exit_code_t do_import(struct options *opts)
|
||||
exit_code_t drc = EXIT_OK;
|
||||
const char *filename;
|
||||
int found;
|
||||
bool is_firmware;
|
||||
|
||||
/* Open input stream. */
|
||||
if (strcmp(opts->import, "-") == 0) {
|
||||
@@ -2744,16 +2816,23 @@ static exit_code_t do_import(struct options *opts)
|
||||
fd = fopen(opts->import, "r");
|
||||
filename = opts->import;
|
||||
}
|
||||
info("Importing configuration data from %s\n", filename);
|
||||
|
||||
if (!fd) {
|
||||
error("Could not open file %s: %s\n", opts->import,
|
||||
strerror(errno));
|
||||
return EXIT_RUNTIME_ERROR;
|
||||
}
|
||||
|
||||
is_firmware = firmware_detect(fd);
|
||||
info("Importing data from %s%s\n", filename,
|
||||
is_firmware ? " (firmware format)" : "");
|
||||
|
||||
/* Read data. */
|
||||
objects = ptrlist_new();
|
||||
rc = export_read(fd, filename, objects);
|
||||
if (is_firmware)
|
||||
rc = firmware_read(fd, filename, -1, opts->config, objects);
|
||||
else
|
||||
rc = export_read(fd, filename, objects);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@@ -2766,8 +2845,8 @@ static exit_code_t do_import(struct options *opts)
|
||||
"selection\n", filename);
|
||||
rc = EXIT_EMPTY_SELECTION;
|
||||
} else {
|
||||
error("%s: No settings found to import\n", filename);
|
||||
rc = EXIT_NO_DATA;
|
||||
info("%s: No settings found to import\n", filename);
|
||||
rc = EXIT_OK;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@@ -2895,6 +2974,7 @@ int main(int argc, char *argv[])
|
||||
force = opts.force;
|
||||
yes = opts.yes;
|
||||
dryrun = opts.dryrun;
|
||||
udev_no_settle = opts.no_settle;
|
||||
path_set_base(opts.base);
|
||||
|
||||
if (dryrun)
|
||||
@@ -2945,8 +3025,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
if ((pers_mod_devs || pers_mod_devtypes) && !opts.no_root_check &&
|
||||
!dryrun) {
|
||||
/* If the root device/device type has been modified, additional
|
||||
* work might be necessary. */
|
||||
/* If the root device/device type or early devices have been
|
||||
* modified, additional work might be necessary. */
|
||||
rc = root_check();
|
||||
if (rc && !drc)
|
||||
drc = rc;
|
||||
|
||||
@@ -54,5 +54,7 @@ OPTIONS
|
||||
--no-root-update Skip root device update
|
||||
--dry-run Display changes without applying
|
||||
--base PATH Use PATH as base for accessing files
|
||||
--no-settle Do not wait for udev to settle
|
||||
--auto-conf Apply changes to auto-configuration only
|
||||
-V, --verbose Print additional run-time information
|
||||
-q, --quiet Print only minimal run-time information
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "ctc_auto.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "path.h"
|
||||
@@ -425,6 +426,7 @@ static struct subtype ctc_subtype = {
|
||||
&ccw_attr_online,
|
||||
&ctc_attr_buffer,
|
||||
&ctc_attr_protocol,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.support_definable = 1,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "dasd.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "modprobe.h"
|
||||
#include "module.h"
|
||||
@@ -316,34 +317,34 @@ static struct attrib dasd_attr_safe_offline = {
|
||||
* DASD subtype methods.
|
||||
*/
|
||||
|
||||
static bool _check_use_diag(struct setting_list *list)
|
||||
{
|
||||
struct setting *u;
|
||||
|
||||
u = setting_list_find(list, dasd_attr_use_diag.name);
|
||||
if (u && u->modified) {
|
||||
if (u->value && atoi(u->value) == 1) {
|
||||
delayed_warn("Cannot set 'use_diag=1' on non-z/VM system\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check if use_diag setting can be correctly applied. */
|
||||
static exit_code_t check_use_diag(struct device *dev, config_t config)
|
||||
{
|
||||
struct setting *u;
|
||||
int zvm = is_zvm();
|
||||
if (is_zvm())
|
||||
return EXIT_OK;
|
||||
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
u = setting_list_find(dev->active.settings,
|
||||
dasd_attr_use_diag.name);
|
||||
if (u && u->modified) {
|
||||
if (u->value && atoi(u->value) == 1 && !zvm) {
|
||||
delayed_warn("Cannot set 'use_diag=1' on "
|
||||
"non-z/VM system\n");
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
u = setting_list_find(dev->persistent.settings,
|
||||
dasd_attr_use_diag.name);
|
||||
if (u && u->modified) {
|
||||
if (u->value && atoi(u->value) == 1 && !zvm) {
|
||||
delayed_warn("Cannot set 'use_diag=1' on "
|
||||
"non-z/VM system\n");
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SCOPE_ACTIVE(config) && !_check_use_diag(dev->active.settings))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
if (SCOPE_PERSISTENT(config) &&
|
||||
!_check_use_diag(dev->persistent.settings))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
if (SCOPE_AUTOCONF(config) &&
|
||||
!_check_use_diag(dev->autoconf.settings))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
@@ -376,6 +377,8 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev,
|
||||
dasd_attr_use_diag.name, &changed, &aset);
|
||||
setting_list_get_bool_state(dev->persistent.settings,
|
||||
dasd_attr_use_diag.name, &changed, &pset);
|
||||
setting_list_get_bool_state(dev->autoconf.settings,
|
||||
dasd_attr_use_diag.name, &changed, &pset);
|
||||
|
||||
if (aset || pset)
|
||||
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
|
||||
@@ -589,7 +592,7 @@ static struct ccw_subtype_data dasd_eckd_data = {
|
||||
.mod = "dasd_eckd_mod",
|
||||
};
|
||||
|
||||
static struct subtype dasd_subtype_eckd = {
|
||||
struct subtype dasd_subtype_eckd = {
|
||||
.super = &ccw_subtype,
|
||||
.devtype = &dasd_devtype,
|
||||
.name = "dasd-eckd",
|
||||
@@ -614,6 +617,7 @@ static struct subtype dasd_subtype_eckd = {
|
||||
&dasd_attr_reservation_policy,
|
||||
&dasd_attr_last_known_reservation_state,
|
||||
&dasd_attr_safe_offline,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
@@ -626,7 +630,7 @@ static struct ccw_subtype_data dasd_fba_data = {
|
||||
.mod = "dasd_fba_mod",
|
||||
};
|
||||
|
||||
static struct subtype dasd_subtype_fba = {
|
||||
struct subtype dasd_subtype_fba = {
|
||||
.super = &ccw_subtype,
|
||||
.devtype = &dasd_devtype,
|
||||
.name = "dasd-fba",
|
||||
@@ -649,6 +653,7 @@ static struct subtype dasd_subtype_fba = {
|
||||
&dasd_attr_reservation_policy,
|
||||
&dasd_attr_last_known_reservation_state,
|
||||
&dasd_attr_safe_offline,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "attrib.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "setting.h"
|
||||
@@ -40,6 +41,7 @@ struct device *device_new(struct subtype *st, const char *id)
|
||||
|
||||
dev->active.settings = setting_list_new();
|
||||
dev->persistent.settings = setting_list_new();
|
||||
dev->autoconf.settings = setting_list_new();
|
||||
|
||||
return dev;
|
||||
}
|
||||
@@ -53,6 +55,7 @@ void device_free(struct device *dev)
|
||||
free(dev->devid);
|
||||
setting_list_free(dev->active.settings);
|
||||
setting_list_free(dev->persistent.settings);
|
||||
setting_list_free(dev->autoconf.settings);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
@@ -83,6 +86,15 @@ void device_print(struct device *dev, int level)
|
||||
setting_list_print(dev->persistent.settings, level + 8);
|
||||
else
|
||||
printf("%*s<none>\n", level + 8, "");
|
||||
|
||||
printf("%*sautoconf:\n", level + 4, "");
|
||||
printf("%*sexists=%d mod=%d deconf=%d\n",
|
||||
level + 8, "", dev->autoconf.exists, dev->autoconf.modified,
|
||||
dev->autoconf.deconfigured);
|
||||
if (dev->autoconf.settings)
|
||||
setting_list_print(dev->autoconf.settings, level + 8);
|
||||
else
|
||||
printf("%*s<none>\n", level + 8, "");
|
||||
}
|
||||
|
||||
static const void *device_hash_get_id(void *dev_ptr)
|
||||
@@ -182,6 +194,10 @@ bool device_needs_writing(struct device *dev, config_t config)
|
||||
(dev->persistent.modified || dev->persistent.deconfigured ||
|
||||
setting_list_modified(dev->persistent.settings)))
|
||||
return true;
|
||||
if (SCOPE_AUTOCONF(config) &&
|
||||
(dev->autoconf.modified || dev->autoconf.deconfigured ||
|
||||
setting_list_modified(dev->autoconf.settings)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -204,6 +220,11 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
/* Check for activeonly. */
|
||||
if (!force && SCOPE_PERSISTENT(config) && a->activeonly)
|
||||
goto err_activeonly_forceable;
|
||||
if (!force && SCOPE_AUTOCONF(config) && a->activeonly)
|
||||
goto err_activeonly_forceable;
|
||||
/* Check for internal. */
|
||||
if (config == config_active && a->internal)
|
||||
goto err_int_noactive;
|
||||
/* Check for multiple values. */
|
||||
if (!force && !a->multi && strlist_find(processed, key))
|
||||
goto err_multi_forceable;
|
||||
@@ -213,6 +234,9 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
goto err_unknown;
|
||||
if (!force)
|
||||
goto err_unknown_forceable;
|
||||
/* Check for internal. */
|
||||
if (config == config_active && internal_by_name(key))
|
||||
goto err_int_noactive;
|
||||
}
|
||||
|
||||
strlist_add(processed, "%s", key);
|
||||
@@ -231,8 +255,15 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
a, key, value);
|
||||
}
|
||||
|
||||
/* Apply to autoconf config. */
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
setting_list_apply_specified(dev->autoconf.settings,
|
||||
a, key, value);
|
||||
}
|
||||
|
||||
/* Additional warning when trying to persist read-only setting. */
|
||||
if (config == config_persistent) {
|
||||
if (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
|
||||
SCOPE_AUTOCONF(config))) {
|
||||
s = setting_list_find(dev->active.settings, key);
|
||||
if (s && s->readonly)
|
||||
warn_readonly = true;
|
||||
@@ -270,6 +301,11 @@ err_activeonly_forceable:
|
||||
delayed_forceable("Attribute '%s' should only be changed in the active "
|
||||
"config\n", a->name);
|
||||
return EXIT_INVALID_SETTING;
|
||||
|
||||
err_int_noactive:
|
||||
delayed_err("Internal attribute '%s' cannot be set in the active config\n",
|
||||
key);
|
||||
return EXIT_INVALID_SETTING;
|
||||
}
|
||||
|
||||
/* Apply device settings from strlist to device. */
|
||||
@@ -341,6 +377,8 @@ void device_reset(struct device *dev, config_t config)
|
||||
reset_device_state(&dev->active);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
reset_device_state(&dev->persistent);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
reset_device_state(&dev->autoconf);
|
||||
dev->processed = 0;
|
||||
}
|
||||
|
||||
@@ -516,6 +554,9 @@ exit_code_t device_write_active_settings(struct device *dev)
|
||||
s = p->ptr;
|
||||
if (!s->modified || s->removed)
|
||||
continue;
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name))
|
||||
continue;
|
||||
|
||||
path = subtype_get_active_attrib_path(st, dev, s->name);
|
||||
if (!path) {
|
||||
@@ -567,6 +608,44 @@ exit_code_t device_check_settings(struct device *dev, config_t config,
|
||||
err))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
if (!setting_list_check_conflict(dev->autoconf.settings,
|
||||
config_autoconf,
|
||||
err))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
struct setting_list *device_get_setting_list(struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
struct setting_list *settings = NULL;
|
||||
|
||||
if (config == config_active)
|
||||
settings = dev->active.settings;
|
||||
else if (config == config_persistent)
|
||||
settings = dev->persistent.settings;
|
||||
else if (config == config_autoconf)
|
||||
settings = dev->autoconf.settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/* Return configuration set in which device exists. */
|
||||
config_t device_get_config(struct device *dev)
|
||||
{
|
||||
config_t config = 0;
|
||||
|
||||
if (dev->active.exists || dev->active.definable)
|
||||
config |= config_active;
|
||||
|
||||
if (dev->persistent.exists)
|
||||
config |= config_persistent;
|
||||
|
||||
if (dev->autoconf.exists)
|
||||
config |= config_autoconf;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static bool is_exportable(struct setting *s, config_t config)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
if (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) {
|
||||
if (setting_is_set(s))
|
||||
return true;
|
||||
}
|
||||
@@ -148,10 +148,9 @@ static int count_exportable(struct device *dev, config_t config)
|
||||
struct setting *s;
|
||||
int count;
|
||||
|
||||
if (config == config_active)
|
||||
list = dev->active.settings;
|
||||
else
|
||||
list = dev->persistent.settings;
|
||||
list = device_get_setting_list(dev, config);
|
||||
if (!list)
|
||||
return 0;
|
||||
count = 0;
|
||||
|
||||
util_list_iterate(&list->list, s) {
|
||||
@@ -169,12 +168,26 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config,
|
||||
exit_code_t rc;
|
||||
struct setting_list *settings;
|
||||
|
||||
if (config == config_all) {
|
||||
rc = export_write_device(fd, dev, config_active, first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
return export_write_device(fd, dev, config_persistent,
|
||||
first_ptr);
|
||||
if (!SCOPE_SINGLE(config)) {
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = export_write_device(fd, dev, config_active,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = export_write_device(fd, dev, config_persistent,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = export_write_device(fd, dev, config_autoconf,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (config == config_active) {
|
||||
@@ -185,10 +198,14 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config,
|
||||
!dev->subtype->support_definable)
|
||||
return EXIT_OK;
|
||||
settings = dev->active.settings;
|
||||
} else {
|
||||
} else if (config == config_persistent) {
|
||||
if (!dev->persistent.exists)
|
||||
return EXIT_OK;
|
||||
settings = dev->persistent.settings;
|
||||
} else {
|
||||
if (!dev->autoconf.exists)
|
||||
return EXIT_OK;
|
||||
settings = dev->autoconf.settings;
|
||||
}
|
||||
|
||||
write_header(fd, config, dev->subtype->name, dev->id, first_ptr);
|
||||
@@ -204,12 +221,21 @@ exit_code_t export_write_devtype(FILE *fd, struct devtype *dt, config_t config,
|
||||
exit_code_t rc;
|
||||
struct setting_list *settings;
|
||||
|
||||
if (config == config_all) {
|
||||
rc = export_write_devtype(fd, dt, config_active, first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
return export_write_devtype(fd, dt, config_persistent,
|
||||
first_ptr);
|
||||
if (!SCOPE_SINGLE(config)) {
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = export_write_devtype(fd, dt, config_active,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = export_write_devtype(fd, dt, config_persistent,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
/* Scope autoconf not supported for devtype */
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (config == config_active)
|
||||
@@ -282,19 +308,6 @@ static bool parse_setting(const char *line, char **key_ptr, char **val_ptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct setting_list *dev_get_setting_list(struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
struct setting_list *settings = NULL;
|
||||
|
||||
if (config == config_active)
|
||||
settings = dev->active.settings;
|
||||
else
|
||||
settings = dev->persistent.settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
static struct setting_list *dt_get_setting_list(struct devtype *dt,
|
||||
config_t config)
|
||||
{
|
||||
@@ -392,6 +405,10 @@ static exit_code_t handle_header(const char *filename, int lineno,
|
||||
setting_list_clear(dev->persistent.settings);
|
||||
dev->persistent.exists = 1;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(hdr->config)) {
|
||||
setting_list_clear(dev->autoconf.settings);
|
||||
dev->autoconf.exists = 1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -410,13 +427,26 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
||||
struct attrib **attribs, *a;
|
||||
struct setting_list *list;
|
||||
|
||||
if (config == config_all) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt, dev,
|
||||
config_active);
|
||||
if (rc)
|
||||
return rc;
|
||||
return handle_setting(filename, lineno, key, value, dt, dev,
|
||||
config_persistent);
|
||||
if (!SCOPE_SINGLE(config)) {
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt,
|
||||
dev, config_active);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt,
|
||||
dev, config_persistent);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt,
|
||||
dev, config_autoconf);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (dt) {
|
||||
@@ -426,7 +456,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
||||
} else if (dev) {
|
||||
/* We're inside a device section. */
|
||||
attribs = dev->subtype->dev_attribs;
|
||||
list = dev_get_setting_list(dev, config);
|
||||
list = device_get_setting_list(dev, config);
|
||||
} else
|
||||
return EXIT_OK;
|
||||
|
||||
@@ -444,7 +474,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
static struct export_object *object_new(export_t type, void *ptr)
|
||||
struct export_object *object_new(export_t type, void *ptr)
|
||||
{
|
||||
struct export_object *obj;
|
||||
|
||||
@@ -465,7 +495,8 @@ static bool empty_device(struct device *dev)
|
||||
if (dev->subtype->support_definable)
|
||||
return false;
|
||||
if (util_list_is_empty(&dev->active.settings->list) &&
|
||||
util_list_is_empty(&dev->persistent.settings->list))
|
||||
util_list_is_empty(&dev->persistent.settings->list) &&
|
||||
util_list_is_empty(&dev->autoconf.settings->list))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
682
zdev/src/firmware.c
Normal file
682
zdev/src/firmware.c
Normal file
@@ -0,0 +1,682 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "attrib.h"
|
||||
#include "ccw.h"
|
||||
#include "ccwgroup.h"
|
||||
#include "dasd.h"
|
||||
#include "device.h"
|
||||
#include "export.h"
|
||||
#include "firmware.h"
|
||||
#include "misc.h"
|
||||
#include "qeth.h"
|
||||
#include "subtype.h"
|
||||
#include "zfcp_host.h"
|
||||
#include "zfcp_lun.h"
|
||||
|
||||
/* In-memory firmware file representation. */
|
||||
struct fw_file {
|
||||
const char *name;
|
||||
char *buffer;
|
||||
size_t size;
|
||||
char *last_access;
|
||||
size_t last_size;
|
||||
};
|
||||
|
||||
/* Record access to fields of the buffered file for use in warning messages. */
|
||||
#define fwacc(f, x) ((f)->last_access = (char *) &(x), \
|
||||
(f)->last_size = sizeof(x), x)
|
||||
|
||||
/*
|
||||
* Firmware file format definitions.
|
||||
*/
|
||||
|
||||
/* Firmware file header. */
|
||||
struct fw_filehdr {
|
||||
uint32_t magic;
|
||||
uint16_t ver;
|
||||
uint16_t hdr_len;
|
||||
uint32_t file_len;
|
||||
uint32_t seq;
|
||||
uint32_t zeroes;
|
||||
uint16_t de_count;
|
||||
char unused[10];
|
||||
} __packed;
|
||||
|
||||
#define FW_HDR_MAGIC 0x7a646576 /* ASCII "zdev" */
|
||||
#define FW_HDR_VER_Z14 0x0000
|
||||
|
||||
/* I/O device ID. */
|
||||
struct fw_iodevid {
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
} __packed;
|
||||
|
||||
#define FW_IODEVID_FLAG_MCSS 0x01
|
||||
|
||||
/* Device setting. */
|
||||
struct fw_setting {
|
||||
uint16_t len;
|
||||
uint8_t key_type;
|
||||
uint8_t key_len;
|
||||
uint8_t val_type;
|
||||
uint8_t val_len;
|
||||
char data[];
|
||||
} __packed;
|
||||
|
||||
#define FW_SETTING_KEYTYPE_ASCII 0x00
|
||||
#define FW_SETTING_VALTYPE_ASCII 0x00
|
||||
#define FW_SETTING_VALTYPE_UINT 0x01
|
||||
|
||||
/* Device settings list. */
|
||||
struct fw_setlist {
|
||||
uint16_t len;
|
||||
char data[];
|
||||
} __packed;
|
||||
|
||||
/* Device entry header. */
|
||||
struct fw_dehdr {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t seq;
|
||||
} __packed;
|
||||
|
||||
#define FW_DE_HDR_TYPE_DASD 0x0001
|
||||
#define FW_DE_HDR_TYPE_ZFCP_HOST 0x0002
|
||||
#define FW_DE_HDR_TYPE_ZFCP_LUN 0x0003
|
||||
#define FW_DE_HDR_TYPE_QETH 0x0004
|
||||
|
||||
/* DASD device entry. */
|
||||
struct fw_dasd {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid id;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* zFCP host device entry. */
|
||||
struct fw_zfcp_host {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid id;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* zFCP LUN device entry. */
|
||||
struct fw_zfcp_lun {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid id;
|
||||
uint64_t wwpn;
|
||||
uint64_t fcp_lun;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* QETH device entry. */
|
||||
struct fw_qeth {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid read_id;
|
||||
struct fw_iodevid write_id;
|
||||
struct fw_iodevid data_id;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* Emit a warning that refers to a position in a firmware file. */
|
||||
static void fwwarn(struct fw_file *f, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
off_t start = (off_t) (f->last_access - f->buffer),
|
||||
end = start + f->last_size - 1;
|
||||
|
||||
fprintf(stderr, "%s: ", f->name);
|
||||
if (start == end)
|
||||
fprintf(stderr, "Byte 0x%zx: ", start);
|
||||
else
|
||||
fprintf(stderr, "Bytes 0x%zx-0x%zx: ", start, end);
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* Basic file format header sanity check. */
|
||||
static bool check_header(struct fw_file *f, struct fw_filehdr *hdr)
|
||||
{
|
||||
if (fwacc(f, hdr->magic) != FW_HDR_MAGIC)
|
||||
fwwarn(f, "Invalid file magic (0x%08x)", hdr->magic);
|
||||
else if (fwacc(f, hdr->ver) != FW_HDR_VER_Z14)
|
||||
fwwarn(f, "Unsupported file version (0x%04x)", hdr->ver);
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define READ_RETRY 3
|
||||
|
||||
/* Read a firmware configuration file. */
|
||||
static exit_code_t read_fw(struct fw_file *file, FILE *fd, const char *filename)
|
||||
{
|
||||
struct fw_file f = { NULL };
|
||||
struct fw_filehdr *hdr;
|
||||
char *buffer, *buffer2;
|
||||
size_t size, size2;
|
||||
int retry;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
for (retry = 0; retry < READ_RETRY; retry++) {
|
||||
/* Read complete file once */
|
||||
rc = misc_read_fd(fd, (void **) &buffer, &size);
|
||||
if (rc) {
|
||||
warn("%s: Could not read file", filename);
|
||||
return rc;
|
||||
}
|
||||
if (!buffer) {
|
||||
/* Empty file - skip silently as this is the default
|
||||
* on machines without firmware support. */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Re-read complete file to detect in-flight modifications. */
|
||||
if (fseek(fd, 0, SEEK_SET) == -1) {
|
||||
/* Could be a pipe, socket, or FIFO - accept v1. */
|
||||
break;
|
||||
}
|
||||
rc = misc_read_fd(fd, (void **) &buffer2, &size2);
|
||||
if (rc || !buffer2) {
|
||||
/* Could not get second version - accept v1. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == size2 && memcmp(buffer, buffer2, size) == 0) {
|
||||
/* No change */
|
||||
free(buffer2);
|
||||
break;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
}
|
||||
|
||||
if (retry >= READ_RETRY) {
|
||||
warnx("%s: File changed %d times while reading - aborting",
|
||||
filename, retry);
|
||||
return EXIT_RUNTIME_ERROR;
|
||||
}
|
||||
|
||||
/* Perform basic checks */
|
||||
f.name = filename;
|
||||
f.buffer = buffer;
|
||||
f.size = size;
|
||||
hdr = (void *) buffer;
|
||||
if (!check_header(&f, hdr)) {
|
||||
free(buffer);
|
||||
return EXIT_FORMAT_ERROR;
|
||||
}
|
||||
if (fwacc(&f, hdr->file_len) > size) {
|
||||
fwwarn(&f, "File length mismatch (expect %zu) - adjusting",
|
||||
size);
|
||||
hdr->file_len = size;
|
||||
}
|
||||
|
||||
*file = f;
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
/* Return textual representation of a device entry type. */
|
||||
static const char *type_to_str(uint16_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case FW_DE_HDR_TYPE_DASD:
|
||||
return "dasd";
|
||||
case FW_DE_HDR_TYPE_ZFCP_HOST:
|
||||
return "zfcp-host";
|
||||
case FW_DE_HDR_TYPE_ZFCP_LUN:
|
||||
return "zfcp-lun";
|
||||
case FW_DE_HDR_TYPE_QETH:
|
||||
return "qeth";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a binary format device setting of the specified length to integer. */
|
||||
static unsigned long parse_value(char *data, uint8_t len)
|
||||
{
|
||||
switch (len) {
|
||||
case 1:
|
||||
return (unsigned long) *((uint8_t *) data);
|
||||
case 2:
|
||||
return (unsigned long) *((uint16_t *) data);
|
||||
case 4:
|
||||
return (unsigned long) *((uint32_t *) data);
|
||||
case 8:
|
||||
return (unsigned long) *((uint64_t *) data);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform sanity checks on device setting. */
|
||||
static bool check_setting(struct fw_file *f, struct fw_setting *set)
|
||||
{
|
||||
/* Key sanity checks */
|
||||
if (fwacc(f, set->key_type) != FW_SETTING_KEYTYPE_ASCII) {
|
||||
fwwarn(f, "Unsupported key type: %d", set->key_type);
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, set->key_len) < 1) {
|
||||
fwwarn(f, "Unsupported key length: %d", set->key_len);
|
||||
return false;
|
||||
}
|
||||
if (sizeof(struct fw_setting) + fwacc(f, set->key_len) > set->len) {
|
||||
fwwarn(f, "Key length exceeds setting");
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, set->data[set->key_len - 1])) {
|
||||
fwwarn(f, "Key not null-terminated");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Value sanity checks */
|
||||
if (fwacc(f, set->val_type) != FW_SETTING_VALTYPE_UINT &&
|
||||
fwacc(f, set->val_type) != FW_SETTING_VALTYPE_ASCII) {
|
||||
fwwarn(f, "Unsupported value type: %d", set->val_type);
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, set->val_len) < 1) {
|
||||
fwwarn(f, "Unsupported value length: %d", set->val_len);
|
||||
return false;
|
||||
}
|
||||
if (sizeof(struct fw_setting) + set->key_len +
|
||||
fwacc(f, set->val_len) > set->len) {
|
||||
fwwarn(f, "Value length exceeds setting");
|
||||
return false;
|
||||
}
|
||||
if ((set->val_type == FW_SETTING_VALTYPE_ASCII) &&
|
||||
fwacc(f, set->data[set->key_len + set->val_len - 1])) {
|
||||
fwwarn(f, "Value not null-terminated");
|
||||
return false;
|
||||
}
|
||||
if (set->val_type == FW_SETTING_VALTYPE_UINT) {
|
||||
switch (fwacc(f, set->val_len)) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
fwwarn(f, "Unsupported integer value length: %d",
|
||||
set->val_len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Add a setting to the device. Emit a warning if the setting is not known. */
|
||||
static void _add_setting(const char *filename, struct device *dev,
|
||||
config_t config, const char *key, const char *value)
|
||||
{
|
||||
struct attrib *a;
|
||||
struct setting_list *list;
|
||||
|
||||
list = device_get_setting_list(dev, config);
|
||||
a = attrib_find(dev->subtype->dev_attribs, key);
|
||||
if (!a) {
|
||||
warnx("%s: Applying unknown device setting %s=%s", filename,
|
||||
key, value);
|
||||
}
|
||||
setting_list_apply(list, a, key, value);
|
||||
}
|
||||
|
||||
static void add_setting(const char *filename, struct device *dev,
|
||||
config_t config, const char *key, const char *value)
|
||||
{
|
||||
if (SCOPE_ACTIVE(config))
|
||||
_add_setting(filename, dev, config_active, key, value);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
_add_setting(filename, dev, config_persistent, key, value);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
_add_setting(filename, dev, config_autoconf, key, value);
|
||||
}
|
||||
|
||||
/* Parse a single device setting in firmware format and apply it to the
|
||||
* specified device. */
|
||||
static void parse_setting(struct fw_file *f, struct fw_setting *set,
|
||||
struct device *dev, config_t config)
|
||||
{
|
||||
char *ascii_key, *ascii_val;
|
||||
unsigned long ulong_val;
|
||||
|
||||
if (!check_setting(f, set))
|
||||
return;
|
||||
|
||||
ascii_key = &set->data[0];
|
||||
if (set->val_type == FW_SETTING_VALTYPE_UINT) {
|
||||
ulong_val = parse_value(&set->data[set->key_len], set->val_len);
|
||||
ascii_val = misc_asprintf("%lu", ulong_val);
|
||||
add_setting(f->name, dev, config, ascii_key, ascii_val);
|
||||
free(ascii_val);
|
||||
} else {
|
||||
ascii_val = &set->data[set->key_len];
|
||||
add_setting(f->name, dev, config, ascii_key, ascii_val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a device settings list in firmware format and apply the resulting
|
||||
* settings to the specified device. */
|
||||
static void parse_settings(struct fw_file *f, char *data, struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
struct fw_setlist *list = (struct fw_setlist *) data;
|
||||
struct fw_setting *set;
|
||||
uint16_t off;
|
||||
|
||||
for (off = sizeof(struct fw_setlist); off < list->len;
|
||||
off += set->len) {
|
||||
set = (struct fw_setting *) &data[off];
|
||||
if (fwacc(f, set->len) < sizeof(struct fw_setting)) {
|
||||
fwwarn(f, "Setting too short");
|
||||
break;
|
||||
}
|
||||
if (off + fwacc(f, set->len) > list->len) {
|
||||
fwwarn(f, "Setting too long");
|
||||
break;
|
||||
}
|
||||
parse_setting(f, set, dev, config);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform sanity checks on an I/O device ID. */
|
||||
static bool check_iodevid(struct fw_file *f, uint8_t *flags,
|
||||
struct fw_iodevid *id)
|
||||
{
|
||||
|
||||
if (fwacc(f, *flags) & FW_IODEVID_FLAG_MCSS) {
|
||||
fwwarn(f, "Unsupported entry in non-default CSS");
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, id->cssid) != 0) {
|
||||
fwwarn(f, "Non-zero CSS-ID");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Perform sanity checks on a device entry. */
|
||||
static bool check_de_size(struct fw_file *f, struct fw_dehdr *de, size_t size)
|
||||
{
|
||||
if (fwacc(f, de->len) < size) {
|
||||
fwwarn(f, "Device entry too short (expect %zu)", size);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert an I/O device ID to CCW device ID format. */
|
||||
static void io_to_ccw(struct ccw_devid *c, struct fw_iodevid *i)
|
||||
{
|
||||
c->cssid = i->cssid;
|
||||
c->ssid = i->ssid;
|
||||
c->devno = i->devno;
|
||||
}
|
||||
|
||||
/* Register a new device configuration. */
|
||||
static struct device *add_device(struct fw_file *f, struct subtype *st,
|
||||
const char *id, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (!st->devices)
|
||||
st->devices = device_list_new(st);
|
||||
|
||||
dev = device_list_find(st->devices, id, NULL);
|
||||
if (!dev) {
|
||||
dev = device_new(st, id);
|
||||
if (!dev) {
|
||||
warnx("%s: Skipping invalid %s device ID %s", f->name,
|
||||
st->name, id);
|
||||
return NULL;
|
||||
}
|
||||
device_list_add(st->devices, dev);
|
||||
}
|
||||
ptrlist_add(objects, object_new(export_device, dev));
|
||||
|
||||
/* Prepare device for new settings. */
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
setting_list_clear(dev->active.settings);
|
||||
if (dev->subtype->support_definable)
|
||||
dev->active.definable = 1;
|
||||
else
|
||||
dev->active.exists = 1;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
setting_list_clear(dev->persistent.settings);
|
||||
dev->persistent.exists = 1;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
setting_list_clear(dev->autoconf.settings);
|
||||
dev->autoconf.exists = 1;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* Parse a DASD device entry. */
|
||||
static void parse_dasd(struct fw_file *f, struct fw_dehdr *de, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
struct fw_dasd *dasd = (struct fw_dasd *) de;
|
||||
struct ccw_devid devid;
|
||||
struct device *dev_eckd, *dev_fba;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_dasd)))
|
||||
return;
|
||||
if (!check_iodevid(f, &dasd->id_flags, &dasd->id))
|
||||
return;
|
||||
|
||||
/* Could be either dasd_eckd or dasd_fba - add both entries */
|
||||
io_to_ccw(&devid, &dasd->id);
|
||||
id = ccw_devid_to_str(&devid);
|
||||
dev_eckd = add_device(f, &dasd_subtype_eckd, id, config, objects);
|
||||
dev_fba = add_device(f, &dasd_subtype_fba, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dasd->hdr.len > sizeof(struct fw_dasd)) {
|
||||
if (dev_eckd)
|
||||
parse_settings(f, dasd->settings, dev_eckd, config);
|
||||
if (dev_fba)
|
||||
parse_settings(f, dasd->settings, dev_fba, config);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a zFCP host device entry. */
|
||||
static void parse_zfcp_host(struct fw_file *f, struct fw_dehdr *de,
|
||||
config_t config, struct util_list *objects)
|
||||
{
|
||||
struct fw_zfcp_host *zfcp_host = (struct fw_zfcp_host *) de;
|
||||
struct ccw_devid devid;
|
||||
struct device *dev;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_zfcp_host)))
|
||||
return;
|
||||
if (!check_iodevid(f, &zfcp_host->id_flags, &zfcp_host->id))
|
||||
return;
|
||||
|
||||
/* Add zfcp_host entry */
|
||||
io_to_ccw(&devid, &zfcp_host->id);
|
||||
id = ccw_devid_to_str(&devid);
|
||||
dev = add_device(f, &zfcp_host_subtype, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dev && zfcp_host->hdr.len > sizeof(struct fw_zfcp_host))
|
||||
parse_settings(f, zfcp_host->settings, dev, config);
|
||||
}
|
||||
|
||||
/* Parse a zFCP LUN device entry. */
|
||||
static void parse_zfcp_lun(struct fw_file *f, struct fw_dehdr *de,
|
||||
config_t config, struct util_list *objects)
|
||||
{
|
||||
struct fw_zfcp_lun *zfcp_lun = (struct fw_zfcp_lun *) de;
|
||||
struct zfcp_lun_devid devid;
|
||||
struct device *dev;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_zfcp_lun)))
|
||||
return;
|
||||
if (!check_iodevid(f, &zfcp_lun->id_flags, &zfcp_lun->id))
|
||||
return;
|
||||
|
||||
/* Add zfcp_lun entry */
|
||||
io_to_ccw(&devid.fcp_dev, &zfcp_lun->id);
|
||||
devid.wwpn = zfcp_lun->wwpn;
|
||||
devid.lun = zfcp_lun->fcp_lun;
|
||||
id = zfcp_lun_devid_to_str(&devid);
|
||||
dev = add_device(f, &zfcp_lun_subtype, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dev && zfcp_lun->hdr.len > sizeof(struct fw_zfcp_lun))
|
||||
parse_settings(f, zfcp_lun->settings, dev, config);
|
||||
|
||||
}
|
||||
|
||||
/* Parse a QETH device entry. */
|
||||
static void parse_qeth(struct fw_file *f, struct fw_dehdr *de, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
struct fw_qeth *qeth = (struct fw_qeth *) de;
|
||||
struct ccwgroup_devid devid;
|
||||
struct device *dev;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_qeth)))
|
||||
return;
|
||||
if (!check_iodevid(f, &qeth->id_flags, &qeth->read_id) ||
|
||||
!check_iodevid(f, &qeth->id_flags, &qeth->write_id) ||
|
||||
!check_iodevid(f, &qeth->id_flags, &qeth->data_id))
|
||||
return;
|
||||
|
||||
/* Add qeth entry */
|
||||
devid.num = 3;
|
||||
io_to_ccw(&devid.devid[0], &qeth->read_id);
|
||||
io_to_ccw(&devid.devid[1], &qeth->write_id);
|
||||
io_to_ccw(&devid.devid[2], &qeth->data_id);
|
||||
id = ccwgroup_devid_to_str(&devid);
|
||||
dev = add_device(f, &qeth_subtype_qeth, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dev && qeth->hdr.len > sizeof(struct fw_qeth))
|
||||
parse_settings(f, qeth->settings, dev, config);
|
||||
}
|
||||
|
||||
/* Parse a firmware file. */
|
||||
static void parse_fw(struct fw_file *f, long skip, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
char *data = f->buffer;
|
||||
struct fw_filehdr *hdr = (struct fw_filehdr *) data;
|
||||
struct fw_dehdr *de;
|
||||
uint16_t count = 0;
|
||||
uint32_t off;
|
||||
|
||||
for (off = hdr->hdr_len; off < hdr->file_len; off += de->len) {
|
||||
count++;
|
||||
de = (struct fw_dehdr *) &data[off];
|
||||
if (fwacc(f, de->len) == 0) {
|
||||
fwwarn(f, "Empty device entry");
|
||||
break;
|
||||
}
|
||||
if (off + fwacc(f, de->len) > hdr->file_len) {
|
||||
fwwarn(f, "Device entry too long");
|
||||
break;
|
||||
}
|
||||
if (skip >= 0 && de->seq <= skip) {
|
||||
debug("Skipping %s entry due to sequence (%08x)\n",
|
||||
type_to_str(de->type), de->seq);
|
||||
continue;
|
||||
}
|
||||
switch (fwacc(f, de->type)) {
|
||||
case FW_DE_HDR_TYPE_DASD:
|
||||
parse_dasd(f, de, config, objects);
|
||||
break;
|
||||
case FW_DE_HDR_TYPE_ZFCP_HOST:
|
||||
parse_zfcp_host(f, de, config, objects);
|
||||
break;
|
||||
case FW_DE_HDR_TYPE_ZFCP_LUN:
|
||||
parse_zfcp_lun(f, de, config, objects);
|
||||
break;
|
||||
case FW_DE_HDR_TYPE_QETH:
|
||||
parse_qeth(f, de, config, objects);
|
||||
break;
|
||||
default:
|
||||
fwwarn(f, "Unknown entry (type=%04x)", de->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != fwacc(f, hdr->de_count))
|
||||
fwwarn(f, "Device entry count mismatch");
|
||||
}
|
||||
|
||||
/* Read configuration objects from @fd in firmware file format. Add pointers to
|
||||
* newly allocated struct export_objects to ptrlist @objects. If @skip is a
|
||||
* positive number, skip over entries with a sequence number equal to or
|
||||
* greater than @skip. */
|
||||
exit_code_t firmware_read(FILE *fd, const char *filename, long skip,
|
||||
config_t config, struct util_list *objects)
|
||||
{
|
||||
struct fw_file file;
|
||||
exit_code_t rc;
|
||||
|
||||
rc = read_fw(&file, fd, filename);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
parse_fw(&file, skip, config, objects);
|
||||
free(file.buffer);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check if @fd refers to a file in binary firmware format. */
|
||||
bool firmware_detect(FILE *fd)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = fgetc(fd);
|
||||
ungetc(c, fd);
|
||||
|
||||
/* Note: A full check would require looking at least at the first 4
|
||||
* bytes, but fd might be non-seekable (e.g. pipe). Since there is no
|
||||
* way that a textual import file can start with a 'z', looking at
|
||||
* the first char should be enough. */
|
||||
|
||||
return c == 'z';
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "generic_ccw.h"
|
||||
#include "internal.h"
|
||||
#include "namespace.h"
|
||||
#include "path.h"
|
||||
#include "subtype.h"
|
||||
@@ -182,6 +183,7 @@ static struct subtype generic_ccw_subtype = {
|
||||
.dev_attribs = ATTRIB_ARRAY(
|
||||
&ccw_attr_online,
|
||||
&ccw_attr_cmb_enable,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.generic = 1,
|
||||
|
||||
38
zdev/src/internal.c
Normal file
38
zdev/src/internal.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "attrib.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
|
||||
struct attrib internal_attr_early = {
|
||||
.name = INTERNAL_ATTR_EARLY,
|
||||
.title = "Activate device early during boot",
|
||||
.desc = "Control the time of activation of a device:\n"
|
||||
" 0: Device is activated normally during boot\n"
|
||||
" 1: Device is activated early in the boot process, by the\n"
|
||||
" initial RAM-disk\n",
|
||||
.defval = "0",
|
||||
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
|
||||
.internal = 1,
|
||||
};
|
||||
|
||||
/* Return identifier of internal attribute with specified @name. */
|
||||
const char *internal_get_name(const char *name)
|
||||
{
|
||||
return name + sizeof(INTERNAL_ATTR_PREFIX) - 1;
|
||||
}
|
||||
|
||||
/* Check if attribute is internal by name. */
|
||||
bool internal_by_name(const char *name)
|
||||
{
|
||||
return starts_with(name, INTERNAL_ATTR_PREFIX);
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ccwgroup.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "lcs.h"
|
||||
#include "lcs_auto.h"
|
||||
#include "misc.h"
|
||||
@@ -362,6 +363,7 @@ static struct subtype lcs_subtype = {
|
||||
&ccw_attr_online,
|
||||
&lcs_attr_lancmd_timeout,
|
||||
&lcs_attr_recover,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.support_definable = 1,
|
||||
|
||||
@@ -59,6 +59,7 @@ struct options {
|
||||
config_t config;
|
||||
unsigned int active:1;
|
||||
unsigned int persistent:1;
|
||||
unsigned int auto_conf:1;
|
||||
struct util_list *columns; /* List of struct strlist_node */
|
||||
unsigned int no_headings:1;
|
||||
struct util_list *base; /* List of struct strlist_node */
|
||||
@@ -98,6 +99,7 @@ enum {
|
||||
OPT_VERBOSE = 'V',
|
||||
OPT_QUIET = 'q',
|
||||
OPT_PAIRS = 'P',
|
||||
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
};
|
||||
|
||||
static struct opts_conflict conflict_list[] = {
|
||||
@@ -150,6 +152,7 @@ static const struct option opt_list[] = {
|
||||
/* Options. */
|
||||
{ "active", no_argument, NULL, OPT_ACTIVE },
|
||||
{ "persistent", no_argument, NULL, OPT_PERSISTENT },
|
||||
{ "auto-conf", no_argument, NULL, OPT_AUTO_CONF },
|
||||
{ "columns", required_argument, NULL, OPT_COLUMNS },
|
||||
{ "no-headings", no_argument, NULL, OPT_NO_HEADINGS },
|
||||
{ "base", required_argument, NULL, OPT_BASE },
|
||||
@@ -623,6 +626,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->persistent = 1;
|
||||
break;
|
||||
|
||||
case OPT_AUTO_CONF:
|
||||
/* --auto-conf */
|
||||
opts->auto_conf = 1;
|
||||
break;
|
||||
|
||||
case OPT_COLUMNS:
|
||||
/* --columns COLUMN */
|
||||
strlist_add_multi(opts->columns, optarg, ",", 0);
|
||||
@@ -685,7 +693,15 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
goto out;
|
||||
|
||||
/* Determine configuration set. */
|
||||
opts->config = get_config(opts->active, opts->persistent);
|
||||
if (!opts->active && !opts->persistent && !opts->auto_conf) {
|
||||
/* Default display targets are active + persistent - note that
|
||||
* autoconf data is still shown when available to make users
|
||||
* aware of this type of data. */
|
||||
opts->config = config_active | config_persistent;
|
||||
} else {
|
||||
opts->config = get_config(opts->active, opts->persistent,
|
||||
opts->auto_conf);
|
||||
}
|
||||
|
||||
/* Handle positional parameters. */
|
||||
rc = parse_positional(opts, argc, argv, optind);
|
||||
@@ -725,6 +741,7 @@ enum dev_table_id {
|
||||
dev_netdevs,
|
||||
dev_exists,
|
||||
dev_pers,
|
||||
dev_auto,
|
||||
dev_online,
|
||||
dev_failed,
|
||||
dev_modules,
|
||||
@@ -744,6 +761,8 @@ static struct column *dev_table = COLUMN_ARRAY(
|
||||
"Device exists in the active configuration"),
|
||||
COLUMN("PERS", align_left, dev_pers, 1,
|
||||
"Device is configured persistently"),
|
||||
COLUMN("AUTO", align_left, dev_auto, 0,
|
||||
"Auto-configuration exists for device"),
|
||||
COLUMN("FAILED", align_left, dev_failed, 0,
|
||||
"Device is in error"),
|
||||
COLUMN("NAMES", align_left, dev_names, 1,
|
||||
@@ -762,21 +781,34 @@ static struct column *dev_table = COLUMN_ARRAY(
|
||||
"Path to specific attribute in active configuration")
|
||||
);
|
||||
|
||||
static char *merge_str(const char *act, const char *pers)
|
||||
static char *merge_str(const char *act, const char *pers, const char *ac,
|
||||
config_t config)
|
||||
{
|
||||
char *str;
|
||||
size_t len;
|
||||
|
||||
if (act && pers) {
|
||||
if (strcmp(act, pers) == 0)
|
||||
str = misc_strdup(act);
|
||||
else
|
||||
str = misc_asprintf("%s/%s", act, pers);
|
||||
} else if (act)
|
||||
str = misc_strdup(act);
|
||||
else if (pers)
|
||||
str = misc_strdup(pers);
|
||||
else
|
||||
str = misc_strdup("-");
|
||||
act = act ? act : "-";
|
||||
pers = pers ? pers : "-";
|
||||
ac = ac ? ac : "-";
|
||||
|
||||
if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0)
|
||||
return misc_strdup(act);
|
||||
|
||||
len = strlen(act) + strlen(pers) + strlen(ac) + /* 3 * / + NUL */ 4;
|
||||
str = misc_malloc(len);
|
||||
|
||||
if (SCOPE_ACTIVE(config))
|
||||
strcat(str, act);
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
if (*str)
|
||||
strcat(str, "/");
|
||||
strcat(str, pers);
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
if (*str)
|
||||
strcat(str, "/");
|
||||
strcat(str, ac);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -821,10 +853,9 @@ static char *get_attr(struct device *dev, const char *name, config_t config)
|
||||
struct setting_list *list;
|
||||
struct setting *s;
|
||||
|
||||
if (config == config_active)
|
||||
list = dev->active.settings;
|
||||
else
|
||||
list = dev->persistent.settings;
|
||||
list = device_get_setting_list(dev, config);
|
||||
if (!list)
|
||||
return NULL;
|
||||
s = setting_list_find(list, name);
|
||||
if (!s) {
|
||||
if (config == config_active) {
|
||||
@@ -841,7 +872,7 @@ static char *get_attr(struct device *dev, const char *name, config_t config)
|
||||
static char *dev_table_get_attr(struct device *dev, const char *attr,
|
||||
config_t config)
|
||||
{
|
||||
char *act = NULL, *pers = NULL, *str;
|
||||
char *act = NULL, *pers = NULL, *ac = NULL, *str;
|
||||
const char *name;
|
||||
|
||||
name = strchr(attr, ':');
|
||||
@@ -853,10 +884,13 @@ static char *dev_table_get_attr(struct device *dev, const char *attr,
|
||||
act = get_attr(dev, name, config_active);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
pers = get_attr(dev, name, config_persistent);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
ac = get_attr(dev, name, config_autoconf);
|
||||
|
||||
str = merge_str(act, pers);
|
||||
str = merge_str(act, pers, ac, config);
|
||||
free(act);
|
||||
free(pers);
|
||||
free(ac);
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -904,7 +938,11 @@ static char *dev_table_get_value(void *item, int id, const char *heading,
|
||||
return misc_strdup(YESNO(dev->active.exists ||
|
||||
dev->active.definable));
|
||||
case dev_pers:
|
||||
if (!dev->persistent.exists && dev->autoconf.exists)
|
||||
return misc_strdup("auto");
|
||||
return misc_strdup(YESNO(dev->persistent.exists));
|
||||
case dev_auto:
|
||||
return misc_strdup(YESNO(dev->autoconf.exists));
|
||||
case dev_online:
|
||||
return dev_table_get_online(dev, config_active);
|
||||
case dev_failed:
|
||||
@@ -942,6 +980,7 @@ static read_scope_t get_scope(struct options *opts)
|
||||
case dev_netdevs:
|
||||
case dev_exists:
|
||||
case dev_pers:
|
||||
case dev_auto:
|
||||
case dev_online:
|
||||
case dev_modules:
|
||||
continue;
|
||||
@@ -960,14 +999,21 @@ static struct util_list *dev_table_build(struct options *opts,
|
||||
struct util_list *selected, *devices = NULL;
|
||||
struct selected_dev_node *sel;
|
||||
struct device *dev;
|
||||
int active, persistent;
|
||||
int active, persistent, autoconf;
|
||||
read_scope_t scope;
|
||||
exit_code_t rc;
|
||||
config_t config = opts->config;
|
||||
|
||||
scope = get_scope(opts);
|
||||
selected = selected_dev_list_new();
|
||||
|
||||
/* Read auto-config data when no configuration set was specified to
|
||||
* make user aware of auto-config data. */
|
||||
if (!opts->active && !opts->persistent && !opts->auto_conf)
|
||||
config |= config_autoconf;
|
||||
|
||||
rc = select_devices(opts->select, selected, 1, 0, opts->pairs,
|
||||
opts->config, scope, err_print);
|
||||
config, scope, err_print);
|
||||
if (rc)
|
||||
goto out;
|
||||
devices = ptrlist_new();
|
||||
@@ -987,7 +1033,8 @@ static struct util_list *dev_table_build(struct options *opts,
|
||||
/* Only process existing devices. */
|
||||
active = dev->active.exists || dev->active.definable;
|
||||
persistent = dev->persistent.exists;
|
||||
if (!active && !persistent)
|
||||
autoconf = dev->autoconf.exists;
|
||||
if (!active && !persistent && !autoconf)
|
||||
continue;
|
||||
|
||||
ptrlist_add(devices, dev);
|
||||
@@ -1025,9 +1072,11 @@ static exit_code_t do_list_devices(struct options *opts)
|
||||
if (!items)
|
||||
return EXIT_EMPTY_SELECTION;
|
||||
|
||||
/* Adjust columns visible depending on --active and --persistent. */
|
||||
/* Adjust columns visible depending on selected config set. */
|
||||
table_set_default(dev_table, dev_online, SCOPE_ACTIVE(opts->config));
|
||||
table_set_default(dev_table, dev_pers, SCOPE_PERSISTENT(opts->config));
|
||||
table_set_default(dev_table, dev_auto, SCOPE_AUTOCONF(opts->config) &&
|
||||
!SCOPE_PERSISTENT(opts->config));
|
||||
table_set_default(dev_table, dev_names, SCOPE_ACTIVE(opts->config));
|
||||
|
||||
/* Display table. */
|
||||
@@ -1057,17 +1106,20 @@ enum settings_table_id {
|
||||
settings_readonly,
|
||||
settings_active,
|
||||
settings_persistent,
|
||||
settings_autoconf,
|
||||
};
|
||||
|
||||
static struct column *settings_table = COLUMN_ARRAY(
|
||||
COLUMN("ATTRIBUTE", align_left, settings_attribute, 1, ""),
|
||||
COLUMN("READONLY", align_left, settings_readonly, 1, ""),
|
||||
COLUMN("ACTIVE", align_left, settings_active, 1, ""),
|
||||
COLUMN("PERSISTENT", align_left, settings_persistent, 1, "")
|
||||
COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""),
|
||||
COLUMN("AUTOCONF", align_left, settings_autoconf, 0, "")
|
||||
);
|
||||
|
||||
static struct util_list *settings_table_build(struct setting_list *active,
|
||||
struct setting_list *persistent,
|
||||
struct setting_list *autoconf,
|
||||
bool readonly)
|
||||
{
|
||||
struct util_list *names, *items;
|
||||
@@ -1088,6 +1140,10 @@ static struct util_list *settings_table_build(struct setting_list *active,
|
||||
util_list_iterate(&persistent->list, s)
|
||||
strlist_add(names, s->name);
|
||||
}
|
||||
if (autoconf && !readonly) {
|
||||
util_list_iterate(&autoconf->list, s)
|
||||
strlist_add(names, s->name);
|
||||
}
|
||||
strlist_sort_unique(names, str_cmp);
|
||||
|
||||
/* Convert strlist to ptrlist. */
|
||||
@@ -1102,6 +1158,7 @@ static struct util_list *settings_table_build(struct setting_list *active,
|
||||
struct settings_table_data {
|
||||
struct setting_list *active;
|
||||
struct setting_list *persistent;
|
||||
struct setting_list *autoconf;
|
||||
int pairs;
|
||||
bool readonly;
|
||||
};
|
||||
@@ -1124,12 +1181,17 @@ static char *settings_table_get_value(void *item, int id, const char *heading,
|
||||
case settings_persistent:
|
||||
list = stdata->persistent;
|
||||
break;
|
||||
case settings_autoconf:
|
||||
list = stdata->autoconf;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (list) {
|
||||
s = setting_list_find(list, name);
|
||||
if (s && !(id == settings_persistent && s->derived)) {
|
||||
if (s &&
|
||||
!((id == settings_persistent || id == settings_autoconf) &&
|
||||
s->derived)) {
|
||||
if (stdata->pairs)
|
||||
return misc_strdup(s->value);
|
||||
else
|
||||
@@ -1145,6 +1207,7 @@ static char *settings_table_get_value(void *item, int id, const char *heading,
|
||||
|
||||
static void settings_table_print(struct setting_list *active,
|
||||
struct setting_list *persistent,
|
||||
struct setting_list *autoconf,
|
||||
struct options *opts, int ind, bool readonly,
|
||||
bool neednl)
|
||||
{
|
||||
@@ -1154,7 +1217,7 @@ static void settings_table_print(struct setting_list *active,
|
||||
items = settings_table_build(
|
||||
SCOPE_ACTIVE(opts->config) ? active : NULL,
|
||||
SCOPE_PERSISTENT(opts->config) ? persistent : NULL,
|
||||
readonly);
|
||||
autoconf, readonly);
|
||||
if (util_list_is_empty(items)) {
|
||||
if (!opts->pairs && !readonly)
|
||||
indent(ind, "%sNo settings found\n",
|
||||
@@ -1170,8 +1233,12 @@ static void settings_table_print(struct setting_list *active,
|
||||
SCOPE_ACTIVE(opts->config));
|
||||
table_set_default(settings_table, settings_persistent,
|
||||
SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0);
|
||||
table_set_default(settings_table, settings_autoconf,
|
||||
(SCOPE_AUTOCONF(opts->config) || autoconf) &&
|
||||
!readonly ? 1 : 0);
|
||||
data.active = active;
|
||||
data.persistent = persistent;
|
||||
data.autoconf = autoconf;
|
||||
data.pairs = opts->pairs;
|
||||
table_print(settings_table, settings_table_get_value, &data, items,
|
||||
NULL, 1, opts->pairs, ind, 0);
|
||||
@@ -1253,7 +1320,7 @@ static exit_code_t do_info_type(struct options *opts)
|
||||
}
|
||||
} else {
|
||||
settings_table_print(dt->active_settings,
|
||||
dt->persistent_settings, opts,
|
||||
dt->persistent_settings, NULL, opts,
|
||||
INFO_INDENT, false, false);
|
||||
}
|
||||
|
||||
@@ -1280,7 +1347,7 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key;
|
||||
const char *id, *type, *exists, *persist, *prefix;
|
||||
const char *id, *type, *exists, *persist, *ac, *prefix;
|
||||
struct util_list *resources, *errors;
|
||||
struct strlist_node *s;
|
||||
bool first;
|
||||
@@ -1299,6 +1366,7 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
||||
errors = subtype_get_errors(dev->subtype, dev->id);
|
||||
exists = YESNO(dev->active.exists || dev->active.definable);
|
||||
persist = YESNO(dev->persistent.exists);
|
||||
ac = YESNO(dev->autoconf.exists);
|
||||
|
||||
/* Print information. */
|
||||
if (opts->pairs) {
|
||||
@@ -1316,6 +1384,8 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
||||
print_pair("ONLINE", online);
|
||||
print_pair("EXISTS", exists);
|
||||
print_pair("PERSISTENT", persist);
|
||||
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
|
||||
print_pair("AUTOCONF", ac);
|
||||
if (errors) {
|
||||
util_list_iterate(errors, s)
|
||||
print_pair("ERROR", s->str);
|
||||
@@ -1341,6 +1411,8 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
||||
print_info("Online", online);
|
||||
print_info("Exists", exists);
|
||||
print_info("Persistent", persist);
|
||||
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
|
||||
print_info("Auto-configured", ac);
|
||||
if (errors) {
|
||||
first = true;
|
||||
util_list_iterate(errors, s) {
|
||||
@@ -1382,11 +1454,17 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
||||
|
||||
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
|
||||
dev->persistent.exists ? dev->persistent.settings :
|
||||
NULL, opts, INFO_INDENT, false, !opts->pairs);
|
||||
NULL,
|
||||
dev->autoconf.exists ? dev->autoconf.settings :
|
||||
NULL,
|
||||
opts, INFO_INDENT, false, !opts->pairs);
|
||||
|
||||
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
|
||||
dev->persistent.exists ? dev->persistent.settings :
|
||||
NULL, opts, INFO_INDENT, true, !opts->pairs);
|
||||
NULL,
|
||||
dev->autoconf.exists ? dev->autoconf.settings :
|
||||
NULL,
|
||||
opts, INFO_INDENT, true, !opts->pairs);
|
||||
|
||||
strlist_free(errors);
|
||||
free(online);
|
||||
@@ -1404,9 +1482,10 @@ static exit_code_t do_info_devices(struct options *opts)
|
||||
struct util_list *selected;
|
||||
struct selected_dev_node *sel;
|
||||
struct device *dev;
|
||||
int found, active, persistent;
|
||||
int found, active, persistent, autoconf;
|
||||
exit_code_t rc, drc = EXIT_OK;
|
||||
read_scope_t scope;
|
||||
config_t config = opts->config;
|
||||
|
||||
if (opts->info > 1)
|
||||
scope = scope_all;
|
||||
@@ -1415,7 +1494,13 @@ static exit_code_t do_info_devices(struct options *opts)
|
||||
|
||||
/* Get list of selected devices. */
|
||||
selected = selected_dev_list_new();
|
||||
select_devices(opts->select, selected, 1, 0, opts->pairs, opts->config,
|
||||
|
||||
/* Read auto-config data when no configuration set was specified to
|
||||
* make user aware of auto-config data. */
|
||||
if (!opts->active && !opts->persistent && !opts->auto_conf)
|
||||
config |= config_autoconf;
|
||||
|
||||
select_devices(opts->select, selected, 1, 0, opts->pairs, config,
|
||||
scope, err_print);
|
||||
|
||||
/* Process selected devices. */
|
||||
@@ -1434,9 +1519,8 @@ static exit_code_t do_info_devices(struct options *opts)
|
||||
/* Only process existing devices. */
|
||||
active = dev->active.exists || dev->active.definable;
|
||||
persistent = dev->persistent.exists;
|
||||
if ((opts->config == config_active && !active) ||
|
||||
(opts->config == config_persistent && !persistent) ||
|
||||
(opts->config == config_all && !active && !persistent))
|
||||
autoconf = dev->autoconf.exists;
|
||||
if (!active && !persistent && !autoconf)
|
||||
continue;
|
||||
if (found > 0)
|
||||
printf("\n");
|
||||
|
||||
@@ -41,5 +41,6 @@ OPTIONS
|
||||
-n, --no-headings Do not print column headings
|
||||
--base PATH Use PATH as base for accessing files
|
||||
--pairs Produce output in KEY="VALUE" format
|
||||
--auto-conf Only show auto-configuration data
|
||||
-V, --verbose Print additional run-time information
|
||||
-q, --quiet Print only minimal run-time information
|
||||
|
||||
@@ -98,26 +98,47 @@ static void dryrun_end_data(void)
|
||||
|
||||
#define READ_CHUNK_SIZE 4096
|
||||
|
||||
/* Read text from @fd and return resulting NULL-terminated text buffer.
|
||||
* If @chomp is non-zero, remove trailing newline character. Return %NULL
|
||||
* on error or when unprintable characters are read. */
|
||||
static char *read_fd(FILE *fd, int chomp)
|
||||
/* Read all data from @fd and return address of resulting buffer in
|
||||
* @buffer_ptr. If @size_ptr is non-zero, use it to store the size of the
|
||||
* resulting buffer. Return %EXIT_OK on success. */
|
||||
exit_code_t misc_read_fd(FILE *fd, void **buffer_ptr, size_t *size_ptr)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
size_t done, i;
|
||||
size_t done = 0;
|
||||
|
||||
done = 0;
|
||||
while (!feof(fd)) {
|
||||
buffer = realloc(buffer, done + READ_CHUNK_SIZE + 1);
|
||||
buffer = realloc(buffer, done + READ_CHUNK_SIZE);
|
||||
if (!buffer)
|
||||
oom();
|
||||
done += fread(&buffer[done], 1, READ_CHUNK_SIZE, fd);
|
||||
if (ferror(fd)) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
return EXIT_RUNTIME_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
buffer = realloc(buffer, done);
|
||||
if (!buffer && done > 0)
|
||||
oom();
|
||||
|
||||
*buffer_ptr = buffer;
|
||||
if (size_ptr)
|
||||
*size_ptr = done;
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
/* Read text from @fd and return resulting NULL-terminated text buffer.
|
||||
* If @chomp is non-zero, remove trailing newline character. Return %NULL
|
||||
* on error or when unprintable characters are read. */
|
||||
static char *read_fd(FILE *fd, int chomp)
|
||||
{
|
||||
char *buffer;
|
||||
size_t done, i;
|
||||
|
||||
if (misc_read_fd(fd, (void **) &buffer, &done))
|
||||
return NULL;
|
||||
|
||||
/* Check if this is a text file at all (required to filter out
|
||||
* binary sysfs attributes). */
|
||||
for (i = 0; i < done; i++) {
|
||||
@@ -131,12 +152,13 @@ static char *read_fd(FILE *fd, int chomp)
|
||||
if (chomp && done > 0 && buffer[done - 1] == '\n')
|
||||
done--;
|
||||
|
||||
if (buffer) {
|
||||
/* NULL-terminate. */
|
||||
buffer[done++] = 0;
|
||||
}
|
||||
/* NULL-terminate. */
|
||||
buffer = realloc(buffer, done + 1);
|
||||
if (!buffer)
|
||||
oom();
|
||||
buffer[done] = 0;
|
||||
|
||||
return realloc(buffer, done);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int count_newline(const char *str)
|
||||
@@ -1085,14 +1107,18 @@ char *misc_readlink(const char *path)
|
||||
}
|
||||
|
||||
/* Determine configuration set. */
|
||||
config_t get_config(int active, int persistent)
|
||||
config_t get_config(int active, int persistent, int autoconf)
|
||||
{
|
||||
if ((!active && !persistent) || (active && persistent))
|
||||
return config_all;
|
||||
else if (active)
|
||||
return config_active;
|
||||
else
|
||||
return config_persistent;
|
||||
config_t config = 0;
|
||||
|
||||
if (active)
|
||||
config |= config_active;
|
||||
if (persistent)
|
||||
config |= config_persistent;
|
||||
if (autoconf)
|
||||
config |= config_autoconf;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/* Determine if program is running under z/VM. */
|
||||
@@ -1226,11 +1252,12 @@ const char *config_to_str(config_t config)
|
||||
return "active";
|
||||
case config_persistent:
|
||||
return "persistent";
|
||||
case config_autoconf:
|
||||
return "autoconf";
|
||||
case config_all:
|
||||
return "all";
|
||||
}
|
||||
/* Should not happen. */
|
||||
return "";
|
||||
return "multiple";
|
||||
}
|
||||
|
||||
/* Convert textual config representation to config_t. */
|
||||
@@ -1240,6 +1267,8 @@ bool str_to_config(const char *str, config_t *config_ptr)
|
||||
*config_ptr = config_active;
|
||||
else if (strcasecmp(str, "persistent") == 0)
|
||||
*config_ptr = config_persistent;
|
||||
else if (strcasecmp(str, "autoconf") == 0)
|
||||
*config_ptr = config_autoconf;
|
||||
else if (strcasecmp(str, "all") == 0)
|
||||
*config_ptr = config_all;
|
||||
else
|
||||
@@ -1688,3 +1717,18 @@ void debug_init(int argc, char *argv[])
|
||||
fprintf(stderr, "%s\"%s\"", i > 0 ? ", " : "", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* Return the last occurrence of @needle in @haystack, or %NULL if @needle
|
||||
* was not found. */
|
||||
char *misc_strrstr(const char *haystack, const char *needle)
|
||||
{
|
||||
char *result, *next;
|
||||
|
||||
result = strstr(haystack, needle);
|
||||
if (result) {
|
||||
while ((next = strstr(result + 1, needle)))
|
||||
result = next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -297,21 +297,25 @@ char *path_get_ccwgroup_devices(const char *drv)
|
||||
}
|
||||
|
||||
/* Return path to udev rule. */
|
||||
char *path_get_udev_rule(const char *type, const char *id)
|
||||
char *path_get_udev_rule(const char *type, const char *id, bool vol)
|
||||
{
|
||||
const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES;
|
||||
|
||||
if (id) {
|
||||
return path_get("%s/%s-%s-%s%s", PATH_UDEV_RULES,
|
||||
return path_get("%s/%s-%s-%s%s", path,
|
||||
UDEV_PREFIX, type, id, UDEV_SUFFIX);
|
||||
}
|
||||
|
||||
return path_get("%s/%s-%s%s", PATH_UDEV_RULES,
|
||||
return path_get("%s/%s-%s%s", path,
|
||||
UDEV_PREFIX, type, UDEV_SUFFIX);
|
||||
}
|
||||
|
||||
/* Return path to directory containing all udev rules. */
|
||||
char *path_get_udev_rules(void)
|
||||
char *path_get_udev_rules(bool vol)
|
||||
{
|
||||
return path_get("%s", PATH_UDEV_RULES);
|
||||
const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES;
|
||||
|
||||
return path_get("%s", path);
|
||||
}
|
||||
|
||||
/* Return path to the specified file in the proc file system. */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ccwgroup.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "nic.h"
|
||||
@@ -1207,7 +1208,7 @@ static exit_code_t check_layer2(struct device *dev, config_t config)
|
||||
{
|
||||
struct setting *l;
|
||||
int layer2_detected, layer2_active = -1, layer2_persistent = -1,
|
||||
layer2_modified = 0;
|
||||
layer2_autoconf = -1, layer2_modified = 0;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
layer2_detected = detect_layer2(dev);
|
||||
@@ -1231,13 +1232,25 @@ static exit_code_t check_layer2(struct device *dev, config_t config)
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
l = setting_list_find(dev->autoconf.settings, qeth_attr_layer2.name);
|
||||
if (l) {
|
||||
layer2_autoconf = atoi(l->value);
|
||||
layer2_modified |= l->modified;
|
||||
} else if (SCOPE_AUTOCONF(config)) {
|
||||
rc = generate_layer2("autoconf", dev->autoconf.settings,
|
||||
&layer2_autoconf, &layer2_modified);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check correct layer2 setting. */
|
||||
if (layer2_detected != -1) {
|
||||
if ((SCOPE_ACTIVE(config) && layer2_active != -1 &&
|
||||
layer2_active != layer2_detected) ||
|
||||
(SCOPE_PERSISTENT(config) && layer2_persistent != -1 &&
|
||||
layer2_persistent != layer2_detected)) {
|
||||
layer2_persistent != layer2_detected) ||
|
||||
(SCOPE_AUTOCONF(config) && layer2_autoconf != -1 &&
|
||||
layer2_autoconf != layer2_detected)) {
|
||||
rc = layer2_mismatch(layer2_detected, layer2_modified);
|
||||
if (rc)
|
||||
goto out;
|
||||
@@ -1256,14 +1269,25 @@ static exit_code_t check_layer2(struct device *dev, config_t config)
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = check_ineffective_settings(dev->autoconf.settings,
|
||||
layer2_autoconf);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
/* check for conflicting layer2 attribute groups */
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = check_conflicting_settings(dev->active.settings);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = check_conflicting_settings(dev->persistent.settings);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
rc = check_conflicting_settings(dev->autoconf.settings);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
@@ -1277,7 +1301,8 @@ static exit_code_t qeth_st_check_pre_configure(struct subtype *st,
|
||||
|
||||
/* No need to check if device is deconfigured. */
|
||||
if ((SCOPE_ACTIVE(config) && dev->active.deconfigured) ||
|
||||
(SCOPE_PERSISTENT(config) && dev->persistent.deconfigured))
|
||||
(SCOPE_PERSISTENT(config) && dev->persistent.deconfigured) ||
|
||||
(SCOPE_AUTOCONF(config) && dev->autoconf.deconfigured))
|
||||
return EXIT_OK;
|
||||
|
||||
rc = check_layer2(dev, config);
|
||||
@@ -1369,7 +1394,7 @@ static struct ccwgroup_subtype_data qeth_data = {
|
||||
.num_devs = QETH_NUM_DEVS,
|
||||
};
|
||||
|
||||
static struct subtype qeth_subtype_qeth = {
|
||||
struct subtype qeth_subtype_qeth = {
|
||||
.super = &ccwgroup_subtype,
|
||||
.devtype = &qeth_devtype,
|
||||
.name = "qeth",
|
||||
@@ -1421,6 +1446,7 @@ static struct subtype qeth_subtype_qeth = {
|
||||
&qeth_attr_vnicc_takeover_learning,
|
||||
&qeth_attr_vnicc_bridge_invisible,
|
||||
&qeth_attr_vnicc_rx_bcast,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.support_definable = 1,
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/util_path.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "root.h"
|
||||
@@ -20,31 +22,78 @@
|
||||
#include "setting.h"
|
||||
#include "subtype.h"
|
||||
|
||||
/* Determine if the root device was modified. If it was modified, run the
|
||||
* corresponding root-install scripts. */
|
||||
static bool is_early_removed(struct device *dev)
|
||||
{
|
||||
struct setting *s;
|
||||
|
||||
s = setting_list_find(dev->persistent.settings,
|
||||
internal_attr_early.name);
|
||||
if (!s || !s->modified)
|
||||
return false;
|
||||
if (!s->actual_value || strcmp(s->actual_value, "1") != 0)
|
||||
return false;
|
||||
if (s->removed || strcmp(s->value, "0") == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void add_early_removed(struct util_list *selected)
|
||||
{
|
||||
int i, j;
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
struct device *dev;
|
||||
|
||||
for (i = 0; devtypes[i]; i++) {
|
||||
dt = devtypes[i];
|
||||
for (j = 0; dt->subtypes[j]; j++) {
|
||||
st = dt->subtypes[j];
|
||||
util_list_iterate(&st->devices->hash.list, dev) {
|
||||
if (is_early_removed(dev)) {
|
||||
selected_dev_list_add(selected, dt, st,
|
||||
dev->id, NULL, EXIT_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
|
||||
* scripts if available. */
|
||||
exit_code_t root_check(void)
|
||||
{
|
||||
struct util_list *selected, *params, *mod = NULL;
|
||||
struct selected_dev_node *sel;
|
||||
struct device *dev;
|
||||
char *params_str;
|
||||
exit_code_t rc;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
struct strlist_node *s;
|
||||
struct devtype *dt;
|
||||
struct select_opts *select;
|
||||
|
||||
debug("Checking for modified root device configuration\n");
|
||||
debug("Checking for required initial RAM-disk update\n");
|
||||
|
||||
/* Get list of devices that provide the root device. */
|
||||
/* Get list of devices that provide the root device or require
|
||||
* early configuration. */
|
||||
selected = selected_dev_list_new();
|
||||
rc = select_by_path(NULL, selected, config_active, scope_mandatory,
|
||||
NULL, NULL, PATH_ROOT, err_ignore);
|
||||
if (rc) {
|
||||
/* First add devices that had zdev:early removed or changed to 0.
|
||||
* The subsequent call to select_devices() will filter out any
|
||||
* duplicates. */
|
||||
add_early_removed(selected);
|
||||
/* Now add devices required for root file system. */
|
||||
if (select_by_path(NULL, selected, config_active, scope_mandatory,
|
||||
NULL, NULL, PATH_ROOT, err_ignore)) {
|
||||
/* Running from an unknown root device is not an error. */
|
||||
verb("Note: Could not determine if root device configuration "
|
||||
"needs to be updated\n");
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
/* Finally add devices with zdev:early=1. */
|
||||
select = select_opts_new();
|
||||
strlist_add(&select->by_attr, "%s=1", INTERNAL_ATTR_EARLY);
|
||||
select_devices(select, selected, 1, 0, 0,
|
||||
config_active | config_persistent, scope_mandatory,
|
||||
err_ignore);
|
||||
select_opts_free(select);
|
||||
|
||||
/* Determine if any of the devices or device types has been modified. */
|
||||
mod = strlist_new();
|
||||
@@ -60,7 +109,7 @@ exit_code_t root_check(void)
|
||||
/* Check devices. */
|
||||
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
||||
if (dev && dev->persistent.exists &&
|
||||
device_needs_writing(dev, config_persistent)) {
|
||||
(device_needs_writing(dev, config_persistent) || force)) {
|
||||
strlist_add(mod, "%s %s", dev->subtype->devname,
|
||||
dev->id);
|
||||
}
|
||||
@@ -68,19 +117,18 @@ exit_code_t root_check(void)
|
||||
|
||||
if (util_list_is_empty(mod))
|
||||
goto out;
|
||||
info("Note: Some of the changes affect devices providing the root "
|
||||
"file system:\n");
|
||||
info("Note: The initial RAM-disk must be updated for these changes to take effect:\n");
|
||||
util_list_iterate(mod, s)
|
||||
info(" - %s\n", s->str);
|
||||
info(" Additional steps such as rebuilding the RAM-disk might be "
|
||||
"required.\n");
|
||||
|
||||
/* Check if script is available. */
|
||||
if (!util_path_is_reg_file(PATH_ROOT_SCRIPT))
|
||||
if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) {
|
||||
warn("A manual update of the initial RAM-disk is required.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ask for confirmation. */
|
||||
if (!confirm("Update persistent root device configuration now?")) {
|
||||
if (!confirm("Update initial RAM-disk now?")) {
|
||||
rc = EXIT_ABORTED;
|
||||
goto out;
|
||||
}
|
||||
@@ -97,7 +145,7 @@ exit_code_t root_check(void)
|
||||
/* Run update command. */
|
||||
if (misc_system(err_delayed_print, "%s %s", PATH_ROOT_SCRIPT,
|
||||
params_str) != 0) {
|
||||
error("Failure while updating root device configuration\n");
|
||||
error("Failure while updating initial RAM-disk\n");
|
||||
delayed_print(DELAY_INDENT);
|
||||
rc = EXIT_RUNTIME_ERROR;
|
||||
}
|
||||
|
||||
@@ -248,12 +248,13 @@ static void unblacklist_devices(struct select_opts *select)
|
||||
bool select_match_state(struct device *dev, struct select_opts *select)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
int exists, configured, online;
|
||||
int exists, configured, autoconf, online;
|
||||
struct util_list *errors;
|
||||
|
||||
exists = dev->active.exists || dev->active.definable;
|
||||
configured = dev->persistent.exists;
|
||||
if (select->all && !(exists || configured))
|
||||
autoconf = dev->autoconf.exists;
|
||||
if (select->all && !(exists || configured || autoconf))
|
||||
return false;
|
||||
if (select->existing && !exists)
|
||||
return false;
|
||||
@@ -862,7 +863,8 @@ static exit_code_t select_nocreate(struct select_opts *select,
|
||||
select->offline || select->online ||
|
||||
SCOPE_ACTIVE(config),
|
||||
select->configured || select->all ||
|
||||
SCOPE_PERSISTENT(config));
|
||||
SCOPE_PERSISTENT(config),
|
||||
select->all || SCOPE_AUTOCONF(config));
|
||||
|
||||
longrun_total = 0;
|
||||
if (quiet)
|
||||
@@ -870,7 +872,7 @@ static exit_code_t select_nocreate(struct select_opts *select,
|
||||
|
||||
/* Count devices. */
|
||||
verb("Scanning for devices in %s configuration%s:\n",
|
||||
config_to_str(id_config), id_config == config_all ? "s" : "");
|
||||
config_to_str(id_config), !SCOPE_SINGLE(id_config) ? "s" : "");
|
||||
for (i = 0; (dt = devtypes[i]); i++) {
|
||||
if (select->devtype && dt != select->devtype)
|
||||
continue;
|
||||
@@ -1128,6 +1130,13 @@ static exit_code_t by_attr_cb(struct subtype *st, const char *id,
|
||||
|
||||
/* Check for attribute value in persistent configuration. */
|
||||
s = setting_list_find(dev->persistent.settings, cb_data->key);
|
||||
if (s) {
|
||||
match = setting_match_value(s, cb_data->value);
|
||||
if (match)
|
||||
goto out;
|
||||
}
|
||||
/* Check for attribute value in autoconf configuration. */
|
||||
s = setting_list_find(dev->autoconf.settings, cb_data->key);
|
||||
if (s)
|
||||
match = setting_match_value(s, cb_data->value);
|
||||
|
||||
|
||||
@@ -646,7 +646,8 @@ static void add_changes(struct util_list *list, struct setting *s)
|
||||
|
||||
/* Return a newly allocated string containing the setting changes found
|
||||
* in PERS and ACT or NULL if no change was found. */
|
||||
char *setting_get_changes(struct setting_list *act, struct setting_list *pers)
|
||||
char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
|
||||
struct setting_list *ac)
|
||||
{
|
||||
struct util_list *out;
|
||||
struct util_list *processed;
|
||||
@@ -668,6 +669,17 @@ char *setting_get_changes(struct setting_list *act, struct setting_list *pers)
|
||||
strlist_add(processed, s->name);
|
||||
}
|
||||
}
|
||||
if (ac) {
|
||||
util_list_iterate(&ac->list, s) {
|
||||
if (s->removed)
|
||||
strlist_add(out, "-%s", s->name);
|
||||
else if (s->modified)
|
||||
add_changes(out, s);
|
||||
else
|
||||
continue;
|
||||
strlist_add(processed, s->name);
|
||||
}
|
||||
}
|
||||
if (act) {
|
||||
util_list_iterate(&act->list, s) {
|
||||
if (!s->modified && !s->removed)
|
||||
|
||||
@@ -195,6 +195,13 @@ bool subtype_device_exists_persistent(struct subtype *st, const char *id)
|
||||
return super->exists_persistent(st, id);
|
||||
}
|
||||
|
||||
bool subtype_device_exists_autoconf(struct subtype *st, const char *id)
|
||||
{
|
||||
struct subtype *super = super_get(st, exists_autoconf, 1);
|
||||
|
||||
return super->exists_autoconf(st, id);
|
||||
}
|
||||
|
||||
void subtype_add_active_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
struct subtype *super = super_get(st, add_active_ids, 1);
|
||||
@@ -209,6 +216,13 @@ void subtype_add_persistent_ids(struct subtype *st, struct util_list *ids)
|
||||
super->add_persistent_ids(st, ids);
|
||||
}
|
||||
|
||||
void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
struct subtype *super = super_get(st, add_autoconf_ids, 1);
|
||||
|
||||
super->add_autoconf_ids(st, ids);
|
||||
}
|
||||
|
||||
exit_code_t subtype_device_read_active(struct subtype *st, struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
@@ -226,6 +240,15 @@ exit_code_t subtype_device_read_persistent(struct subtype *st,
|
||||
return super->read_persistent(st, dev, scope);
|
||||
}
|
||||
|
||||
exit_code_t subtype_device_read_autoconf(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
struct subtype *super = super_get(st, read_autoconf, 1);
|
||||
|
||||
return super->read_autoconf(st, dev, scope);
|
||||
}
|
||||
|
||||
exit_code_t subtype_device_configure_active(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
@@ -242,6 +265,14 @@ exit_code_t subtype_device_configure_persistent(struct subtype *st,
|
||||
return super->configure_persistent(st, dev);
|
||||
}
|
||||
|
||||
exit_code_t subtype_device_configure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
struct subtype *super = super_get(st, configure_autoconf, 1);
|
||||
|
||||
return super->configure_autoconf(st, dev);
|
||||
}
|
||||
|
||||
exit_code_t subtype_device_deconfigure_active(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
@@ -258,6 +289,14 @@ exit_code_t subtype_device_deconfigure_persistent(struct subtype *st,
|
||||
return super->deconfigure_persistent(st, dev);
|
||||
}
|
||||
|
||||
exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
struct subtype *super = super_get(st, deconfigure_autoconf, 1);
|
||||
|
||||
return super->deconfigure_autoconf(st, dev);
|
||||
}
|
||||
|
||||
exit_code_t subtype_check_pre_configure(struct subtype *st, struct device *dev,
|
||||
int prereq, config_t config)
|
||||
{
|
||||
@@ -299,7 +338,7 @@ void subtype_online_set(struct subtype *st, struct device *dev, int online,
|
||||
int subtype_online_get(struct subtype *st, struct device *dev, config_t config)
|
||||
{
|
||||
struct subtype *super = super_get(st, online_get, 0);
|
||||
int act_online = 1, pers_online = 1;
|
||||
int act_online = 1, pers_online = 1, auto_online = 1;
|
||||
|
||||
if (super)
|
||||
return super->online_get(st, dev, config);
|
||||
@@ -310,8 +349,10 @@ int subtype_online_get(struct subtype *st, struct device *dev, config_t config)
|
||||
act_online = dev->active.exists;
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
pers_online = dev->persistent.exists;
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
auto_online = dev->autoconf.exists;
|
||||
|
||||
return MIN(act_online, pers_online);
|
||||
return MIN(MIN(act_online, pers_online), auto_online);
|
||||
}
|
||||
|
||||
bool subtype_online_specified(struct subtype *st, struct device *dev,
|
||||
@@ -495,6 +536,10 @@ bool subtype_device_exists(struct subtype *st, const char *id, config_t config)
|
||||
if (!subtype_device_exists_persistent(st, id))
|
||||
return false;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
if (!subtype_device_exists_autoconf(st, id))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -512,6 +557,8 @@ static struct util_list *get_ids(struct subtype *st, config_t config)
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
subtype_add_persistent_ids(st, ids);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
subtype_add_autoconf_ids(st, ids);
|
||||
|
||||
/* Provide a sorted view. */
|
||||
strlist_sort_unique(ids, st->namespace->qsort_cmp);
|
||||
@@ -683,6 +730,19 @@ static exit_code_t read_device(struct subtype *st, const char *id,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
if (subtype_device_exists_autoconf(st, id))
|
||||
rc = subtype_device_read_autoconf(st, dev, scope);
|
||||
else if (defined) {
|
||||
/* Need to copy detected settings to autoconf
|
||||
* config. */
|
||||
setting_list_merge(dev->autoconf.settings,
|
||||
dev->active.settings, false, false);
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (add)
|
||||
device_list_add(st->devices, dev);
|
||||
|
||||
@@ -756,6 +816,25 @@ exit_code_t subtype_write_device(struct subtype *st, struct device *dev,
|
||||
if (!rc)
|
||||
namespace_set_modified(dev->subtype->namespace);
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
if (dev->autoconf.deconfigured) {
|
||||
/* Deconfigure device. */
|
||||
if (dev->autoconf.exists) {
|
||||
rc = subtype_device_deconfigure_autoconf(st,
|
||||
dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
} else if (dev->autoconf.exists) {
|
||||
/* Configure device. */
|
||||
rc = subtype_device_configure_autoconf(st, dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (!rc)
|
||||
namespace_set_modified(dev->subtype->namespace);
|
||||
}
|
||||
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "udev.h"
|
||||
|
||||
int udev_need_settle = 0;
|
||||
int udev_no_settle;
|
||||
|
||||
/* Create a newly allocated udev entry. */
|
||||
static struct udev_entry_node *udev_entry_node_new(const char *key,
|
||||
@@ -359,7 +360,8 @@ static bool get_ids_cb(const char *filename, void *data)
|
||||
|
||||
/* Add the IDs for all devices of the specified subtype name for which a
|
||||
* udev rule exists to strlist LIST. */
|
||||
void udev_get_device_ids(const char *type, struct util_list *list)
|
||||
void udev_get_device_ids(const char *type, struct util_list *list,
|
||||
bool autoconf)
|
||||
{
|
||||
char *path, *prefix;
|
||||
struct util_list *files;
|
||||
@@ -368,7 +370,7 @@ void udev_get_device_ids(const char *type, struct util_list *list)
|
||||
|
||||
prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type);
|
||||
plen = strlen(prefix);
|
||||
path = path_get_udev_rules();
|
||||
path = path_get_udev_rules(autoconf);
|
||||
files = strlist_new();
|
||||
if (!misc_read_dir(path, files, get_ids_cb, prefix))
|
||||
goto out;
|
||||
@@ -387,12 +389,12 @@ out:
|
||||
}
|
||||
|
||||
/* Remove UDEV rule for device. */
|
||||
exit_code_t udev_remove_rule(const char *type, const char *id)
|
||||
exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf)
|
||||
{
|
||||
char *path;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
path = path_get_udev_rule(type, id);
|
||||
path = path_get_udev_rule(type, id, autoconf);
|
||||
if (util_path_is_reg_file(path))
|
||||
rc = remove_file(path);
|
||||
free(path);
|
||||
@@ -403,5 +405,39 @@ exit_code_t udev_remove_rule(const char *type, const char *id)
|
||||
/* Wait for all current udev events to finish. */
|
||||
void udev_settle(void)
|
||||
{
|
||||
if (udev_no_settle)
|
||||
return;
|
||||
misc_system(err_ignore, "%s settle", PATH_UDEVADM);
|
||||
}
|
||||
|
||||
/* Extract internal attribute settings from @entry and add to @list.
|
||||
* Associate corresponding attribute if found in @attribs. */
|
||||
void udev_add_internal_from_entry(struct setting_list *list,
|
||||
struct udev_entry_node *entry,
|
||||
struct attrib **attribs)
|
||||
{
|
||||
char *copy, *name, *end, *u;
|
||||
struct attrib *a;
|
||||
|
||||
/* ENV{zdev_var}="1" */
|
||||
copy = misc_strdup(entry->key);
|
||||
|
||||
/* Find attribute name start. */
|
||||
name = strchr(copy, '{');
|
||||
end = strrchr(copy, '}');
|
||||
if (!name || !end)
|
||||
goto out;
|
||||
*end = 0;
|
||||
name++;
|
||||
|
||||
/* zdev_ => zdev: */
|
||||
u = strchr(name, '_');
|
||||
if (u)
|
||||
*u = ':';
|
||||
|
||||
a = attrib_find(attribs, name);
|
||||
setting_list_apply_actual(list, a, name, entry->value);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "attrib.h"
|
||||
#include "ccw.h"
|
||||
#include "device.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "setting.h"
|
||||
@@ -25,7 +26,7 @@
|
||||
#include "udev_ccw.h"
|
||||
|
||||
/* Check if a udev rule for the specified ccw device exists. */
|
||||
bool udev_ccw_exists(const char *type, const char *id)
|
||||
bool udev_ccw_exists(const char *type, const char *id, bool autoconf)
|
||||
{
|
||||
char *path, *normid;
|
||||
bool rc;
|
||||
@@ -34,7 +35,7 @@ bool udev_ccw_exists(const char *type, const char *id)
|
||||
if (!normid)
|
||||
return false;
|
||||
|
||||
path = path_get_udev_rule(type, normid);
|
||||
path = path_get_udev_rule(type, normid, autoconf);
|
||||
rc = util_path_is_reg_file(path);
|
||||
free(path);
|
||||
free(normid);
|
||||
@@ -49,6 +50,12 @@ static void add_setting_from_entry(struct setting_list *list,
|
||||
char *copy, *name, *end;
|
||||
struct attrib *a;
|
||||
|
||||
/* ENV{zdev_var}="1" */
|
||||
if (starts_with(entry->key, "ENV{zdev_") &&
|
||||
strcmp(entry->op, "=") == 0) {
|
||||
udev_add_internal_from_entry(list, entry, attribs);
|
||||
return;
|
||||
}
|
||||
/* ATTR{[ccw/0.0.37bf]online}=1 */
|
||||
if (strncmp(entry->key, "ATTR{[ccw/", 10) != 0 ||
|
||||
strcmp(entry->op, "=") != 0)
|
||||
@@ -88,15 +95,16 @@ static void udev_file_get_settings(struct udev_file *file,
|
||||
}
|
||||
|
||||
/* Read the persistent configuration of a CCW device from a udev rule. */
|
||||
exit_code_t udev_ccw_read_device(struct device *dev)
|
||||
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
struct device_state *state = &dev->persistent;
|
||||
struct device_state *state = autoconf ? &dev->autoconf :
|
||||
&dev->persistent;
|
||||
struct udev_file *file = NULL;
|
||||
exit_code_t rc;
|
||||
char *path;
|
||||
|
||||
path = path_get_udev_rule(st->name, dev->id);
|
||||
path = path_get_udev_rule(st->name, dev->id, autoconf);
|
||||
rc = udev_read_file(path, &file);
|
||||
if (rc)
|
||||
goto out;
|
||||
@@ -128,12 +136,13 @@ static char *get_label_id(const char *prefix, const char *type,
|
||||
}
|
||||
|
||||
/* Write the persistent configuration of a CCW device to a udev rule. */
|
||||
exit_code_t udev_ccw_write_device(struct device *dev)
|
||||
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
struct ccw_subtype_data *data = st->data;
|
||||
const char *type = st->name, *drv = data->ccwdrv, *id = dev->id;
|
||||
struct device_state *state = &dev->persistent;
|
||||
struct device_state *state = autoconf ? &dev->autoconf :
|
||||
&dev->persistent;
|
||||
char *path, *cfg_label = NULL, *end_label = NULL;
|
||||
struct util_list *list;
|
||||
struct ptrlist_node *p;
|
||||
@@ -142,7 +151,7 @@ exit_code_t udev_ccw_write_device(struct device *dev)
|
||||
FILE *fd;
|
||||
|
||||
if (!state->exists)
|
||||
return udev_remove_rule(type, id);
|
||||
return udev_remove_rule(type, id, autoconf);
|
||||
|
||||
cfg_label = get_label_id("cfg", type, id);
|
||||
end_label = get_label_id("end", type, id);
|
||||
@@ -150,7 +159,7 @@ exit_code_t udev_ccw_write_device(struct device *dev)
|
||||
/* Apply attributes in correct order. */
|
||||
list = setting_list_get_sorted(state->settings);
|
||||
|
||||
path = path_get_udev_rule(type, id);
|
||||
path = path_get_udev_rule(type, id, autoconf);
|
||||
debug("Writing %s udev rule file %s\n", type, path);
|
||||
if (!util_path_exists(path)) {
|
||||
rc = path_create(path);
|
||||
@@ -188,7 +197,14 @@ exit_code_t udev_ccw_write_device(struct device *dev)
|
||||
s = p->ptr;
|
||||
if (s->removed)
|
||||
continue;
|
||||
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name, s->value);
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
||||
internal_get_name(s->name), s->value);
|
||||
} else {
|
||||
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name,
|
||||
s->value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write udev rule epilog. */
|
||||
@@ -234,14 +250,18 @@ out:
|
||||
}
|
||||
|
||||
/* Write a udev rule to free devices from the cio-ignore blacklist. */
|
||||
exit_code_t udev_ccw_write_cio_ignore(const char *id_list)
|
||||
exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf)
|
||||
{
|
||||
char *path, *curr = NULL;
|
||||
char *path, *prefix, *curr = NULL;
|
||||
FILE *fd;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
/* Ensure that autoconf version of cio-ignore is not masked
|
||||
* by normal one. */
|
||||
prefix = autoconf ? "cio-ignore-autoconf" : "cio-ignore";
|
||||
|
||||
/* Create file. */
|
||||
path = path_get_udev_rule("cio-ignore", NULL);
|
||||
path = path_get_udev_rule(prefix, NULL, autoconf);
|
||||
|
||||
if (!*id_list) {
|
||||
/* Empty id_list string - remove file. */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "attrib.h"
|
||||
#include "ccwgroup.h"
|
||||
#include "device.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "setting.h"
|
||||
@@ -25,34 +26,34 @@
|
||||
#include "udev_ccwgroup.h"
|
||||
|
||||
static char *get_rule_path_by_devid(const char *type,
|
||||
struct ccwgroup_devid *devid)
|
||||
struct ccwgroup_devid *devid, bool autoconf)
|
||||
{
|
||||
char *ccw_id, *path;
|
||||
|
||||
ccw_id = ccw_devid_to_str(&devid->devid[0]);
|
||||
path = path_get_udev_rule(type, ccw_id);
|
||||
path = path_get_udev_rule(type, ccw_id, autoconf);
|
||||
free(ccw_id);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static char *get_rule_path(const char *type, const char *id)
|
||||
static char *get_rule_path(const char *type, const char *id, bool autoconf)
|
||||
{
|
||||
struct ccwgroup_devid devid;
|
||||
|
||||
if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK)
|
||||
return NULL;
|
||||
|
||||
return get_rule_path_by_devid(type, &devid);
|
||||
return get_rule_path_by_devid(type, &devid, autoconf);
|
||||
}
|
||||
|
||||
/* Check if a udev rule for the specified CCWGROUP device exists. */
|
||||
bool udev_ccwgroup_exists(const char *type, const char *id)
|
||||
bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf)
|
||||
{
|
||||
char *path;
|
||||
bool rc;
|
||||
|
||||
path = get_rule_path(type, id);
|
||||
path = get_rule_path(type, id, autoconf);
|
||||
if (!path)
|
||||
return false;
|
||||
rc = util_path_is_reg_file(path);
|
||||
@@ -68,6 +69,12 @@ static void add_setting_from_entry(struct setting_list *list,
|
||||
char *copy, *name, *end;
|
||||
struct attrib *a;
|
||||
|
||||
/* ENV{zdev_var}="1" */
|
||||
if (starts_with(entry->key, "ENV{zdev_") &&
|
||||
strcmp(entry->op, "=") == 0) {
|
||||
udev_add_internal_from_entry(list, entry, attribs);
|
||||
return;
|
||||
}
|
||||
/* ATTR{[ccwgroup/0.0.f5f0]online}=1 */
|
||||
if (strncmp(entry->key, "ATTR{[ccwgroup/", 10) != 0 ||
|
||||
strcmp(entry->op, "=") != 0)
|
||||
@@ -143,15 +150,16 @@ static void expand_id(struct device *dev, struct udev_file *file)
|
||||
}
|
||||
|
||||
/* Read the persistent configuration of a CCWGROUP device from a udev rule. */
|
||||
exit_code_t udev_ccwgroup_read_device(struct device *dev)
|
||||
exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
struct device_state *state = &dev->persistent;
|
||||
struct device_state *state = autoconf ? &dev->autoconf :
|
||||
&dev->persistent;
|
||||
struct udev_file *file = NULL;
|
||||
exit_code_t rc;
|
||||
char *path;
|
||||
|
||||
path = get_rule_path_by_devid(st->name, dev->devid);
|
||||
path = get_rule_path_by_devid(st->name, dev->devid, autoconf);
|
||||
rc = udev_read_file(path, &file);
|
||||
if (rc)
|
||||
goto out;
|
||||
@@ -184,9 +192,11 @@ static char *get_label_id(const char *prefix, const char *type,
|
||||
}
|
||||
|
||||
/* Write the persistent configuration of a CCWGROUP device to a udev rule. */
|
||||
exit_code_t udev_ccwgroup_write_device(struct device *dev)
|
||||
exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
struct device_state *state = autoconf ? &dev->autoconf :
|
||||
&dev->persistent;
|
||||
struct ccwgroup_subtype_data *data = st->data;
|
||||
const char *type = st->name, *drv = data->ccwgroupdrv, *id = dev->id;
|
||||
struct ccwgroup_devid devid;
|
||||
@@ -200,21 +210,21 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev)
|
||||
FILE *fd;
|
||||
unsigned int i;
|
||||
|
||||
if (!dev->persistent.exists)
|
||||
return udev_ccwgroup_remove_rule(type, id);
|
||||
if (!state->exists)
|
||||
return udev_ccwgroup_remove_rule(type, id, autoconf);
|
||||
|
||||
if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK)
|
||||
return EXIT_INVALID_ID;
|
||||
|
||||
ccw_id = ccw_devid_to_str(&devid.devid[0]);
|
||||
path = get_rule_path(type, ccw_id);
|
||||
path = get_rule_path(type, ccw_id, autoconf);
|
||||
|
||||
group_label = get_label_id("group", type, ccw_id);
|
||||
cfg_label = get_label_id("cfg", type, ccw_id);
|
||||
end_label = get_label_id("end", type, ccw_id);
|
||||
|
||||
/* Apply attributes in correct order. */
|
||||
list = setting_list_get_sorted(dev->persistent.settings);
|
||||
list = setting_list_get_sorted(state->settings);
|
||||
|
||||
debug("Writing %s udev rule file %s\n", type, path);
|
||||
if (!util_path_exists(path)) {
|
||||
@@ -279,6 +289,10 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev)
|
||||
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n",
|
||||
ccw_id, s->name, str->str);
|
||||
}
|
||||
} else if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
||||
internal_get_name(s->name), s->value);
|
||||
} else {
|
||||
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n", ccw_id,
|
||||
s->name, s->value);
|
||||
@@ -357,12 +371,13 @@ static exit_code_t get_ids_cb(const char *path, const char *filename,
|
||||
|
||||
/* Add the IDs for all devices of the specified subtype name for which a
|
||||
* udev rule exists to strlist LIST. */
|
||||
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list)
|
||||
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
|
||||
bool autoconf)
|
||||
{
|
||||
struct get_ids_cb_data cb_data;
|
||||
char *path;
|
||||
|
||||
path = path_get_udev_rules();
|
||||
path = path_get_udev_rules(autoconf);
|
||||
cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type);
|
||||
cb_data.ids = list;
|
||||
|
||||
@@ -374,7 +389,8 @@ void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list)
|
||||
}
|
||||
|
||||
/* Remove UDEV rule for CCWGROUP device. */
|
||||
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id)
|
||||
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
|
||||
bool autoconf)
|
||||
{
|
||||
char *partial_id, *path;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
@@ -383,7 +399,7 @@ exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id)
|
||||
if (!partial_id)
|
||||
return EXIT_INVALID_ID;
|
||||
|
||||
path = path_get_udev_rule(type, partial_id);
|
||||
path = path_get_udev_rule(type, partial_id, autoconf);
|
||||
if (util_path_is_reg_file(path))
|
||||
rc = remove_file(path);
|
||||
free(path);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "attrib.h"
|
||||
#include "device.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "scsi.h"
|
||||
@@ -128,7 +129,7 @@ static bool zfcp_lun_devid_from_entry(struct zfcp_lun_devid *id_ptr,
|
||||
struct udev_entry_node *entry)
|
||||
{
|
||||
struct zfcp_lun_devid id;
|
||||
char *copy = NULL, *s;
|
||||
char *copy = NULL, *s, *e, *u;
|
||||
int i;
|
||||
bool rc = false;
|
||||
|
||||
@@ -182,6 +183,28 @@ static bool zfcp_lun_devid_from_entry(struct zfcp_lun_devid *id_ptr,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
||||
if (starts_with(entry->key, "ENV{zdev_")) {
|
||||
copy = misc_strdup(entry->key);
|
||||
|
||||
/* Find ID start (last __) and end (last }). */
|
||||
s = misc_strrstr(copy, "__");
|
||||
e = strrchr(copy, '}');
|
||||
if (!s || !e)
|
||||
goto out;
|
||||
*e = 0;
|
||||
s += 2;
|
||||
/* Convert variable name to ID format. */
|
||||
for (i = 0, u = s; (u = strchr(u, '_')); i++, u++) {
|
||||
if (i < 2)
|
||||
*u = '.';
|
||||
else
|
||||
*u = ':';
|
||||
}
|
||||
rc = zfcp_lun_parse_devid(&id, s, err_ignore) == EXIT_OK ?
|
||||
true : false;
|
||||
}
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
if (rc)
|
||||
@@ -211,11 +234,46 @@ static struct zfcp_lun_node *zfcp_lun_node_from_entry(
|
||||
return node;
|
||||
}
|
||||
|
||||
static void add_internal_setting_from_entry(struct udev_entry_node *entry,
|
||||
struct zfcp_lun_node *node)
|
||||
{
|
||||
char *copy, *name, *end, *u;
|
||||
struct attrib *a;
|
||||
|
||||
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
||||
copy = misc_strdup(entry->key);
|
||||
|
||||
/* Find attribute name start and end. */
|
||||
name = strchr(copy, '{');
|
||||
end = misc_strrstr(copy, "__");
|
||||
if (!name || !end)
|
||||
goto out;
|
||||
*end = 0;
|
||||
name++;
|
||||
|
||||
/* zdev_ => zdev: */
|
||||
u = strchr(name, '_');
|
||||
if (u)
|
||||
*u = ':';
|
||||
|
||||
a = attrib_find(zfcp_lun_subtype.dev_attribs, name);
|
||||
setting_list_apply_actual(node->fc_settings, a, name, entry->value);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
}
|
||||
|
||||
static void add_fc_setting_from_entry(struct udev_entry_node *entry,
|
||||
struct zfcp_lun_node *node)
|
||||
{
|
||||
char *copy, *s, *e;
|
||||
|
||||
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
||||
if (starts_with(entry->key, "ENV{zdev_") &&
|
||||
strcmp(entry->op, "=") == 0) {
|
||||
add_internal_setting_from_entry(entry, node);
|
||||
return;
|
||||
}
|
||||
/*ATTR{[ccw/0.0.1941]0x500507630510c1ae/0x402340d400000000/failed}="0"*/
|
||||
if (!starts_with(entry->key, "ATTR{[ccw/"))
|
||||
return;
|
||||
@@ -369,14 +427,14 @@ static exit_code_t lun_cb(const char *path, const char *name, void *data)
|
||||
|
||||
/* Add the IDs for all zfcp lun devices for which a configuration exists to
|
||||
* LIST. */
|
||||
void udev_zfcp_lun_add_device_ids(struct util_list *list)
|
||||
void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf)
|
||||
{
|
||||
struct lun_cb_data cb_data;
|
||||
char *path;
|
||||
|
||||
cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, ZFCP_LUN_NAME);
|
||||
cb_data.list = list;
|
||||
path = path_get_udev_rules();
|
||||
path = path_get_udev_rules(autoconf);
|
||||
|
||||
if (util_path_is_dir(path))
|
||||
path_for_each(path, lun_cb, &cb_data);
|
||||
@@ -385,7 +443,9 @@ void udev_zfcp_lun_add_device_ids(struct util_list *list)
|
||||
free(cb_data.prefix);
|
||||
}
|
||||
|
||||
static char *get_zfcp_lun_path(const char *id)
|
||||
/* Return path to zfcp lun udev rule file containing configuration data for
|
||||
* all LUNs of a zfcp device. */
|
||||
static char *get_zfcp_lun_path(const char *id, bool autoconf)
|
||||
{
|
||||
char *copy, *e, *path;
|
||||
|
||||
@@ -393,12 +453,19 @@ static char *get_zfcp_lun_path(const char *id)
|
||||
e = strchr(copy, ':');
|
||||
if (e)
|
||||
*e = 0;
|
||||
path = path_get_udev_rule(ZFCP_LUN_NAME, copy);
|
||||
path = path_get_udev_rule(ZFCP_LUN_NAME, copy, autoconf);
|
||||
free(copy);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Return path to zfcp lun udev rule file containing configuration data for
|
||||
* a single LUN. */
|
||||
static char *get_single_zfcp_lun_path(const char *id, bool autoconf)
|
||||
{
|
||||
return path_get_udev_rule(ZFCP_LUN_NAME, id, autoconf);
|
||||
}
|
||||
|
||||
/* Apply the settings found in NODE to STATE. */
|
||||
static void zfcp_lun_node_to_state(struct zfcp_lun_node *node,
|
||||
struct attrib **attribs,
|
||||
@@ -428,16 +495,22 @@ static void zfcp_lun_node_to_state(struct zfcp_lun_node *node,
|
||||
}
|
||||
|
||||
/* Read the persistent configuration of a zfcp lun from a udev rule. */
|
||||
exit_code_t udev_zfcp_lun_read_device(struct device *dev)
|
||||
exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf)
|
||||
{
|
||||
struct subtype *st = dev->subtype;
|
||||
struct device_state *state = &dev->persistent;
|
||||
struct device_state *state = autoconf ? &dev->autoconf :
|
||||
&dev->persistent;
|
||||
struct util_list *luns;
|
||||
struct zfcp_lun_node *node;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
char *path;
|
||||
|
||||
path = get_zfcp_lun_path(dev->id);
|
||||
/* Check for single lun file first then try multi lun file. */
|
||||
path = get_single_zfcp_lun_path(dev->id, autoconf);
|
||||
if (!util_path_exists(path)) {
|
||||
free(path);
|
||||
path = get_zfcp_lun_path(dev->id, autoconf);
|
||||
}
|
||||
|
||||
/* Get previous rule data. */
|
||||
luns = zfcp_lun_node_list_new();
|
||||
@@ -475,7 +548,7 @@ static struct zfcp_lun_node *state_to_zfcp_lun_node(struct zfcp_lun_devid *id,
|
||||
s->value);
|
||||
setting_list_add(node->scsi_settings, n);
|
||||
} else {
|
||||
n = setting_new(NULL, s->name, s->value);
|
||||
n = setting_new(s->attrib, s->name, s->value);
|
||||
setting_list_add(node->fc_settings, n);
|
||||
}
|
||||
}
|
||||
@@ -565,9 +638,21 @@ static exit_code_t write_luns_rule(const char *path, struct util_list *list)
|
||||
node->id.lun);
|
||||
|
||||
util_list_iterate(&node->fc_settings->list, s) {
|
||||
fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64 "/0x%016"
|
||||
PRIx64 "/%s}=\"%s\"\n", hba_id, node->id.wwpn,
|
||||
node->id.lun, s->name, s->value);
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s__%x_%x_%04x_0x%016"
|
||||
PRIx64 "_0x%016" PRIx64 "}=\"%s\"\n",
|
||||
internal_get_name(s->name),
|
||||
node->id.fcp_dev.cssid,
|
||||
node->id.fcp_dev.ssid,
|
||||
node->id.fcp_dev.devno, node->id.wwpn,
|
||||
node->id.lun, s->value);
|
||||
} else {
|
||||
fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64
|
||||
"/0x%016" PRIx64 "/%s}=\"%s\"\n",
|
||||
hba_id, node->id.wwpn, node->id.lun,
|
||||
s->name, s->value);
|
||||
}
|
||||
}
|
||||
last_node = node;
|
||||
}
|
||||
@@ -599,8 +684,10 @@ out:
|
||||
|
||||
/* Update the udev rule file that configures the zfcp lun with the specified
|
||||
* ID. If @state is %NULL, remove the rule, otherwise create a rule that
|
||||
* applies the corresponding parameters. */
|
||||
static exit_code_t update_lun_rule(const char *id, struct device_state *state)
|
||||
* applies the corresponding parameters. If @single is set, update a single
|
||||
* lun rule file, otherwise update a multi lun rule file. */
|
||||
static exit_code_t update_lun_rule(const char *id, struct device_state *state,
|
||||
bool single, bool autoconf)
|
||||
{
|
||||
struct zfcp_lun_devid devid;
|
||||
struct util_list *luns;
|
||||
@@ -612,7 +699,8 @@ static exit_code_t update_lun_rule(const char *id, struct device_state *state)
|
||||
rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print);
|
||||
if (rc)
|
||||
return rc;
|
||||
path = get_zfcp_lun_path(id);
|
||||
path = single ? get_single_zfcp_lun_path(id, autoconf) :
|
||||
get_zfcp_lun_path(id, autoconf);
|
||||
|
||||
/* Get previous rule data. */
|
||||
luns = zfcp_lun_node_list_new();
|
||||
@@ -648,27 +736,55 @@ static exit_code_t update_lun_rule(const char *id, struct device_state *state)
|
||||
|
||||
/* Write a udev-rule to configure the specified zfcp lun and associated
|
||||
* device state. */
|
||||
exit_code_t udev_zfcp_lun_write_device(struct device *dev)
|
||||
exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf)
|
||||
{
|
||||
return update_lun_rule(dev->id, &dev->persistent);
|
||||
exit_code_t rc;
|
||||
struct device_state *state = autoconf ? &dev->autoconf :
|
||||
&dev->persistent;
|
||||
|
||||
rc = update_lun_rule(dev->id, state, true, autoconf);
|
||||
|
||||
/* We only want single lun rule files so remove any remaining
|
||||
* references in multi lun rule files. */
|
||||
update_lun_rule(dev->id, NULL, false, autoconf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */
|
||||
exit_code_t udev_zfcp_lun_remove_rule(const char *id)
|
||||
exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf)
|
||||
{
|
||||
return update_lun_rule(id, NULL);
|
||||
exit_code_t rc, rc2;
|
||||
|
||||
rc = update_lun_rule(id, NULL, true, autoconf);
|
||||
rc2 = update_lun_rule(id, NULL, false, autoconf);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return rc2;
|
||||
}
|
||||
|
||||
/* Determine if a udev rule exists for configuring the specified zfcp lun. */
|
||||
bool udev_zfcp_lun_exists(const char *id)
|
||||
bool udev_zfcp_lun_exists(const char *id, bool autoconf)
|
||||
{
|
||||
struct zfcp_lun_devid devid;
|
||||
char *path, *rule, *pattern = NULL;
|
||||
char *path, *rule = NULL, *pattern = NULL;
|
||||
bool rc = false;
|
||||
|
||||
if (zfcp_lun_parse_devid(&devid, id, err_ignore) != EXIT_OK)
|
||||
return false;
|
||||
path = get_zfcp_lun_path(id);
|
||||
|
||||
/* Check for single lun rule file first. */
|
||||
path = get_single_zfcp_lun_path(id, autoconf);
|
||||
if (util_path_exists(path)) {
|
||||
rc = true;
|
||||
goto out;
|
||||
}
|
||||
free(path);
|
||||
|
||||
/* Check multi lun rule file next. */
|
||||
path = get_zfcp_lun_path(id, autoconf);
|
||||
rule = misc_read_text_file(path, 1, err_ignore);
|
||||
if (!rule)
|
||||
goto out;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "ccw.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "setting.h"
|
||||
@@ -247,6 +248,7 @@ struct subtype zfcp_host_subtype = {
|
||||
&zfcp_host_attr_failed,
|
||||
&zfcp_host_attr_port_remove,
|
||||
&zfcp_host_attr_port_rescan,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "misc.h"
|
||||
#include "internal.h"
|
||||
#include "namespace.h"
|
||||
#include "path.h"
|
||||
#include "scsi.h"
|
||||
@@ -467,7 +468,14 @@ static exit_code_t zfcp_lun_st_read_persistent(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
return udev_zfcp_lun_read_device(dev);
|
||||
return udev_zfcp_lun_read_device(dev, false);
|
||||
}
|
||||
|
||||
static exit_code_t zfcp_lun_st_read_autoconf(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
return udev_zfcp_lun_read_device(dev, true);
|
||||
}
|
||||
|
||||
static exit_code_t zfcp_lun_add(struct device *dev)
|
||||
@@ -564,7 +572,13 @@ static exit_code_t zfcp_lun_st_configure_active(struct subtype *st,
|
||||
static exit_code_t zfcp_lun_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_zfcp_lun_write_device(dev);
|
||||
return udev_zfcp_lun_write_device(dev, false);
|
||||
}
|
||||
|
||||
static exit_code_t zfcp_lun_st_configure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_zfcp_lun_write_device(dev, true);
|
||||
}
|
||||
|
||||
static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st,
|
||||
@@ -578,7 +592,13 @@ static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st,
|
||||
static exit_code_t zfcp_lun_st_deconfigure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_zfcp_lun_remove_rule(dev->id);
|
||||
return udev_zfcp_lun_remove_rule(dev->id, false);
|
||||
}
|
||||
|
||||
static exit_code_t zfcp_lun_st_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_zfcp_lun_remove_rule(dev->id, true);
|
||||
}
|
||||
|
||||
static exit_code_t check_npiv(struct subtype *st, struct device *dev,
|
||||
@@ -606,7 +626,8 @@ static exit_code_t check_npiv(struct subtype *st, struct device *dev,
|
||||
if (!allow_lun_scan)
|
||||
goto out;
|
||||
|
||||
if (!(dev->active.deconfigured || dev->persistent.deconfigured)) {
|
||||
if (!(dev->active.deconfigured || dev->persistent.deconfigured ||
|
||||
dev->autoconf.deconfigured)) {
|
||||
delayed_info("Note: Auto LUN scan enabled - manual LUN "
|
||||
"configuration is redundant for %s %s\n",
|
||||
zfcp_host_subtype.devname, fcp_dev_id);
|
||||
@@ -643,7 +664,8 @@ static exit_code_t zfcp_lun_st_check_post_configure(struct subtype *st,
|
||||
|
||||
/* Don't show note when an attribute was modified. */
|
||||
if (setting_list_modified(dev->active.settings) ||
|
||||
setting_list_modified(dev->persistent.settings))
|
||||
setting_list_modified(dev->persistent.settings) ||
|
||||
setting_list_modified(dev->autoconf.settings))
|
||||
return EXIT_OK;
|
||||
|
||||
/* Check for NPIV but don't route exit code to caller - we only
|
||||
@@ -795,7 +817,12 @@ static bool zfcp_lun_st_exists_active(struct subtype *st, const char *id)
|
||||
|
||||
static bool zfcp_lun_st_exists_persistent(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_zfcp_lun_exists(id);
|
||||
return udev_zfcp_lun_exists(id, false);
|
||||
}
|
||||
|
||||
static bool zfcp_lun_st_exists_autoconf(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_zfcp_lun_exists(id, true);
|
||||
}
|
||||
|
||||
static exit_code_t zfcp_lun_st_is_definable(struct subtype *st, const char *id,
|
||||
@@ -889,7 +916,13 @@ static void zfcp_lun_st_add_active_ids(struct subtype *st,
|
||||
static void zfcp_lun_st_add_persistent_ids(struct subtype *st,
|
||||
struct util_list *ids)
|
||||
{
|
||||
udev_zfcp_lun_add_device_ids(ids);
|
||||
udev_zfcp_lun_add_device_ids(ids, false);
|
||||
}
|
||||
|
||||
static void zfcp_lun_st_add_autoconf_ids(struct subtype *st,
|
||||
struct util_list *ids)
|
||||
{
|
||||
udev_zfcp_lun_add_device_ids(ids, true);
|
||||
}
|
||||
|
||||
static exit_code_t add_sg_cb(const char *path, const char *filename, void *data)
|
||||
@@ -1065,6 +1098,7 @@ struct subtype zfcp_lun_subtype = {
|
||||
&zfcp_lun_attr_scsi_timeout,
|
||||
&zfcp_lun_attr_scsi_state,
|
||||
&zfcp_lun_attr_scsi_delete,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.prefixes = STRING_ARRAY(SCSI_ATTR_PREFIX),
|
||||
.unknown_dev_attribs = 1,
|
||||
@@ -1072,18 +1106,23 @@ struct subtype zfcp_lun_subtype = {
|
||||
|
||||
.exists_active = &zfcp_lun_st_exists_active,
|
||||
.exists_persistent = &zfcp_lun_st_exists_persistent,
|
||||
.exists_autoconf = &zfcp_lun_st_exists_autoconf,
|
||||
|
||||
.add_active_ids = &zfcp_lun_st_add_active_ids,
|
||||
.add_persistent_ids = &zfcp_lun_st_add_persistent_ids,
|
||||
.add_autoconf_ids = &zfcp_lun_st_add_autoconf_ids,
|
||||
|
||||
.read_active = &zfcp_lun_st_read_active,
|
||||
.read_persistent = &zfcp_lun_st_read_persistent,
|
||||
.read_autoconf = &zfcp_lun_st_read_autoconf,
|
||||
|
||||
.configure_active = &zfcp_lun_st_configure_active,
|
||||
.configure_persistent = &zfcp_lun_st_configure_persistent,
|
||||
.configure_autoconf = &zfcp_lun_st_configure_autoconf,
|
||||
|
||||
.deconfigure_active = &zfcp_lun_st_deconfigure_active,
|
||||
.deconfigure_persistent = &zfcp_lun_st_deconfigure_persistent,
|
||||
.deconfigure_autoconf = &zfcp_lun_st_deconfigure_autoconf,
|
||||
|
||||
.check_pre_configure = &zfcp_lun_st_check_pre_configure,
|
||||
.check_post_configure = &zfcp_lun_st_check_post_configure,
|
||||
|
||||
@@ -119,6 +119,7 @@ extern enum scan_key_state scan_key_table[SCAN_SECTION_NUM][SCAN_KEYWORD_NUM];
|
||||
|
||||
|
||||
int scan_file(const char* filename, struct scan_token** array);
|
||||
int scan_bls(const char* blsdir, struct scan_token** token, int scan_size);
|
||||
void scan_free(struct scan_token* array);
|
||||
char* scan_keyword_name(enum scan_keyword_id id);
|
||||
int scan_check_defaultboot(struct scan_token* scan);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#define ZIPL_CONF_VAR "ZIPLCONF"
|
||||
#define ZIPL_DEFAULT_CONF "/etc/zipl.conf"
|
||||
#define ZIPL_DEFAULT_BLSDIR "/boot/loader/entries"
|
||||
|
||||
#define MENU_DEFAULT_PROMPT 0
|
||||
#define MENU_DEFAULT_TIMEOUT 0
|
||||
|
||||
@@ -25,7 +25,7 @@ loading a data file to initialize named saved segments (NSS)
|
||||
Each of these operations is characterized by a boot configuration, i.e. a
|
||||
set of required parameters.
|
||||
.B zipl
|
||||
supports two ways of specifying a boot configuration:
|
||||
supports three ways of specifying a boot configuration:
|
||||
.IP " -"
|
||||
.B command line:
|
||||
all parameters are provided through the command line switches described below.
|
||||
@@ -37,6 +37,11 @@ parameters are provided by sections defined in a configuration file (see
|
||||
Using a configuration file, you can either specify a single boot configuration
|
||||
or a menu, i.e. a list of configurations from which users can choose at boot
|
||||
time.
|
||||
.IP " -"
|
||||
.B BLS config files:
|
||||
boot configurations are specified using BootLoaderSpec (BLS) configuration files. The
|
||||
.BR zipl.conf (5)
|
||||
configuration file is still used to specify parameters or aditional boot configurations.
|
||||
.PP
|
||||
|
||||
To use a single boot configuration section, provide its name as parameter to
|
||||
@@ -117,6 +122,11 @@ Print version information, then exit.
|
||||
Use the specified <CONFIG FILE>. If none is supplied, the environment
|
||||
variable ZIPLCONF is evaluated if set, otherwise /etc/zipl.conf is used.
|
||||
|
||||
.TP
|
||||
.BR "\-b <BLS DIRECTORY>" " or " "\-\-blsdir=<BLS DIRECTORY>"
|
||||
Use the specified <BLS DIRECTORY> to parse BootLoaderSpec config files.
|
||||
If none is supplied, the /boot/loader/entries directory is used.
|
||||
|
||||
.TP
|
||||
.BR "\-t <TARGET DIRECTORY>" " or " "\-\-target=<TARGET DIRECTORY>"
|
||||
Use the specified <TARGET DIRECTORY>.
|
||||
|
||||
@@ -117,6 +117,27 @@ timeout = 0
|
||||
.br
|
||||
.PP
|
||||
|
||||
.B BootLoaderSpec configuration files
|
||||
|
||||
Another way to specify IPL sections is to use BLS config files. These are
|
||||
configuration files located by default at /boot/loader/entries, but another
|
||||
location can be specified using the '\-\-blsdir' option of zipl.
|
||||
|
||||
.IP
|
||||
# An example for a BLS configuration file
|
||||
.br
|
||||
|
||||
version 4.15.9
|
||||
.br
|
||||
linux /vmlinuz-4.15.9
|
||||
.br
|
||||
initrd /initramfs-4.15.9
|
||||
.br
|
||||
options root=/dev/dasda1 console=ttyS0
|
||||
.PP
|
||||
|
||||
The location of the linux and initrd has to be specified relative to the boot partition. The BLS config files are only used to specify the IPL sections, a zipl.conf configuration files is still needed for global parameters.
|
||||
|
||||
.B Boot menu
|
||||
|
||||
The
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "error.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define DATA_SIZE(x) ((size_t) (&_binary_##x##_bin_size))
|
||||
#define DATA_SIZE(x) ((size_t) (&_binary_##x##_bin_end - &_binary_##x##_bin_start))
|
||||
#define DATA_ADDR(x) (&_binary_##x##_bin_start)
|
||||
|
||||
#define STAGE2_MAX_SIZE 0x3000
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
/* Command line options */
|
||||
static struct option options[] = {
|
||||
{ "config", required_argument, NULL, 'c'},
|
||||
{ "blsdir", required_argument, NULL, 'b'},
|
||||
{ "target", required_argument, NULL, 't'},
|
||||
{ "targetbase", required_argument, NULL, 0xaa},
|
||||
{ "targettype", required_argument, NULL, 0xab},
|
||||
@@ -55,11 +56,12 @@ static struct option options[] = {
|
||||
};
|
||||
|
||||
/* Command line option abbreviations */
|
||||
static const char option_string[] = "-c:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:";
|
||||
static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:";
|
||||
|
||||
struct command_line {
|
||||
char* data[SCAN_KEYWORD_NUM];
|
||||
char* config;
|
||||
char *blsdir;
|
||||
char* menu;
|
||||
char* section;
|
||||
int help;
|
||||
@@ -197,6 +199,14 @@ get_command_line(int argc, char* argv[], struct command_line* line)
|
||||
} else
|
||||
cmdline.config = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
if (cmdline.blsdir != NULL) {
|
||||
error_reason("Option 'blsdir' specified more "
|
||||
"than once");
|
||||
rc = -1;
|
||||
} else
|
||||
cmdline.blsdir = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
if (cmdline.menu != NULL) {
|
||||
error_reason("Option 'menu' specified more "
|
||||
@@ -1731,8 +1741,9 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
|
||||
struct scan_token* scan;
|
||||
struct scan_token* new_scan;
|
||||
char* filename;
|
||||
char *blsdir;
|
||||
char* source;
|
||||
int rc;
|
||||
int rc, scan_size;
|
||||
|
||||
/* Read configuration file */
|
||||
if (cmdline->config != NULL) {
|
||||
@@ -1750,9 +1761,20 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
|
||||
source = "";
|
||||
}
|
||||
printf("Using config file '%s'%s\n", filename, source);
|
||||
rc = scan_file(filename, &scan);
|
||||
if (rc) {
|
||||
scan_size = scan_file(filename, &scan);
|
||||
if (scan_size <= 0) {
|
||||
error_text("Config file '%s'", filename);
|
||||
return scan_size;
|
||||
}
|
||||
/* Check if a BLS directory was provided on command line */
|
||||
if (cmdline->blsdir != NULL) {
|
||||
blsdir = cmdline->blsdir;
|
||||
} else {
|
||||
blsdir = ZIPL_DEFAULT_BLSDIR;
|
||||
}
|
||||
rc = scan_bls(blsdir, &scan, scan_size);
|
||||
if (rc) {
|
||||
error_text("BLS parsing '%s'", blsdir);
|
||||
return rc;
|
||||
}
|
||||
if ((cmdline->menu == NULL) && (cmdline->section == NULL)) {
|
||||
|
||||
193
zipl/src/scan.c
193
zipl/src/scan.c
@@ -16,13 +16,21 @@
|
||||
#define __USE_ISOC99
|
||||
#endif
|
||||
|
||||
/* Need GNU function strverscmp() in dirent.h */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
|
||||
#include "boot.h"
|
||||
@@ -538,9 +546,9 @@ scan_free(struct scan_token* array)
|
||||
|
||||
#define INITIAL_ARRAY_LENGTH 40
|
||||
|
||||
/* Scan file FILENAME for tokens. Upon success, return zero and set TOKEN
|
||||
* to point to a NULL-terminated array of scan_tokens, i.e. the token id
|
||||
* of the last token is 0. Return non-zero otherwise. */
|
||||
/* Scan file FILENAME for tokens. Upon success, return the number allocated
|
||||
* tokens and set TOKEN to point to a NULL-terminated array of scan_tokens,
|
||||
* i.e. the token id of the last token is 0. Return non-zero otherwise. */
|
||||
int
|
||||
scan_file(const char* filename, struct scan_token** token)
|
||||
{
|
||||
@@ -623,10 +631,183 @@ scan_file(const char* filename, struct scan_token** token)
|
||||
}
|
||||
}
|
||||
misc_free_file_buffer(&file);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
scan_free(array);
|
||||
else
|
||||
*token = array;
|
||||
return rc;
|
||||
}
|
||||
|
||||
*token = array;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bls_filter(const struct dirent *ent)
|
||||
{
|
||||
int offset = strlen(ent->d_name) - strlen(".conf");
|
||||
|
||||
if (offset < 0)
|
||||
return 0;
|
||||
|
||||
return strncmp(ent->d_name + offset, ".conf", strlen(".conf")) == 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bls_sort(const struct dirent **ent_a, const struct dirent **ent_b)
|
||||
{
|
||||
return strverscmp((*ent_a)->d_name, (*ent_b)->d_name);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
scan_append_section_heading(struct scan_token* scan, int* index, char* name);
|
||||
static int
|
||||
scan_append_keyword_assignment(struct scan_token* scan, int* index,
|
||||
enum scan_keyword_id id, char* value);
|
||||
|
||||
|
||||
static int
|
||||
scan_bls_field(struct misc_file_buffer *file, struct scan_token* scan,
|
||||
int* index)
|
||||
{
|
||||
int current;
|
||||
int key_start, key_end;
|
||||
int val_start, val_end;
|
||||
char *val;
|
||||
|
||||
for (key_start = file->pos; ; file->pos++) {
|
||||
current = misc_get_char(file, 0);
|
||||
|
||||
if (isblank(current)) {
|
||||
key_end = file->pos;
|
||||
skip_blanks(file);
|
||||
val_start = file->pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isalnum(current) && current != '_' && current != '-')
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (; ; file->pos++) {
|
||||
current = misc_get_char(file, 0);
|
||||
|
||||
if (current == '\n' || current == EOF)
|
||||
break;
|
||||
}
|
||||
|
||||
val_end = file->pos;
|
||||
file->buffer[key_end] = '\0';
|
||||
file->buffer[val_end] = '\0';
|
||||
|
||||
if (strncmp("version", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
scan_append_section_heading(scan, index, &file->buffer[val_start]);
|
||||
}
|
||||
|
||||
if (strncmp("linux", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
misc_asprintf(&val, "%s", &file->buffer[val_start]);
|
||||
scan_append_keyword_assignment(scan, index, scan_keyword_image, val);
|
||||
free(val);
|
||||
}
|
||||
|
||||
if (strncmp("options", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
scan_append_keyword_assignment(scan, index, scan_keyword_parameters,
|
||||
&file->buffer[val_start]);
|
||||
}
|
||||
|
||||
if (strncmp("initrd", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
misc_asprintf(&val, "%s", &file->buffer[val_start]);
|
||||
scan_append_keyword_assignment(scan, index, scan_keyword_ramdisk, val);
|
||||
free(val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scan_bls(const char* blsdir, struct scan_token** token, int scan_size)
|
||||
{
|
||||
int count = 0;
|
||||
int size, remaining = 0, n, current, rc = -1;
|
||||
struct scan_token* buffer;
|
||||
struct scan_token* array = *token;
|
||||
struct dirent** bls_entries;
|
||||
struct misc_file_buffer file;
|
||||
struct stat sb;
|
||||
char filename[PATH_MAX];
|
||||
|
||||
if (!(stat(blsdir, &sb) == 0 && S_ISDIR(sb.st_mode)))
|
||||
return 0;
|
||||
|
||||
n = scandir(blsdir, &bls_entries, bls_filter, bls_sort);
|
||||
if (n <= 0)
|
||||
return n;
|
||||
|
||||
while (array[count].id != 0)
|
||||
count++;
|
||||
|
||||
remaining = scan_size - count;
|
||||
|
||||
if (remaining < n) {
|
||||
size = scan_size - remaining + n;
|
||||
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
|
||||
if (!buffer)
|
||||
goto err;
|
||||
memset(buffer, 0, size * sizeof(struct scan_token));
|
||||
memcpy(buffer, array, count * sizeof(struct scan_token));
|
||||
} else {
|
||||
buffer = array;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
sprintf(filename, "%s/%s", blsdir, bls_entries[n]->d_name);
|
||||
printf("Using BLS config file '%s'\n", filename);
|
||||
|
||||
rc = misc_get_file_buffer(filename, &file);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
while ((size_t)file.pos < file.length) {
|
||||
current = misc_get_char(&file, 0);
|
||||
switch (current) {
|
||||
case '#':
|
||||
file.pos++;
|
||||
skip_line(&file);
|
||||
break;
|
||||
case EOF:
|
||||
break;
|
||||
case '\t':
|
||||
case '\0':
|
||||
case ' ':
|
||||
file.pos++;
|
||||
break;
|
||||
default:
|
||||
rc = scan_bls_field(&file, buffer, &count);
|
||||
if (rc) {
|
||||
error_reason("Incorrect BLS field in "
|
||||
"config file %s\n", filename);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
misc_free_file_buffer(&file);
|
||||
free(bls_entries[n]);
|
||||
}
|
||||
|
||||
*token = buffer;
|
||||
rc = 0;
|
||||
err:
|
||||
if (n > 0) {
|
||||
do {
|
||||
free(bls_entries[n]);
|
||||
} while (n-- > 0);
|
||||
}
|
||||
|
||||
free(bls_entries);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ static const char* usage_text[] = {
|
||||
"-h, --help Print this help, then exit",
|
||||
"-v, --version Print version information, then exit",
|
||||
"-c, --config CONFIGFILE Read configuration from CONFIGFILE",
|
||||
"-b, --blsdir BLSDIR Parse BootLoaderSpec files from BLSDIR",
|
||||
"-t, --target TARGETDIR Write bootmap file to TARGETDIR and install",
|
||||
" bootloader on device containing TARGETDIR",
|
||||
" --targetbase BASEDEVICE Install bootloader on BASEDEVICE",
|
||||
|
||||
@@ -1,47 +1,97 @@
|
||||
include ../common.mak
|
||||
|
||||
ifeq (${HAVE_OPENSSL},0)
|
||||
|
||||
all:
|
||||
$(SKIP) HAVE_OPENSSL=0
|
||||
|
||||
install:
|
||||
$(SKIP) HAVE_OPENSSL=0
|
||||
|
||||
ifneq (${HAVE_OPENSSL},0)
|
||||
BUILD_TARGETS += zkey
|
||||
INSTALL_TARGETS += install-zkey
|
||||
else
|
||||
BUILD_TARGETS += zkey-skip
|
||||
INSTALL_TARGETS += zkey-skip
|
||||
endif
|
||||
|
||||
check_dep:
|
||||
ifneq (${HAVE_CRYPTSETUP2},0)
|
||||
ifneq (${HAVE_JSONC},0)
|
||||
BUILD_TARGETS += zkey-cryptsetup
|
||||
INSTALL_TARGETS += install-zkey-cryptsetup
|
||||
CPPFLAGS += -DHAVE_LUKS2_SUPPORT
|
||||
else
|
||||
BUILD_TARGETS += zkey-cryptsetup-skip-jsonc
|
||||
INSTALL_TARGETS += zkey-cryptsetup-skip-jsonc
|
||||
endif
|
||||
else
|
||||
BUILD_TARGETS += zkey-cryptsetup-skip-cryptsetup2
|
||||
INSTALL_TARGETS += zkey-cryptsetup-skip-cryptsetup2
|
||||
endif
|
||||
|
||||
CPPFLAGS += -I../include
|
||||
LIBS = $(rootdir)/libutil/libutil.a
|
||||
|
||||
detect-libcryptsetup.h:
|
||||
echo "#include <libcryptsetup.h>" > detect-libcryptsetup.h
|
||||
echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.h
|
||||
echo " #error libcryptsetup version 2.0.3 is required" >> detect-libcryptsetup.h
|
||||
echo "#endif" >> detect-libcryptsetup.h
|
||||
echo "int i = CRYPT_SLOT_UNBOUND;" >> detect-libcryptsetup.h
|
||||
|
||||
check-dep-zkey:
|
||||
$(call check_dep, \
|
||||
"zkey", \
|
||||
"openssl/evp.h", \
|
||||
"openssl-devel", \
|
||||
"HAVE_OPENSSL=0")
|
||||
|
||||
CPPFLAGS += -I../include
|
||||
LDLIBS += -ldl -lcrypto
|
||||
check-dep-zkey-cryptsetup: detect-libcryptsetup.h
|
||||
$(call check_dep, \
|
||||
"zkey-cryptsetup", \
|
||||
"detect-libcryptsetup.h", \
|
||||
"cryptsetup-devel version 2.0.3", \
|
||||
"HAVE_CRYPTSETUP2=0", \
|
||||
"-I.")
|
||||
$(call check_dep, \
|
||||
"zkey-cryptsetup", \
|
||||
"json-c/json.h", \
|
||||
"json-c-devel", \
|
||||
"HAVE_JSONC=0")
|
||||
|
||||
all: check_dep zkey
|
||||
zkey-skip:
|
||||
echo " SKIP zkey due to HAVE_OPENSSL=0"
|
||||
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
zkey-cryptsetup-skip-cryptsetup2:
|
||||
echo " SKIP zkey-cryptsetup due to HAVE_CRYPTSETUP2=0"
|
||||
|
||||
zkey-cryptsetup-skip-jsonc:
|
||||
echo " SKIP zkey-cryptsetup due to HAVE_JSONC=0"
|
||||
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
zkey.o: zkey.c pkey.h misc.h
|
||||
pkey.o: pkey.c pkey.h
|
||||
properties.o: properties.c properties.h
|
||||
properties.o: check-dep-zkey properties.c properties.h
|
||||
keystore.o: keystore.c keystore.h properties.h
|
||||
zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h misc.h
|
||||
|
||||
zkey: zkey.o pkey.o properties.o keystore.o $(libs)
|
||||
zkey: LDLIBS = -ldl -lcrypto
|
||||
zkey: zkey.o pkey.o properties.o keystore.o $(LIBS)
|
||||
|
||||
install: all
|
||||
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c
|
||||
zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(LIBS)
|
||||
|
||||
install-common:
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
install-zkey:
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1
|
||||
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey
|
||||
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository
|
||||
|
||||
endif
|
||||
install-zkey-cryptsetup:
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey-cryptsetup $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -m 644 -c zkey-cryptsetup.1 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
install: all install-common $(INSTALL_TARGETS)
|
||||
|
||||
clean:
|
||||
rm -f *.o zkey
|
||||
rm -f *.o zkey zkey-cryptsetup detect-libcryptsetup.h
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
586
zkey/keystore.c
586
zkey/keystore.c
File diff suppressed because it is too large
Load Diff
@@ -30,16 +30,17 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, size_t sector_size,
|
||||
size_t keybits, bool xts, const char *clear_key_file,
|
||||
int pkey_fd);
|
||||
const char *volume_type, int pkey_fd);
|
||||
|
||||
int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, size_t sector_size,
|
||||
const char *import_file);
|
||||
const char *import_file, const char *volume_type);
|
||||
|
||||
int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, long int sector_size);
|
||||
const char *apqns, long int sector_size,
|
||||
const char *volume_type);
|
||||
|
||||
int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
const char *newname);
|
||||
@@ -63,12 +64,14 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
|
||||
bool quiet);
|
||||
|
||||
int keystore_list_keys(struct keystore *keystore, const char *name_filter,
|
||||
const char *volume_filter, const char *apqn_filter);
|
||||
const char *volume_filter, const char *apqn_filter,
|
||||
const char *volume_type);
|
||||
|
||||
int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter,
|
||||
bool execute);
|
||||
bool execute, const char *volume_type);
|
||||
|
||||
int keystore_crypttab(struct keystore *keystore, const char *volume_filter);
|
||||
int keystore_crypttab(struct keystore *keystore, const char *volume_filter,
|
||||
const char *volume_type);
|
||||
|
||||
void keystore_free(struct keystore *keystore);
|
||||
|
||||
|
||||
158
zkey/pkey.c
158
zkey/pkey.c
@@ -11,11 +11,13 @@
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/if_alg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -25,6 +27,12 @@
|
||||
|
||||
#include "pkey.h"
|
||||
|
||||
#ifndef AF_ALG
|
||||
#define AF_ALG 38
|
||||
#endif
|
||||
#ifndef SOL_ALG
|
||||
#define SOL_ALG 279
|
||||
#endif
|
||||
|
||||
#define pr_verbose(verbose, fmt...) do { \
|
||||
if (verbose) \
|
||||
@@ -34,6 +42,8 @@
|
||||
#define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? 2 * (keysize) : (keysize))
|
||||
#define HALF_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? (keysize) / 2 : (keysize))
|
||||
|
||||
#define MAX_CIPHER_LEN 32
|
||||
|
||||
/*
|
||||
* Definitions for the CCA library
|
||||
*/
|
||||
@@ -367,6 +377,8 @@ int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
if (rc < 0) {
|
||||
rc = -errno;
|
||||
warnx("Failed to generate a secure key: %s", strerror(errno));
|
||||
warnx("Make sure that all available CCA crypto adapters are "
|
||||
"setup with the same master key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -378,6 +390,8 @@ int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
rc = -errno;
|
||||
warnx("Failed to generate a secure key: %s",
|
||||
strerror(errno));
|
||||
warnx("Make sure that all available CCA crypto "
|
||||
"adapters are setup with the same master key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -465,6 +479,8 @@ int generate_secure_key_clear(int pkey_fd, const char *keyfile,
|
||||
rc = -errno;
|
||||
warnx("Failed to generate a secure key from a "
|
||||
"clear key: %s", strerror(errno));
|
||||
warnx("Make sure that all available CCA crypto adapters are "
|
||||
"setup with the same master key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -479,6 +495,8 @@ int generate_secure_key_clear(int pkey_fd, const char *keyfile,
|
||||
rc = -errno;
|
||||
warnx("Failed to generate a secure key from "
|
||||
"a clear key: %s", strerror(errno));
|
||||
warnx("Make sure that all available CCA crypto "
|
||||
"adapters are setup with the same master key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -746,3 +764,143 @@ int validate_secure_key(int pkey_fd,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key verification pattern of a secure key by encrypting the all
|
||||
* zero message with the secure key using the AF_ALG interface
|
||||
*
|
||||
* @param[in] key the secure key token
|
||||
* @param[in] key_size the size of the secure key
|
||||
* @param[in] vp buffer where the verification pattern is returned
|
||||
* @param[in] vp_len the size of the buffer
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
int generate_key_verification_pattern(const char *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose)
|
||||
{
|
||||
int tfmfd = -1, opfd = -1, rc = 0;
|
||||
char null_msg[ENC_ZERO_LEN];
|
||||
char enc_zero[ENC_ZERO_LEN];
|
||||
struct af_alg_iv *alg_iv;
|
||||
struct cmsghdr *header;
|
||||
uint32_t *type;
|
||||
ssize_t len;
|
||||
size_t i;
|
||||
|
||||
struct sockaddr_alg sa = {
|
||||
.salg_family = AF_ALG,
|
||||
.salg_type = "skcipher",
|
||||
};
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)null_msg,
|
||||
.iov_len = sizeof(null_msg),
|
||||
};
|
||||
int iv_msg_size = CMSG_SPACE(sizeof(*alg_iv) + PAES_BLOCK_SIZE);
|
||||
char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size];
|
||||
struct msghdr msg = {
|
||||
.msg_control = buffer,
|
||||
.msg_controllen = sizeof(buffer),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
if (vp_len < VERIFICATION_PATTERN_LEN) {
|
||||
rc = -EMSGSIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)",
|
||||
key_size > SECURE_KEY_SIZE ? "xts" : "cbc");
|
||||
|
||||
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (tfmfd < 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "Failed to open an AF_ALG socket");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "Failed to bind the AF_ALG socket, "
|
||||
"salg_name='%s' ", sa.salg_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key,
|
||||
key_size) < 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "Failed to set the key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
opfd = accept(tfmfd, NULL, 0);
|
||||
if (opfd < 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "Failed to accept on the AF_ALG socket");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(null_msg, 0, sizeof(null_msg));
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
header = CMSG_FIRSTHDR(&msg);
|
||||
if (header == NULL) {
|
||||
pr_verbose(verbose, "Failed to obtain control message header");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
header->cmsg_level = SOL_ALG;
|
||||
header->cmsg_type = ALG_SET_OP;
|
||||
header->cmsg_len = CMSG_LEN(sizeof(*type));
|
||||
type = (void *)CMSG_DATA(header);
|
||||
*type = ALG_OP_ENCRYPT;
|
||||
|
||||
header = CMSG_NXTHDR(&msg, header);
|
||||
if (header == NULL) {
|
||||
pr_verbose(verbose, "Failed to obtain control message "
|
||||
"header");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
header->cmsg_level = SOL_ALG;
|
||||
header->cmsg_type = ALG_SET_IV;
|
||||
header->cmsg_len = iv_msg_size;
|
||||
alg_iv = (void *)CMSG_DATA(header);
|
||||
alg_iv->ivlen = PAES_BLOCK_SIZE;
|
||||
memcpy(alg_iv->iv, null_msg, PAES_BLOCK_SIZE);
|
||||
|
||||
len = sendmsg(opfd, &msg, 0);
|
||||
if (len != ENC_ZERO_LEN) {
|
||||
pr_verbose(verbose, "Failed to send to the AF_ALG socket");
|
||||
rc = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = read(opfd, enc_zero, sizeof(enc_zero));
|
||||
if (len != ENC_ZERO_LEN) {
|
||||
pr_verbose(verbose, "Failed to receive from the AF_ALG socket");
|
||||
rc = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(vp, 0, vp_len);
|
||||
for (i = 0; i < sizeof(enc_zero); i++)
|
||||
sprintf(&vp[i * 2], "%02x", enc_zero[i]);
|
||||
|
||||
pr_verbose(verbose, "Key verification pattern: %s", vp);
|
||||
|
||||
out:
|
||||
if (opfd != -1)
|
||||
close(opfd);
|
||||
if (tfmfd != -1)
|
||||
close(tfmfd);
|
||||
|
||||
if (rc != 0)
|
||||
pr_verbose(verbose, "Failed to generate the key verification "
|
||||
"pattern: %s", strerror(-rc));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,10 @@ typedef void (*t_CSNBKTC)(long *return_code,
|
||||
unsigned char *rule_array,
|
||||
unsigned char *key_identifier);
|
||||
|
||||
#define PAES_BLOCK_SIZE 16
|
||||
#define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE)
|
||||
#define VERIFICATION_PATTERN_LEN (2 * ENC_ZERO_LEN + 1)
|
||||
|
||||
int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose);
|
||||
|
||||
int open_pkey_device(bool verbose);
|
||||
@@ -122,4 +126,7 @@ int key_token_change(t_CSNBKTC dll_CSNBKTC,
|
||||
u8 *secure_key, unsigned int secure_key_size,
|
||||
char *method, bool verbose);
|
||||
|
||||
int generate_key_verification_pattern(const char *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -149,6 +149,7 @@ void properties_free(struct properties *properties)
|
||||
free(property->name);
|
||||
free(property->value);
|
||||
util_list_remove(&properties->list, property);
|
||||
free(property);
|
||||
}
|
||||
|
||||
free(properties);
|
||||
@@ -259,6 +260,7 @@ int properties_remove(struct properties *properties, const char *name)
|
||||
free(property->name);
|
||||
free(property->value);
|
||||
util_list_remove(&properties->list, property);
|
||||
free(property);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -614,10 +616,13 @@ char *str_list_remove(const char *str_list, const char *str)
|
||||
*/
|
||||
void str_list_free_string_array(char **strings)
|
||||
{
|
||||
char **list = strings;
|
||||
|
||||
util_assert(strings != NULL, "Internal error: strings is NULL");
|
||||
|
||||
while (*strings != NULL) {
|
||||
free((void *)*strings);
|
||||
strings++;
|
||||
}
|
||||
free(list);
|
||||
}
|
||||
|
||||
403
zkey/zkey-cryptsetup.1
Normal file
403
zkey/zkey-cryptsetup.1
Normal file
@@ -0,0 +1,403 @@
|
||||
.\" Copyright IBM Corp. 2018
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
.TH ZKEY\-CRYPTSETUP 1 "May 2018" "s390-tools"
|
||||
.SH NAME
|
||||
zkey\-cryptsetup \- Manage secure AES volume keys of volumes encrypted with
|
||||
\fBLUKS2\fP and the \fBpaes\fP cipher
|
||||
.
|
||||
.
|
||||
.SH SYNOPSIS
|
||||
.B zkey\-cryptsetup
|
||||
.I command
|
||||
.I device
|
||||
.RI [ OPTIONS ]
|
||||
.
|
||||
.PP
|
||||
.B zkey\-cryptsetup
|
||||
.RI [ command ]
|
||||
.BR \-\-help | \-h
|
||||
.br
|
||||
.B zkey\-cryptsetup
|
||||
.BR \-\-version | \-v
|
||||
.
|
||||
.
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
Use \fBzkey\-cryptsetup\fP to validate and re-encipher secure AES
|
||||
volume keys of volumes encrypted with \fBLUKS2\fP and the \fBpaes\fP cipher.
|
||||
These secure AES volume keys are enciphered with a master key of an IBM
|
||||
cryptographic adapter in CCA coprocessor mode.
|
||||
.PP
|
||||
To encrypt a volume using \fBLUKS2\fP and the \fBpaes\fP cipher, generate a
|
||||
secure AES key using \fBzkey\fP: \fB'zkey generate luks.key --xts'\fP.
|
||||
Then format the device with \fBcryptsetup\fP using the just generated secure
|
||||
AES key from file luks.key: \fB'cryptsetup luksFormat <device> --type luks2
|
||||
--cipher paes-xts-plain64 --master-key-file luks.key --key-size 1024'\fP. For
|
||||
more details about \fBzkey\fP or \fBcryptsetup\fP see the
|
||||
corresponding man pages.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SH COMMANDS
|
||||
.
|
||||
.
|
||||
.SS "Validate secure AES volume keys"
|
||||
.
|
||||
.B zkey\-cryptsetup
|
||||
.BR validate | val
|
||||
.I device
|
||||
.RB [ \-\-key\-file | \-d
|
||||
.IR file-name ]
|
||||
.RB [ \-\-keyfile\-offset | \-o
|
||||
.IR bytes ]
|
||||
.RB [ \-\-keyfile\-size | \-l
|
||||
.IR bytes ]
|
||||
.RB [ \-\-tries | \-T
|
||||
.IR number ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.RB [ \-\-debug | \-D ]
|
||||
.PP
|
||||
Use the
|
||||
.B validate
|
||||
command to validate a secure AES volume key of a volume encrypted with
|
||||
\fBLUKS2\fP and the \fBpaes\fP cipher.
|
||||
It checks if the LUKS2 header of the volume contains a valid secure key.
|
||||
It also displays the attributes of the secure key, such as key size, whether
|
||||
it is a secure key that can be used for the XTS cipher mode, and the master key
|
||||
register (CURRENT or OLD) with which the secure key is enciphered.
|
||||
For further information about master key registers, see the
|
||||
\fBreencipher\fP command.
|
||||
.PP
|
||||
To open a key slot contained in the LUKS2 header of the volume, a passphrase is
|
||||
required. You are prompted for the passphrase, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
is specified, the passphrase is read from the specified file. You can specify
|
||||
options
|
||||
.B \-\-keyfile\-offset
|
||||
and
|
||||
.B \-\-keyfile\-size
|
||||
to control which part of the key file is used as passphrase. These options
|
||||
behave in the same way as with \fBcryptsetup\fP.
|
||||
.
|
||||
.SS "Re-encipher secure AES volume keys"
|
||||
.
|
||||
.PP
|
||||
.B zkey\-cryptsetup
|
||||
.BR reencipher | re
|
||||
.I device
|
||||
.RB [ \-\-staged | \-s ]
|
||||
.RB [ \-\-in\-place | \-i ]
|
||||
.RB [ \-\-complete | \-c ]
|
||||
.RB [ \-\-key\-file | \-d
|
||||
.IR file-name ]
|
||||
.RB [ \-\-keyfile\-offset | \-o
|
||||
.IR bytes ]
|
||||
.RB [ \-\-keyfile\-size | \-l
|
||||
.IR bytes ]
|
||||
.RB [ \-\-tries | \-T
|
||||
.IR number ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.RB [ \-\-debug | \-D ]
|
||||
.PP
|
||||
Use the
|
||||
.B reencipher
|
||||
command to re-encipher a secure AES volume key of a volume encrypted with
|
||||
\fBLUKS2\fP and the \fBpaes\fP cipher. A secure AES volume key must be
|
||||
re-enciphered when the master key of the cryptographic adapter in CCA
|
||||
coprocessor mode changes.
|
||||
.PP
|
||||
The cryptographic adapter in CCA coprocessor mode has three different registers
|
||||
to store master keys:
|
||||
.RS 2
|
||||
.IP "\(bu" 2
|
||||
The \fBCURRENT\fP register contains the current master key.
|
||||
.
|
||||
.IP "\(bu" 2
|
||||
The \fBOLD\fP register contains the previously used master key.
|
||||
Secure keys enciphered with the master key contained in the \fBOLD\fP
|
||||
register can still be used until the master key is changed again.
|
||||
.
|
||||
.IP "\(bu" 2
|
||||
The \fBNEW\fP register contains the new master key to be set.
|
||||
The master key in the \fBNEW\fP register cannot be used until it is made
|
||||
the current master key. You can pro-actively re-encipher a secure key with the
|
||||
\fBNEW\fP master key before this key is made the \fBCURRENT\fP key.
|
||||
.RE
|
||||
.PP
|
||||
\fBzkey\-cryptsetup\fP automatically detects whether the secure volume key
|
||||
is currently enciphered with the master key in the \fBOLD\fP register or with
|
||||
the master key in the \fBCURRENT\fP register. If currently enciphered with the
|
||||
master key in the \fBOLD\fP register, it is re-enciphered with the master key
|
||||
in the \fBCURRENT\fP register. If it is currently enciphered with the master
|
||||
key in the \fBCURRENT\fP register, it is re-enciphered with the master key in
|
||||
the \fBNEW\fP register. If for this case the \fBNEW\fP register does not
|
||||
contain a valid master key, then the re-encipher operation fails.
|
||||
.PP
|
||||
Re-enciphering a secure volume key of a volume encrypted with
|
||||
\fBLUKS2\fP and the \fBpaes\fP cipher can be performed \fBin-place\fP, or in
|
||||
\fBstaged\fP mode.
|
||||
.PP
|
||||
\fB"In-place"\fP immediately replaces the secure volume key in the LUKS2
|
||||
header of the encrypted volume with the re-enciphered secure volume key.
|
||||
Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is performed in-place per
|
||||
default. You can use option \fB--in-place\fP to force an in-place
|
||||
re-enciphering for the \fBCURRENT\fP to \fBNEW\fP case. Be aware that
|
||||
an encrypted volume with a secure volume key that was re-enciphered in-place
|
||||
from \fBCURRENT\fP to \fBNEW\fP is no longer usable, until the new CCA master
|
||||
key has been made the current one.
|
||||
.PP
|
||||
\fBStaged\fP mode means that the re-enciphered secure volume key is stored in a
|
||||
separate (unbound) key slot in the LUKS2 header of the encrypted volume. Thus
|
||||
all key slots containing the current secure volume key are still valid at this
|
||||
point. Once the new CCA master key has been set (made active), you must rerun
|
||||
the reencipher command with option \fB--complete\fP to complete the staged
|
||||
re-enciphering. When completing the staged re-enciphering, the (unbound) key
|
||||
slot containing the re-enciphered secure volume key becomes the active
|
||||
key slot and, optionally, all key slots containing the old secure volume key
|
||||
are removed.
|
||||
Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is performed in staged mode per
|
||||
default. You can use option \fB--staged\fP to force a staged re-enciphering for
|
||||
the \fBOLD\fP to \fBCURRENT\fP case.
|
||||
.PP
|
||||
To open a key slot contained in the LUKS2 header of the volume, a passphrase is
|
||||
required. You are prompted for the passphrase, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
is specified, the passphrase is read from the specified file. You can specify
|
||||
options
|
||||
.B \-\-keyfile\-offset
|
||||
and
|
||||
.B \-\-keyfile\-size
|
||||
to control which part of the key file is used as passphrase. These options
|
||||
behave in the same way as with \fBcryptsetup\fP.
|
||||
.PP
|
||||
.B Note:
|
||||
The \fBreencipher\fP command requires the CCA host library (libcsulcca.so)
|
||||
to be installed.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Set a verification pattern of the secure AES volume key"
|
||||
.
|
||||
.B zkey\-cryptsetup
|
||||
.BR setvp | setv
|
||||
.I device
|
||||
.RB [ \-\-key\-file | \-d
|
||||
.IR file-name ]
|
||||
.RB [ \-\-keyfile\-offset | \-o
|
||||
.IR bytes ]
|
||||
.RB [ \-\-keyfile\-size | \-l
|
||||
.IR bytes ]
|
||||
.RB [ \-\-tries | \-T
|
||||
.IR number ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.RB [ \-\-debug | \-D ]
|
||||
.PP
|
||||
Use the
|
||||
.B setvp
|
||||
command to set a verification pattern of the secure AES volume key of a volume
|
||||
encrypted with \fBLUKS2\fP and the \fBpaes\fP cipher. The verification pattern
|
||||
identifies the effective key used to encrypt the volume's data.
|
||||
The verification pattern is stored in a token named
|
||||
\fBpaes-verification-pattern\fP in the LUKS2 header.
|
||||
.PP
|
||||
.B Note:
|
||||
Set the verification pattern right after formatting the volume using
|
||||
\fB'cryptsetup luksFormat'\fP.
|
||||
.PP
|
||||
To open a key slot contained in the LUKS2 header of the volume, a passphrase is
|
||||
required. You are prompted for the passphrase, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
is specified, the passphrase is read from the specified file. You can specify
|
||||
options
|
||||
.B \-\-keyfile\-offset
|
||||
and
|
||||
.B \-\-keyfile\-size
|
||||
to control which part of the key file is used as passphrase. These options
|
||||
behave in the same way as with \fBcryptsetup\fP.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Set a new secure AES volume key for a volume"
|
||||
.
|
||||
.B zkey\-cryptsetup
|
||||
.BR setkey | setk
|
||||
.I device
|
||||
.BR \-\-master\-key\-file | \-m
|
||||
.IR file-name
|
||||
.RB [ \-\-key\-file | \-d
|
||||
.IR file-name ]
|
||||
.RB [ \-\-keyfile\-offset | \-o
|
||||
.IR bytes ]
|
||||
.RB [ \-\-keyfile\-size | \-l
|
||||
.IR bytes ]
|
||||
.RB [ \-\-tries | \-T
|
||||
.IR number ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.RB [ \-\-debug | \-D ]
|
||||
.PP
|
||||
Use the
|
||||
.B setkey
|
||||
command to set a new secure AES volume key for a volume encrypted with
|
||||
\fBLUKS2\fP and the \fBpaes\fP cipher. Use this command to recover from an
|
||||
invalid secure AES volume key contained in the LUKS2 header.
|
||||
A secure AES volume key contained in the LUKS2 header can become invalid when
|
||||
the CCA master key is changed without re-enciphering the secure volume key.
|
||||
.PP
|
||||
You can recover the secure volume key only if you have a copy of the secure key
|
||||
in a file, and this copy was re-enciphered when the CCA master key has been
|
||||
changed. Thus, the copy of the secure key must be currently enciphered with the
|
||||
CCA master key in the CURRENT or OLD master key register.
|
||||
Specify the secure key file with option
|
||||
.B \-\-master\-key\-file
|
||||
to set this secure key as the new volume key.
|
||||
.PP
|
||||
In case the LUKS2 header of the volume contains a verification pattern token,
|
||||
it is used to ensure that the new volume key contains the same effective key.
|
||||
If no verification pattern token is available, then you are prompted to confirm
|
||||
that the specified secure key is the correct one.
|
||||
.B ATTENTION:
|
||||
If you set a wrong secure key you will loose all the data on the encrypted
|
||||
volume!
|
||||
.PP
|
||||
To open a key slot contained in the LUKS2 header of the volume, a passphrase is
|
||||
required. You are prompted for the passphrase, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
is specified, the passphrase is read from the specified file. You can specify
|
||||
options
|
||||
.B \-\-keyfile\-offset
|
||||
and
|
||||
.B \-\-keyfile\-size
|
||||
to control which part of the key file is used as passphrase. These options
|
||||
behave in the same way the same as with \fBcryptsetup\fP.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SH OPTIONS
|
||||
.
|
||||
.SS "Options for the reencipher command"
|
||||
.TP
|
||||
.BR \-i ", " \-\-in-place
|
||||
Forces an in-place re-enciphering of a secure volume key in the LUKS2
|
||||
header. This option immediately replaces the secure volume key in the LUKS2
|
||||
header of the encrypted volume with the re-enciphered secure volume key.
|
||||
Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is performed in-place per
|
||||
default.
|
||||
.TP
|
||||
.BR \-s ", " \-\-staged
|
||||
Forces that the re-enciphering of a secure volume key in the LUKS2
|
||||
header is performed in staged mode. Staged mode means that the re-enciphered
|
||||
secure volume key is stored in a separate (unbound) key slot in the LUKS2
|
||||
header of the encrypted volume. Thus all key slots containing the current
|
||||
secure volume key are still valid at this point. Once the new CCA master key
|
||||
has been set (made active), you must rerun the reencipher command with option
|
||||
\fB--complete\fP to complete the staged re-enciphering. Re-enciphering from
|
||||
\fBCURRENT\fP to \fBNEW\fP is performed in staged mode per default.
|
||||
.TP
|
||||
.BR \-p ", " \-\-complete
|
||||
Completes a staged re-enciphering. Use this option after the new CCA master key
|
||||
has been set (made active). When completing the staged re-enciphering, the
|
||||
(unbound) key slot containing the re-enciphered secure volume key becomes
|
||||
the active key slot and, optionally, all key slots containing the old secure
|
||||
volume key are removed.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Options for the setkey command"
|
||||
.TP
|
||||
.BR \-m ", " \-\-master\-key\-file\~\fIfile\-name\fP
|
||||
Specifies the name of a file containing the secure AES key that is set as the
|
||||
new volume key.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Options for supplying the passphrase"
|
||||
.TP
|
||||
.BR \-d ", " \-\-key\-file\~\fIfile\-name\fP
|
||||
Reads the passphrase from the specified file. If this option is omitted,
|
||||
or if the file\-name is \fI-\fP (a dash), then you are prompted to enter the
|
||||
passphrase interactively.
|
||||
.TP
|
||||
.BR \-o ", " \-\-keyfile\-offset\~\fIbytes\fP
|
||||
Specifies the number of bytes to skip before starting to read in the file
|
||||
specified with option \fB\-\-key\-file\fP. If omitted, the file is read
|
||||
from the beginning. When option \fB\-\-key\-file\fP is not specified, this
|
||||
option is ignored.
|
||||
.TP
|
||||
.BR \-l ", " \-\-keyfile\-size\~\fIbytes\fP
|
||||
Specifies the number of bytes to be read from the beginning of the file
|
||||
specified with option \fB\-\-key\-file\fP. If omitted, the file is read
|
||||
until the end. When \fB\-\-keyfile\-offset\fP is also specified, reading starts
|
||||
at the offset. When option \fB\-\-key\-file\fP is not specified, this option is
|
||||
ignored.
|
||||
.TP
|
||||
.BR \-T ", " \-\-tries\~\fInumber\fP
|
||||
Specifies how often the interactive input of the passphrase can be re-entered.
|
||||
The default is 3 times. When option \fB\-\-key\-file\fP is specified, this
|
||||
option is ignored, and the passphrase is read only once from the file.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "General options"
|
||||
.TP
|
||||
.BR \-V ", " \-\-verbose
|
||||
Displays additional information messages during processing.
|
||||
.TP
|
||||
.BR \-D ", " \-\-debug
|
||||
Displays additional debugging messages during processing. This option also
|
||||
implies \fB\-\-verbose\fP.
|
||||
.TP
|
||||
.BR \-h ", " \-\-help
|
||||
Displays help text and exits.
|
||||
.TP
|
||||
.BR \-v ", " \-\-version
|
||||
Displays version information and exits.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
.B zkey-cryptsetup reencipher /dev/dasdd1
|
||||
Re-enciphers the secure volume key of the encrypted volume /dev/dasdd1.
|
||||
.TP
|
||||
.B zkey-cryptsetup reencipher /dev/dasdd1 \-\-staged
|
||||
Re-enciphers the secure volume key of the encrypted volume /dev/dasdd1 in
|
||||
staged mode.
|
||||
.TP
|
||||
.B zkey-cryptsetup reencipher /dev/dasdd1 \-\-complete
|
||||
Completes re-enciphers the secure volume key of the encrypted
|
||||
volume /dev/dasdd1.
|
||||
.TP
|
||||
.B zkey-cryptsetup reencipher /dev/dasdd1 \-\-in\-place
|
||||
Re-enciphers the secure volume key of the encrypted volume /dev/dasdd1 in
|
||||
in-place mode.
|
||||
.TP
|
||||
.B zkey-cryptsetup validate /dev/dasdd1
|
||||
Validates the secure volume key of the encrypted volume /dev/dasdd1 and
|
||||
displays its attributes.
|
||||
.TP
|
||||
.B zkey-cryptsetup setvp /dev/dasdd1
|
||||
Sets the verification pattern of the secure volume key of the encrypted
|
||||
volume /dev/dasdd1.
|
||||
.TP
|
||||
.B zkey-cryptsetup setkey /dev/dasdd1 --master-key-file seckey.key
|
||||
Sets the secure key contained in file seckey.key as the new volume key
|
||||
for the encrypted volume /dev/dasdd1.
|
||||
2270
zkey/zkey-cryptsetup.c
Normal file
2270
zkey/zkey-cryptsetup.c
Normal file
File diff suppressed because it is too large
Load Diff
296
zkey/zkey.1
296
zkey/zkey.1
@@ -75,30 +75,32 @@ key repository.
|
||||
.BR generate | gen
|
||||
.I secure\-key\-file
|
||||
.RB [ \-\-keybits | \-k
|
||||
.IB size ]
|
||||
.IR size ]
|
||||
.RB [ \-\-xts | \-x ]
|
||||
.RB [ \-\-clearkey | \-c
|
||||
.IB clear\-key\-file ]
|
||||
.IR clear\-key\-file ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
.B zkey
|
||||
.BR generate | gen
|
||||
.B \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.RB [ \-\-description | \-d
|
||||
.IB description ]
|
||||
.IR description ]
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.IR volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.RB [ \-\-apqns | \-a
|
||||
.IB card1.domain1[,card2.domain2[,...]] ]
|
||||
.IR card1.domain1[,card2.domain2[,...]] ]
|
||||
.RB [ \-\-sector-size | \-S
|
||||
.IB bytes ]
|
||||
.IR bytes ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-keybits | \-k
|
||||
.IB size ]
|
||||
.IR size ]
|
||||
.RB [ \-\-xts | \-x ]
|
||||
.RB [ \-\-clearkey | \-c
|
||||
.IB clear\-key\-file ]
|
||||
.IR clear\-key\-file ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.PP
|
||||
Use the
|
||||
@@ -115,16 +117,16 @@ The generated secure key can either be stored in a file in the file system,
|
||||
or in the secure key repository. To store the generated secure key in a
|
||||
file, specify the file name with option \fIsecure\-key\-file\fP. To store the
|
||||
secure key in the secure key repository, specify the name of the key using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option. When storing the secure key in a key repository,
|
||||
additional information can be associated with a secure key using the
|
||||
.B --description
|
||||
.B \-\-description
|
||||
,
|
||||
.B --volumes
|
||||
.B \-\-volumes
|
||||
,
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
, or the
|
||||
.B --sector-size
|
||||
.B \-\-sector-size
|
||||
options.
|
||||
.
|
||||
.SS "Validating secure AES keys"
|
||||
@@ -138,7 +140,7 @@ options.
|
||||
.B zkey
|
||||
.BR validate | val
|
||||
.RB [ \-\-name | \-N
|
||||
.IB key-name ]
|
||||
.IR key-name ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.PP
|
||||
Use the
|
||||
@@ -156,10 +158,10 @@ secure key repository. To validate a secure key contained in a file, specify
|
||||
the file name with option \fIsecure\-key\-file\fP. To validate secure keys
|
||||
contained in the secure key repository, specify the name of the key
|
||||
or a pattern containing wildcards using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option. When wildcards are used you must quote the value.
|
||||
If neither option \fIsecure\-key\-file\fP nor option
|
||||
.B --name
|
||||
.B \-\-name
|
||||
are specified, then all secure keys contained in the key repository
|
||||
are validated.
|
||||
.
|
||||
@@ -171,15 +173,15 @@ are validated.
|
||||
.RB [ \-\-to\-new | \-n ]
|
||||
.RB [ \-\-from\-old | \-o ]
|
||||
.RB [ \-\-output | \-f
|
||||
.IB output\-file ]
|
||||
.IR output\-file ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.PP
|
||||
.B zkey
|
||||
.BR reencipher | re
|
||||
.RB [ \-\-name | \-N
|
||||
.IB key-name ]
|
||||
.IR key-name ]
|
||||
.RB [ \-\-apqns | \-a
|
||||
.IB card1.domain1[,card2.domain2[,...]] ]
|
||||
.IR card1.domain1[,card2.domain2[,...]] ]
|
||||
.RB [ \-\-to\-new | \-n ]
|
||||
.RB [ \-\-from\-old | \-o ]
|
||||
.RB [ \-\-in-place | \-i ]
|
||||
@@ -190,7 +192,7 @@ are validated.
|
||||
Use the
|
||||
.B reencipher
|
||||
command to re-encipher an existing secure key with a new master key.
|
||||
A secure key bust be re-enciphered when the master key of the CCA
|
||||
A secure key must be re-enciphered when the master key of the CCA
|
||||
cryptographic adapter changes.
|
||||
.PP
|
||||
The CCA cryptographic adapter has three different registers to store
|
||||
@@ -243,18 +245,18 @@ secure key repository. To re-encipher a secure key contained in a file,
|
||||
specify the file name with option \fIsecure\-key\-file\fP. To re-encipher
|
||||
secure keys contained in the secure key repository, specify the name of the key
|
||||
or a pattern containing wildcards using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option. When wildcards are used you must quote the value.
|
||||
You can also specify the
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
option to re-encipher those secure
|
||||
keys which are associated with the specified cryptographic adapters (APQNs).
|
||||
You can use wildcards for the APQN specification.
|
||||
When wildcards are used you must quote the value.
|
||||
If both option
|
||||
.B --name
|
||||
.B \-\-name
|
||||
and option
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
are specified then all secure keys
|
||||
contained in the key repository that match both patterns are re-enciphered.
|
||||
If all both options are omitted, then all secure keys contained in the key
|
||||
@@ -265,7 +267,7 @@ performed \fBin-place\fP, or in \fBstaged\fP mode.
|
||||
.PP
|
||||
\fB"In-place"\fP immediately replaces the secure key in the repository with
|
||||
the re-enciphered secure key. Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is
|
||||
performed in-place per default. You can use option \fB--in-place\fP to force an
|
||||
performed in-place per default. You can use option \fB\-\-in-place\fP to force an
|
||||
in-place re-enciphering for the \fBCURRENT\fP to \fBNEW\fP case. Be aware that
|
||||
a secure key that was re-enciphered in-place from \fBCURRENT\fP to \fBNEW\fP
|
||||
is no longer valid, until the new CCA master key has been made the current one.
|
||||
@@ -273,9 +275,9 @@ is no longer valid, until the new CCA master key has been made the current one.
|
||||
\fBStaged\fP mode means that the re-enciphered secure key is stored in a
|
||||
separate file in the secure key repository. Thus the current secure key is still
|
||||
valid at this point. Once the new CCA master key has been set (made active), you
|
||||
must rerun the reencipher command with option \fB--complete\fP to complete the
|
||||
must rerun the reencipher command with option \fB\-\-complete\fP to complete the
|
||||
staged re-enciphering. Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is
|
||||
performed in staged mode per default. You can use option \fB--staged\fP to force
|
||||
performed in staged mode per default. You can use option \fB\-\-staged\fP to force
|
||||
a staged re-enciphering for the \fBOLD\fP to \fBCURRENT\fP case.
|
||||
.PP
|
||||
.B Note:
|
||||
@@ -288,15 +290,17 @@ to be installed.
|
||||
.BR import | im
|
||||
.I secure\-key\-file
|
||||
.B \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.RB [ \-\-description | \-d
|
||||
.IB description ]
|
||||
.IR description ]
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.IR volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.RB [ \-\-apqns | \-a
|
||||
.IB card1.domain1[,card2.domain2[,...]] ]
|
||||
.IR card1.domain1[,card2.domain2[,...]] ]
|
||||
.RB [ \-\-sector-size | \-S
|
||||
.IB bytes ]
|
||||
.IR bytes ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -305,13 +309,13 @@ Use the
|
||||
command to import an existing secure key contained in a file into the the
|
||||
secure key repository. When importing a secure key in a key repository,
|
||||
additional information can be associated with a secure key using the
|
||||
.B --description
|
||||
.B \-\-description
|
||||
,
|
||||
.B --volumes
|
||||
.B \-\-volumes
|
||||
,
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
, or the
|
||||
.B --sector-size
|
||||
.B \-\-sector-size
|
||||
options.
|
||||
.
|
||||
.SS "Export AES secure keys from the secure key repository"
|
||||
@@ -320,7 +324,7 @@ options.
|
||||
.BR export | ex
|
||||
.I secure\-key\-file
|
||||
.B \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -329,7 +333,7 @@ Use the
|
||||
command to export an existing secure key contained in the secure key repository
|
||||
to a file in the file system. Specify the name of the key that is to be exported
|
||||
using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option. You cannot use wildcards.
|
||||
When wildcards are used you must quote the value.
|
||||
The exported secure key also remains in the secure key repository.
|
||||
@@ -339,20 +343,22 @@ The exported secure key also remains in the secure key repository.
|
||||
.B zkey
|
||||
.BR list | li
|
||||
.RB [ \-\-name | \-N
|
||||
.IB key-name ]
|
||||
.IR key-name ]
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB volume1[:dmname1][,volume2[:dmname2][,...]] ]
|
||||
.IR volume1[:dmname1][,volume2[:dmname2][,...]] ]
|
||||
.RB [ \-\-apqns | \-a
|
||||
.IB card1.domain1[,card2.domain2[,...]] ]
|
||||
.IR card1.domain1[,card2.domain2[,...]] ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
Use the
|
||||
.B list
|
||||
command to display a list of secure keys contained in the secure key repository.
|
||||
You can filter the displayed list by key name, associated volumes, and
|
||||
associated cryptographic adapters (APQNs). You can use wildcards for the key
|
||||
name, associated APQNs, and associated volumes. The device-mapper name of an
|
||||
You can filter the displayed list by key name, associated volumes, associated
|
||||
cryptographic adapters (APQNs), and volume type. You can use wildcards for the
|
||||
key name, associated APQNs, and associated volumes. The device-mapper name of an
|
||||
associated volume can be omitted; if it is specified then only those keys are
|
||||
listed that are associated with the specified volume and device-mapper name.
|
||||
.PP
|
||||
@@ -361,15 +367,15 @@ The
|
||||
command displays the attributes of the secure keys, such as key sizes,
|
||||
whether it is a secure key that can be used for the XTS cipher mode, the textual
|
||||
description, associated cryptographic adapters (APQNs) and volumes, the
|
||||
sector size, and timestamps for key creation, last modification and last
|
||||
re-encipherment.
|
||||
sector size, the key verification pattern, and timestamps for key creation, last
|
||||
modification and last re-encipherment.
|
||||
.
|
||||
.SS "Remove existing AES secure keys from the secure key repository"
|
||||
.
|
||||
.B zkey
|
||||
.BR remove | rem
|
||||
.B \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.RB [ \-\-force | \-F ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
@@ -378,10 +384,10 @@ Use the
|
||||
.B remove
|
||||
command to remove an existing secure key from the secure key repository.
|
||||
Specify the name of the key that is to be removed using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option. You cannot use wildcards. The remove command prompts for
|
||||
a confirmation, unless you specify the
|
||||
.B --force
|
||||
.B \-\-force
|
||||
option.
|
||||
.PP
|
||||
.B Note:
|
||||
@@ -395,43 +401,45 @@ secure key.
|
||||
.B zkey
|
||||
.BR change | ch
|
||||
.B \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.RB [ \-\-description | \-d
|
||||
.IB description ]
|
||||
.IR description ]
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB [+|-]volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.IR [+|-]volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.RB [ \-\-apqns | \-a
|
||||
.IB [+|-]card1.domain1[,card2.domain2[,...]] ]
|
||||
.IR [+|-]card1.domain1[,card2.domain2[,...]] ]
|
||||
.RB [ \-\-sector-size | \-S
|
||||
.IB bytes ]
|
||||
.IR bytes ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
Use the
|
||||
.B change
|
||||
command to change the description, the associated volumes, the associated
|
||||
cryptographic adapters (APQNs), and the sector size of a secure key contained
|
||||
in the secure key repository. Specify the name of the key that is to be changed
|
||||
using the
|
||||
.B --name
|
||||
cryptographic adapters (APQNs), the sector size, and the volume type of a secure
|
||||
key contained in the secure key repository. Specify the name of the key that is
|
||||
to be changed using the
|
||||
.B \-\-name
|
||||
option. You cannot use wildcards.
|
||||
.PP
|
||||
You can set (replace), add, or
|
||||
remove volume and cryptographic adapters (APQN) associations. To set
|
||||
(replace) an association, specify the association with the
|
||||
.B --volumes
|
||||
.B \-\-volumes
|
||||
or the
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
options. To add an association,
|
||||
specify the new association prefixed with a \fI+\fP with the
|
||||
.B --volumes
|
||||
.B \-\-volumes
|
||||
or the
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
options. To remove an association,
|
||||
specify the association to remove prefixed with a \fI-\fP with the
|
||||
.B --volumes
|
||||
.B \-\-volumes
|
||||
or the
|
||||
.B --apqns
|
||||
.B \-\-apqns
|
||||
options. You cannot mix \fI+\fP and
|
||||
\fI-\fP in one specification. You can either add or remove (or set) the
|
||||
associations with one command.
|
||||
@@ -447,9 +455,9 @@ command.
|
||||
.B zkey
|
||||
.BR rename | ren
|
||||
.B \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.B \-\-new-name | \-w
|
||||
.IB new-key-name
|
||||
.IR new-key-name
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -457,9 +465,9 @@ Use the
|
||||
.B rename
|
||||
command to rename an existing secure key in the secure key repository.
|
||||
Specify the name of the key that is to be renamed using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option and the new name using the
|
||||
.B --new-name
|
||||
.B \-\-new-name
|
||||
option. You cannot use wildcards.
|
||||
.
|
||||
.SS "Copy (duplicate) existing AES secure keys in the secure key repository"
|
||||
@@ -467,11 +475,11 @@ option. You cannot use wildcards.
|
||||
.B zkey
|
||||
.B copy | co
|
||||
.RB \-\-name | \-N
|
||||
.IB key-name
|
||||
.IR key-name
|
||||
.B \-\-new-key-name | \-w
|
||||
.IB new-name
|
||||
.IR new-name
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.IR volume1:dmname1[,volume2:dmname2[,...]] ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -479,15 +487,15 @@ Use the
|
||||
.B copy
|
||||
command to copy (duplicate) an existing secure key in the secure key repository.
|
||||
Specify the name of the key that is to be copied using the
|
||||
.B --name
|
||||
.B \-\-name
|
||||
option and the name of the copied key using the
|
||||
.B --new-name
|
||||
.B \-\-new-name
|
||||
option. You cannot use wildcards.
|
||||
.PP
|
||||
.B Note:
|
||||
When copying a secure key, the volume associations are not copied, because
|
||||
a specific volume can only be associated with a single secure key. Specify the
|
||||
.B --volumes
|
||||
.B \-\-volumes
|
||||
option to associate different
|
||||
volumes with the copied secure key, or use the \fBchange\fP command to associate
|
||||
volumes afterwards.
|
||||
@@ -497,45 +505,56 @@ volumes afterwards.
|
||||
.B zkey
|
||||
.BR crypttab | cryptt
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB volume1[:dmname1][,volume2[:dmname2][,...]] ]
|
||||
.IR volume1[:dmname1][,volume2[:dmname2][,...]] ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
Use the
|
||||
.B crypttab
|
||||
command to generate crypttab entries using the \fBplain\fP dm-crypt mode
|
||||
for volumes that are associated with secure keys contained in the secure key
|
||||
repository. Specify the
|
||||
.B --volumes
|
||||
command to generate crypttab entries using the \fBplain\fP or \fBLUKS2\fP
|
||||
dm-crypt mode for volumes that are associated with secure keys contained in the
|
||||
secure key repository. Specify the
|
||||
.B \-\-volumes
|
||||
option to limit the list
|
||||
of volumes where crypttab entries are generated for. You can use wildcards.
|
||||
When wildcards are used you must quote the value.
|
||||
The device-mapper name of an associated volume can be omitted; if it is
|
||||
specified then only those volumes with the specified volume and device-mapper
|
||||
name are selected.
|
||||
Specify the
|
||||
.B \-\-volume-type
|
||||
option to generate crypttab entries for the specified volume type only.
|
||||
.
|
||||
.SS "Generate cryptsetup commands for volumes associated with secure AES keys"
|
||||
.
|
||||
.B zkey
|
||||
.BR cryptsetup | crypts
|
||||
.RB [ \-\-volumes | \-l
|
||||
.IB volume1[:dmname1][,volume2[:dmname2][,...]] ]
|
||||
.IR volume1[:dmname1][,volume2[:dmname2][,...]] ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-run | \-r ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
Use the
|
||||
.B cryptsetup
|
||||
command to generate \fBcryptsetup plainOpen\fP commands for volumes that are
|
||||
associated with secure keys contained in the secure key repository. Specify the
|
||||
.B --volumes
|
||||
command to generate \fBcryptsetup plainOpen\fP or \fBcryptsetup luksFormat\fP
|
||||
commands for volumes that are associated with secure keys contained in the
|
||||
secure key repository. Specify the
|
||||
.B \-\-volumes
|
||||
option to limit the list
|
||||
of volumes where cryptsetup commands are generated for. You can use wildcards.
|
||||
When wildcards are used you must quote the value.
|
||||
The device-mapper name of an associated volume can be omitted; if it is
|
||||
specified then only those volumes with the specified volume and device-mapper
|
||||
name are selected. Specify the
|
||||
.B --run
|
||||
.B \-\-volume-type
|
||||
option to generate cryptsetup commands for the specified volume type only.
|
||||
Specify the
|
||||
.B \-\-run
|
||||
option to run the generated cryptsetup commands.
|
||||
.
|
||||
.
|
||||
@@ -589,8 +608,17 @@ This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
|
||||
Specifies the sector size in bytes used with dm-crypt. It must be a power of two
|
||||
and in the range 512 - 4096 bytes. If omitted, the system default sector size
|
||||
is used.
|
||||
and in the range of 512 to 4096 bytes. If omitted, the system default sector
|
||||
size is used.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-t ", " \-\-volume-type\~\fItype\fP
|
||||
Specifies the volume type of the associated volumes used with dm-crypt. Possible
|
||||
values are \fBplain\fP and \fBluks2\fP. If omitted, \fBluks2\fP is used.
|
||||
This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
|
||||
the default volume type is \fBplain\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
@@ -650,7 +678,7 @@ repository is performed in staged mode. Staged mode means that the re-enciphered
|
||||
secure key is stored in a separate file in the secure key repository. Thus the
|
||||
current secure key is still valid at this point. Once the new CCA master key has
|
||||
been set (made active), you must rerun the reencipher command with option
|
||||
\fB--complete\fP to complete the staged re-enciphering.
|
||||
\fB\-\-complete\fP to complete the staged re-enciphering.
|
||||
Re-enciphering from CURRENT to NEW is performed in staged mode per default.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
@@ -690,8 +718,17 @@ This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
|
||||
Specifies the sector size in bytes used with dm-crypt. It must be a power of two
|
||||
and in the range 512 - 4096 bytes. If omitted, the system default sector size
|
||||
is used.
|
||||
and in the range of 512 to 4096 bytes. If omitted, the system default sector
|
||||
size is used.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-t ", " \-\-volume-type\~\fItype\fP
|
||||
Specifies the volume type of the associated volumes used with dm-crypt. Possible
|
||||
values are \fBplain\fP and \fBluks2\fP. If omitted, \fBluks2\fP is used.
|
||||
This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
|
||||
the default volume type is \fBplain\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
@@ -734,6 +771,15 @@ APQNs. Each APQN association specifies a card and domain number separated
|
||||
by a period (like lszcrypt displays it). You can use wildcards in the APQN
|
||||
specification.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-t ", " \-\-volume-type\~\fItype\fP
|
||||
Specifies the volume type of the associated volumes used with dm-crypt. Possible
|
||||
values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume
|
||||
type are listed.
|
||||
This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
.
|
||||
@@ -791,9 +837,16 @@ This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
|
||||
Specifies the sector size in bytes used with dm-crypt. It must be a power of two
|
||||
and in the range 512 - 4096 bytes. If omitted, the system default sector size
|
||||
is used. Specify \fI0\fP to un-set the sector size so that the system default
|
||||
is used.
|
||||
and in the range of 512 to 4096 bytes. Specify \fI0\fP to set the sector size
|
||||
to the system default.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-t ", " \-\-volume-type\~\fItype\fP
|
||||
Specifies the volume type of the associated volumes used with dm-crypt. Possible
|
||||
values are \fBplain\fP and \fBluks2\fP.
|
||||
This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
@@ -845,6 +898,15 @@ specified volume and device-mapper name. You can use wildcards to specify
|
||||
the volumes and device-mapper names.
|
||||
When wildcards are used you must quote the value.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-t ", " \-\-volume-type\~\fItype\fP
|
||||
Specifies the volume type of the associated volumes used with dm-crypt. Possible
|
||||
values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume
|
||||
type are selected to generate crypttab entries for.
|
||||
This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
.
|
||||
@@ -861,10 +923,18 @@ the volumes and device-mapper names.
|
||||
When wildcards are used you must quote the value.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-r ", " \-\-run\fP
|
||||
Runs the generated cryptsetup commands. When an execution of a cryptsetup
|
||||
command fails, no further cryptsetup commands are executed, and zkey ends
|
||||
with an error.
|
||||
.BR \-t ", " \-\-volume-type\~\fItype\fP
|
||||
Specifies the volume type of the associated volumes used with dm-crypt. Possible
|
||||
values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume
|
||||
type are selected to generate cryptsetup commands for.
|
||||
This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-r ", " \-\-run
|
||||
Runs the generated cryptsetup commands. When one of the cryptsetup command fail,
|
||||
no further cryptsetup commands are run, and zkey ends with an error.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
@@ -895,15 +965,20 @@ in file 'seckey.bin'.
|
||||
Generates a secure AES key from the clear key in file 'clearkey.bin' and
|
||||
stores it in file 'seckey.bin'.
|
||||
.TP
|
||||
.B zkey generate --name seckey
|
||||
.B zkey generate \-\-name seckey
|
||||
Generates a random 256-bit secure AES key and stores it in the secure key
|
||||
repository under the name 'seckey'.
|
||||
repository using the name 'seckey'.
|
||||
.TP
|
||||
.B zkey generate --name seckey --volumes /dev/dasdc1:encvol --apqns 03.004c
|
||||
.B zkey generate \-\-name seckey \-\-volumes /dev/dasdc1:encvol \-\-apqns 03.004c
|
||||
Generates a random 256-bit secure AES key and stores it in the secure key
|
||||
repository under the name 'seckey' and associates it with block
|
||||
repository using the name 'seckey' and associates it with block
|
||||
device '/dev/dasdc1' and device-mapper name 'encvol', and APQN '03.004c'.
|
||||
.TP
|
||||
.B zkey generate \-\-name seckey \-\-volumes /dev/dasdc1:encvol \-\-volume-type luks2
|
||||
Generates a random 256-bit secure AES key and stores it in the secure key
|
||||
repository using the name 'seckey' and associates it with block
|
||||
device '/dev/dasdc1' and device-mapper name 'encvol', and a volume type of luks2.
|
||||
.TP
|
||||
.B zkey reencipher seckey.bin \-\-from\-old
|
||||
Re-enciphers the secure key in file 'seckey.bin' which is currently enciphered
|
||||
with the master key in the OLD register with the master key in the CURRENT
|
||||
@@ -915,17 +990,17 @@ Re-enciphers the secure key in file 'seckey.bin' which is currently enciphered
|
||||
with the master key in the CURRENT register with the master key in the NEW
|
||||
register, and saves the re-enciphered secure key to file 'seckey2.bin'.
|
||||
.TP
|
||||
.B zkey reencipher --name seckey
|
||||
.B zkey reencipher \-\-name seckey
|
||||
Re-enciphers the secure key 'seckey' in the secure key repository.
|
||||
.TP
|
||||
.B zkey reencipher --apqns 03.004c
|
||||
.B zkey reencipher \-\-apqns 03.004c
|
||||
Re-enciphers all secure keys contained in the secure key repository that are
|
||||
associated with APQN '03.004c'.
|
||||
.TP
|
||||
.B zkey validate seckey.bin
|
||||
Validates the secure key in file 'seckey.bin' and displays its attributes.
|
||||
.TP
|
||||
.B zkey validate --name seckey
|
||||
.B zkey validate \-\-name seckey
|
||||
Validates the secure key 'seckey' in the secure key repository and displays its
|
||||
attributes.
|
||||
.TP
|
||||
@@ -933,25 +1008,28 @@ attributes.
|
||||
Lists all secure keys in the secure key repository and displays its
|
||||
attributes.
|
||||
.TP
|
||||
.B zkey list --name '*key'
|
||||
.B zkey list \-\-name '*key'
|
||||
Lists all secure keys in the secure key repository with names ending with 'key'
|
||||
and displays its attributes.
|
||||
.TP
|
||||
.B zkey change --name seckey --volumes +/dev/dasdc2:encvol2
|
||||
.B zkey change \-\-name seckey \-\-volumes +/dev/dasdc2:encvol2
|
||||
Changes the secure key 'seckey' in the secure key repository and adds
|
||||
volume '/dev/dasdc2' with device-mapper name 'encvol2' to the list of associated
|
||||
volumes of this secure key.
|
||||
.TP
|
||||
.B zkey change --name seckey --apqns -03.004c
|
||||
.B zkey change \-\-name seckey \-\-apqns -03.004c
|
||||
Changes the secure key 'seckey' in the secure key repository and removes
|
||||
APQN '03.004c' from the list of associated APQNs of this secure key.
|
||||
.TP
|
||||
.B zkey crypttab --volumes '/dev/dasdc*'
|
||||
.B zkey crypttab \-\-volumes '/dev/dasdc*'
|
||||
Generates crypttab entries for all volumes that match the pattern '/dev/dasdc*'.
|
||||
.TP
|
||||
.B zkey cryptsetup --volumes '*:enc_dasd'
|
||||
.B zkey cryptsetup \-\-volumes '*:enc_dasd'
|
||||
Generates cryptsetup commands for the volumes that uses the device-mapper
|
||||
name 'enc_dasd'.
|
||||
.TP
|
||||
.B zkey cryptsetup \-\-volume-type luks2
|
||||
Generates cryptsetup commands for all volumes of type luks2.
|
||||
.
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
|
||||
127
zkey/zkey.c
127
zkey/zkey.c
@@ -68,6 +68,7 @@ static struct zkey_globals {
|
||||
char *volumes;
|
||||
char *apqns;
|
||||
long int sector_size;
|
||||
char *volume_type;
|
||||
char *newname;
|
||||
bool run;
|
||||
bool force;
|
||||
@@ -180,6 +181,16 @@ static struct util_opt opt_vec[] = {
|
||||
"used",
|
||||
.command = COMMAND_GENERATE,
|
||||
},
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
{
|
||||
.option = { "volume-type", required_argument, NULL, 't'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the associated volume(s). Possible values "
|
||||
"are 'plain' and 'luks2'. When this option is omitted, "
|
||||
"the default is 'luks2'",
|
||||
.command = COMMAND_GENERATE,
|
||||
},
|
||||
#endif
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -211,19 +222,23 @@ static struct util_opt opt_vec[] = {
|
||||
},
|
||||
{
|
||||
.option = {"complete", 0, NULL, 'p'},
|
||||
.desc = "Completes a pending re-enciphering of a secure AES "
|
||||
"key that was re-enciphered with the master key in the "
|
||||
"NEW register",
|
||||
.desc = "Completes a staged re-enciphering. Use this option "
|
||||
"after the new CCA master key has been set (made "
|
||||
"active)",
|
||||
.command = COMMAND_REENCIPHER,
|
||||
},
|
||||
{
|
||||
.option = {"in-place", 0, NULL, 'i'},
|
||||
.desc = "Forces an in-place re-enchipering of a secure AES key",
|
||||
.desc = "Forces an in-place re-enchipering of a secure AES "
|
||||
"key. Re-enciphering from OLD to CURRENT is performed "
|
||||
"in-place per default",
|
||||
.command = COMMAND_REENCIPHER,
|
||||
},
|
||||
{
|
||||
.option = {"staged", 0, NULL, 's'},
|
||||
.desc = "Forces a staged re-enchipering of a secure AES key",
|
||||
.desc = "Forces that the re-enciphering of a secure AES key is "
|
||||
"performed in staged mode. Re-enciphering from CURRENT "
|
||||
"to NEW is performed in staged mode per default",
|
||||
.command = COMMAND_REENCIPHER,
|
||||
},
|
||||
{
|
||||
@@ -310,6 +325,16 @@ static struct util_opt opt_vec[] = {
|
||||
"used",
|
||||
.command = COMMAND_IMPORT,
|
||||
},
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
{
|
||||
.option = { "volume-type", required_argument, NULL, 't'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the associated volume(s). Possible values "
|
||||
"are 'plain' and 'luks2'. When this option is omitted, "
|
||||
"the default is 'luks2'",
|
||||
.command = COMMAND_IMPORT,
|
||||
},
|
||||
#endif
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -358,6 +383,16 @@ static struct util_opt opt_vec[] = {
|
||||
"associated with specific crypto cards",
|
||||
.command = COMMAND_LIST,
|
||||
},
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
{
|
||||
.option = { "volume-type", required_argument, NULL, 't'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the associated volume(s). Possible values "
|
||||
"are 'plain' and 'luks2'. Use this option to list all "
|
||||
"keys with the specified volumes type.",
|
||||
.command = COMMAND_LIST,
|
||||
},
|
||||
#endif
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -422,11 +457,19 @@ static struct util_opt opt_vec[] = {
|
||||
.option = { "sector-size", required_argument, NULL, 'S'},
|
||||
.argument = "0|512|4096",
|
||||
.desc = "The sector size used with dm-crypt. It must be power "
|
||||
"of two and in range 512 - 4096 bytes. If this option "
|
||||
"is omitted, the system default sector size (512) is "
|
||||
"used",
|
||||
"of two and in range 512 - 4096 bytes. Specify 0 to "
|
||||
"use the system default sector size (512)",
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
{
|
||||
.option = { "volume-type", required_argument, NULL, 't'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the associated volume(s). Possible values "
|
||||
"are 'plain' and 'luks2'",
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
#endif
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -494,6 +537,17 @@ static struct util_opt opt_vec[] = {
|
||||
"volume and the device-mapper name matches",
|
||||
.command = COMMAND_CRYPTTAB,
|
||||
},
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
{
|
||||
.option = { "volume-type", required_argument, NULL, 't'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the associated volume(s). Possible values "
|
||||
"are 'plain' and 'luks2'. Use this option to select "
|
||||
"the keys by its volume type for which a crypttab "
|
||||
"entry is to be generated",
|
||||
.command = COMMAND_CRYPTTAB,
|
||||
},
|
||||
#endif
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -512,6 +566,17 @@ static struct util_opt opt_vec[] = {
|
||||
"both, the volume and the device-mapper name matches",
|
||||
.command = COMMAND_CRYPTSETUP,
|
||||
},
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
{
|
||||
.option = { "volume-type", required_argument, NULL, 't'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the associated volume(s). Possible values "
|
||||
"are 'plain' and 'luks2'. Use this option to select "
|
||||
"the keys by its volume type for which a crypttab "
|
||||
"entry is to be generated",
|
||||
.command = COMMAND_CRYPTSETUP,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.option = {"run", 0, NULL, 'r'},
|
||||
.desc = "Runs the generated cryptsetup command",
|
||||
@@ -819,7 +884,7 @@ static int command_generate_repository(void)
|
||||
|
||||
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.sector_size, g.keybits, g.xts,
|
||||
g.clearkeyfile, g.pkey_fd);
|
||||
g.clearkeyfile, g.volume_type, g.pkey_fd);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1057,6 +1122,7 @@ static int command_reencipher(void)
|
||||
*/
|
||||
static int command_validate_file(void)
|
||||
{
|
||||
char vp[VERIFICATION_PATTERN_LEN];
|
||||
size_t secure_key_size;
|
||||
size_t clear_key_size;
|
||||
u8 *secure_key;
|
||||
@@ -1089,14 +1155,30 @@ static int command_validate_file(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = generate_key_verification_pattern((char *)secure_key,
|
||||
secure_key_size, vp, sizeof(vp),
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the verification pattern: %s",
|
||||
strerror(-rc));
|
||||
warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
||||
"that the 'paes' cipher is available");
|
||||
rc = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Validation of secure key in file '%s':\n", g.pos_arg);
|
||||
printf(" Status: Valid\n");
|
||||
printf(" Secure key size: %lu bytes\n", secure_key_size);
|
||||
printf(" Clear key size: %lu bits\n", clear_key_size);
|
||||
printf(" XTS type key: %s\n",
|
||||
printf(" Status: Valid\n");
|
||||
printf(" Secure key size: %lu bytes\n", secure_key_size);
|
||||
printf(" Clear key size: %lu bits\n", clear_key_size);
|
||||
printf(" XTS type key: %s\n",
|
||||
secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No");
|
||||
printf(" Encrypted with: %s CCA master key\n",
|
||||
printf(" Enciphered with: %s CCA master key\n",
|
||||
is_old_mk ? "OLD" : "CURRENT");
|
||||
printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
||||
vp);
|
||||
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
||||
&vp[VERIFICATION_PATTERN_LEN / 2]);
|
||||
|
||||
out:
|
||||
free(secure_key);
|
||||
@@ -1150,7 +1232,8 @@ static int command_import(void)
|
||||
g.sector_size = 0;
|
||||
|
||||
rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.sector_size, g.pos_arg);
|
||||
g.apqns, g.sector_size, g.pos_arg,
|
||||
g.volume_type);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1183,7 +1266,8 @@ static int command_list(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns);
|
||||
rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns,
|
||||
g.volume_type);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1222,7 +1306,7 @@ static int command_change(void)
|
||||
}
|
||||
|
||||
rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.sector_size);
|
||||
g.apqns, g.sector_size, g.volume_type);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1282,7 +1366,7 @@ static int command_crypttab(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = keystore_crypttab(g.keystore, g.volumes);
|
||||
rc = keystore_crypttab(g.keystore, g.volumes, g.volume_type);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1296,7 +1380,7 @@ static int command_cryptsetup(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = keystore_cryptsetup(g.keystore, g.volumes, g.run);
|
||||
rc = keystore_cryptsetup(g.keystore, g.volumes, g.run, g.volume_type);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1473,6 +1557,11 @@ int main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_LUKS2_SUPPORT
|
||||
case 't':
|
||||
g.volume_type = optarg;
|
||||
break;
|
||||
#endif
|
||||
case 'w':
|
||||
g.newname = optarg;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user