summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Cantrell <dcantrell@redhat.com>2009-05-06 08:41:05 -1000
committerDavid Cantrell <dcantrell@redhat.com>2009-05-06 08:41:38 -1000
commit9249e40f42ffbbdcf42cd1caad72e3d622c7a75b (patch)
tree09fcf626fdd38885f686aba3a1e1d21118271dfd
parent5ebb7235d36390fa72faa730c1f5a452e3432eb1 (diff)
downloadanaconda-9249e40f42ffbbdcf42cd1caad72e3d622c7a75b.tar.gz
anaconda-9249e40f42ffbbdcf42cd1caad72e3d622c7a75b.tar.xz
anaconda-9249e40f42ffbbdcf42cd1caad72e3d622c7a75b.zip
IBM improvements to linuxrc.s390 (#475350)
IBM has reworked linuxrc.s390 to provide a better initial configuration experience for users.
-rw-r--r--loader/Makefile5
-rw-r--r--loader/linuxrc.s3903488
-rw-r--r--loader/lsznet.raw368
-rwxr-xr-xscripts/mk-images2
4 files changed, 3377 insertions, 486 deletions
diff --git a/loader/Makefile b/loader/Makefile
index def2badea..861604c3e 100644
--- a/loader/Makefile
+++ b/loader/Makefile
@@ -70,7 +70,7 @@ REALCC=gcc
# linuxrc + shutdown on s390, init everywhere else
ifneq (,$(filter s390 s390x,$(ARCH)))
-BINS += linuxrc.s390 shutdown
+BINS += linuxrc.s390 lsznet.raw shutdown
SHUTDOWNOPTS = -DAS_SHUTDOWN=1
else
BINS += init
@@ -98,6 +98,9 @@ loader.po: $(wildcard *.c)
linuxrc.s390:
@echo "Nothing to do for $@"
+lsznet.raw:
+ @echo "Nothing to do for $@"
+
init: init.o undomounts.o shutdown.o copy.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
diff --git a/loader/linuxrc.s390 b/loader/linuxrc.s390
index af2d43956..1db416771 100644
--- a/loader/linuxrc.s390
+++ b/loader/linuxrc.s390
@@ -1,5 +1,6 @@
-#! /bin/sh
-#
+#! /bin/bash
+
+# linuxrc.s390: init process of Red Hat's installer initrd for s390(x)
# Copyright (C) 2000-2004 by
# Bernhard Rosenkraenzer <bero@redhat.com>
# Oliver Paukstadt <opaukstadt@millenux.com>
@@ -8,6 +9,8 @@
# Nils Philippsen <nils@redhat.de>
# Helge Deller <hdeller@redhat.de>
# David Sainty <dsainty@redhat.com>
+# Copyright (C) IBM Corp. 2008,2009
+# Author: Steffen Maier <maier@de.ibm.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,175 +26,2745 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
-VERSION=1.1
+
+# prerequisites of this script to run inside the RHEL5.3 installer initrd:
+# - copy udevsettle and udevd to initrd
+# - copy lsznet.raw to initrd as /sbin/lsznet
+# - create /etc/udev/udev.conf with at least one comment line as content
+
+VERSION=1.2
export TEXTDOMAIN=s390installer
export TEXTDOMAINDIR=/usr/lib/locale
-# check IP address format
-# param: IP string
-# return: 0 (valid IP) or 1 (invalid IP)
-checkip()
-{
- checkipv6 $1
- a=$?
- checkipv4 $1
- b=$?
+# helper function to execute command in arguments and print command on stdout
+function debug() {
+ # uncomment the following echo "$*" to enable debug output
+ #echo "$*"
+ $*
+}
- if [ $a -eq 1 ] || [ $b -eq 1 ]; then
- return 1
+# FIXME: maybe change to "$$" for production use, in case it wouldn't be init
+declare -r INITPID="1"
+
+unset testing
+[ "$$" != "$INITPID" ] && testing="1"
+# uncomment the following test="1" to never execute sensitive commands
+#testing="1"
+
+# helper function to disable commands while running outside the initrd
+function tv() {
+ if [ -z "$testing" ]; then
+ $*
else
return 0
fi
}
-checkipv6()
+# for checkipv6 / checkipv4 see also:
+# https://bugzilla.redhat.com/show_bug.cgi?id=234152#c11
+# https://enterprise.redhat.com/issue-tracker/?module=issues&action=view&tid=115847
+
+# see also RFC4291,sec.2.2
+# the following check is incomplete, but sufficient to distinguish from IPv4
+function checkipv6()
{
- ip=$1
- echo $ip | awk -F':' 'BEGIN{ error = 0} { if (NF > 8) error=1; i = 1; while (i++<=NF) {if (!match(toupper($i), "^[0-9A-F]*$")){ error=1}}exit error}'
- return $?;
+ local ip=$1
+ [ -z "$ip" ] && return 1
+ echo $ip | awk -F':' '
+ BEGIN {
+ error = 0
+ }
+
+ {
+ if (NF > 8) {
+ error = 1
+ exit error
+ }
+ for (i = 1; i <= NF; i++) {
+ if ( ! match(toupper($i), "^[0-9A-F]{0,4}$") ) {
+ error = 1
+ break
+ }
+ }
+ exit error
+ }
+ '
+ return $?
}
-checkipv4()
+function checkipv4()
{
- ip=$1
+ local ip=$1
echo $ip | awk -F'.' '{ if (NF != 4) { exit 1 } i=1; while (i<=NF) { if ($i>255 || $i<0) { exit 1 }; i=i+1; } exit 0 }'
return $?
}
-doshutdown()
+function doshutdown()
{
- echo $"about to exec shutdown"
exec /sbin/shutdown
exit 0
}
-doreboot()
+function doreboot()
{
+ # find out the location of /boot and use it to re-ipl
+ boot="$(cat /proc/mounts | grep " /mnt/sysimage/boot " | awk -F" " '{print $1}')"
+ if [ -z $boot ]; then
+ # use root if /boot not used
+ boot="$(cat /proc/mounts | grep " /mnt/sysimage " | awk -F" " '{print $1}')"
+ fi
+
+ # lookup dasd disk
+ echo $boot | grep "dasd" > /dev/null
+ if [ $? -eq 0 ]; then
+ type="ccw"
+ boot="$(basename $boot)"
+ # strip partition number from dasd device
+ boot="$(echo ${boot%[0-9]})"
+ id="$(basename $(readlink /sys/block/$boot/device))"
+ echo $type > /sys/firmware/reipl/reipl_type
+ echo $id > /sys/firmware/reipl/$type/device
+ else
+ # scsi re-ipl only supported on newer machines
+ doshutdown
+ exit 0
+ fi
+
echo $"about to exec shutdown -r"
exec /sbin/shutdown -r
exit 0
}
-sysecho () {
- file=$1
- shift
- i=1
- while [ $i -le 10 ] ; do
- if [ ! -f $file ]; then
- sleep 1
- i=$((i+1))
- else
- break
- fi
- done
- [ -f $file ] && echo $* > $file
+function sysecho () {
+ file=$1
+ shift
+ local i=1
+ while [ $i -le 10 ] ; do
+ if [ ! -f "$file" ]; then
+ sleep 1
+ i=$((i+1))
+ else
+ break
+ fi
+ done
+ [ -f "$file" ] && echo $* > $file
}
-
-startinetd()
+function startinetd()
{
- echo
- echo $"Starting telnetd and sshd to allow login over the network."
- echo $"Welcome to the anaconda install environment $VERSION for $S390ARCH" > /etc/issue.net
- echo $"Welcome to the anaconda install environment $VERSION for $S390ARCH" > /etc/motd
- echo >> /etc/motd
-
- /sbin/xinetd -stayalive -reuse -pidfile /tmp/xinetd.pid
- /sbin/sshd
- if [ -z "$RUNKS" ]; then
- echo
- echo $"Connect now to $IPADDR to start the installation."
- read
- while : ; do
- /bin/sh --login
- [ $? = 0 ] || break
- done
- fi
+ echo
+ echo $"Starting telnetd and sshd to allow login over the network."
+ if [ -z "$testing" ]; then
+ echo $"Welcome to the anaconda install environment $VERSION for $S390ARCH" > /etc/issue.net
+ echo $"Welcome to the anaconda install environment $VERSION for $S390ARCH" > /etc/motd
+ echo >> /etc/motd
+ fi # testing
+
+ /sbin/xinetd -stayalive -reuse -pidfile /tmp/xinetd.pid
+ /sbin/sshd
+ if [ -z "$RUNKS" ]; then
+ echo
+ echo $"Connect now to $IPADDR and login as user root to start the installation."
+ echo $"E.g. using: ssh -X root@$IPADDR"
+ read
+ while : ; do
+ /bin/sh --login
+ [ $? = 0 ] || break
+ done
+ fi
}
# read file from CMS and write it to /tmp
-readcmsfile() # $1=dasdport $2=filename
+function readcmsfile() # $1=dasdport $2=filename
{
- local dev
- if [ $# -ne 2 ]; then return; fi
- mknod /dev/dasda b 94 0
- insmod dasd_mod$LO dasd=$1
- insmod dasd_eckd_mod$LO
- cmsfscat -d /dev/dasda -a $2 > /tmp/$2
- if [ ${#1} == 3 ]; then
- dev="0.0.0${1}"
- elif [ ${#1} == 4 ]; then
- dev="0.0.${1}"
- fi
- sysecho /sys/bus/ccw/drivers/dasd-eckd/$dev/online 0
- rmmod dasd_eckd_mod
- rmmod dasd_mod
-}
-
-setupdevice()
-{
- if [ -z "$SUBCHANNELS" -o -z "$NETTYPE" ]; then
- echo $"SUBCHANNELS or NETTYPE empty, cannot continue."
- exit 1
- fi
- SYSDIR=${SUBCHANNELS//,*/} # get first subchannel. This is where the device can be brought online
- sysecho /sys/bus/ccwgroup/drivers/${NETTYPE}/group "$SUBCHANNELS"
- if [ -n "$PORTNAME" ]; then
- if [ "$NETTYPE" = "lcs" ]; then
- sysecho /sys/bus/ccwgroup/drivers/${NETTYPE}/${SYSDIR}/portno "$PORTNAME"
- else
- sysecho /sys/bus/ccwgroup/drivers/${NETTYPE}/${SYSDIR}/portname "$PORTNAME"
- fi
- fi
- if [ -n "$CTCPROT" -a "$NETTYPE" = "ctc" ]; then
- sysecho /sys/bus/ccwgroup/drivers/ctc/${SYSDIR}/protocol "$CTCPROT"
- fi
- if [ -n "$LAYER2" -a "$NETTYPE" = "qeth" ]; then
- sysecho /sys/bus/ccwgroup/drivers/qeth/${SYSDIR}/layer2 "$LAYER2"
- fi
- sysecho /sys/bus/ccwgroup/drivers/${NETTYPE}/${SYSDIR}/online 1
-}
-
-createDevices()
+ local dev
+ if [ $# -ne 2 ]; then return; fi
+ mknod /dev/dasda b 94 0
+ if ! sysecho /proc/cio_ignore "free $1"; then
+ echo $"DASD $1 could not be cleared from device blacklist"
+ return 1
+ fi
+ # /proc/cio_ignore won't block on freeing devices until resensing
+ # has been completed, so wait until the udev event queue depletes
+ # (without udevsettle we could wait 2 seconds unconditionally)
+ #debug ls -laF /dev/.udev
+ udevsettle
+ sleep 1
+ insmod dasd_mod$LO dasd=$1
+ insmod dasd_eckd_mod$LO
+ if ! cmsfscat -d /dev/dasda -a $2 > /tmp/$2; then
+ echo $"Could not read conf file $2 on CMS DASD $1."
+ fi
+ # maybe replace with a more robust: dev=$(printf "0.0.%04x" $((0x${1})))
+ if [ ${#1} == 3 ]; then
+ dev="0.0.0${1}"
+ elif [ ${#1} == 4 ]; then
+ dev="0.0.${1}"
+ fi
+ sysecho /sys/bus/ccw/drivers/dasd-eckd/$dev/online 0
+ rmmod dasd_eckd_mod
+ rmmod dasd_mod
+}
+
+function createDevices()
{
awk '{ printf("mknod /dev/%s %s %s %s\n", $1, $2, $3, $4);
- printf("chmod %s /dev/%s\n", $5, $1);
- printf("chown %s /dev/%s\n", $6, $1);
- }' <<EOF | sh
- console c 5 1 600 root:root
- null c 1 3 666 root:root
- zero c 1 5 666 root:root
- mem c 1 1 600 root:root
- ptmx c 5 2 666 root:root
- tty c 5 0 666 root:root
- tty0 c 4 0 600 root:tty
- tty1 c 4 1 600 root:tty
- random c 1 8 644 root:root
- urandom c 1 9 644 root:root
- rtc c 10 135 644 root:root
+ printf("chmod %s /dev/%s\n", $5, $1);
+ printf("chown %s /dev/%s\n", $6, $1);
+ }' <<EOF | sh
+console c 5 1 600 root:root
+null c 1 3 666 root:root
+zero c 1 5 666 root:root
+mem c 1 1 600 root:root
+ptmx c 5 2 666 root:root
+tty c 5 0 666 root:root
+tty0 c 4 0 600 root:tty
+tty1 c 4 1 600 root:tty
+random c 1 8 644 root:root
+urandom c 1 9 644 root:root
+rtc c 10 135 644 root:root
+EOF
+ for i in 2 3 4 5 6 7 8 9 ; do
+ ln -s console /dev/tty$i
+ done
+ mkdir /dev/pts
+ ln -s /proc/self/fd /dev/fd
+}
+
+# from here on accesses to sysfs try to follow
+# linux/Documentation/sysfs-rules.txt
+
+### lsznet.raw integration
+
+declare -a nettable
+
+function read_lsznet_output() {
+ #local lsznet_output=/tmp/lsznet.raw
+ #lsznet.raw > $lsznet_output
+ count=0
+ local line
+ while read line; do
+ nettable[$count]="$line"
+ count=$((count + 1))
+ #done < $lsznet_output
+ #rm -f $lsznet_output
+ # using the more sophisticated process substitution instead of temp file
+ # requires the symlink /dev/fd -> /proc/self/fd => createDevices
+ done < <(lsznet)
+}
+
+function print_nettable() {
+ local fmtstring="%3s %-14s %-7s %-5s %-4s %-6s %-7s %s\n"
+ printf "$fmtstring" \
+ "NUM" "CARD" "CU" "CHPID" "TYPE" "DRIVER" "IF" "DEVICES"
+ local i
+ for ((i=0; i < count; i++)); do
+ local item cutype chp chpidtype devdrv devname chlist cardtype
+ read item cutype chp chpidtype devdrv devname chlist cardtype <<< ${nettable[$i]}
+ printf "$fmtstring" \
+ $item "$cardtype" $cutype $chp "$chpidtype" $devdrv $devname $chlist
+ done
+}
+
+function clear_screen() {
+ # FIXME: find a way to clear screen despite 3215 line mode terminal
+ echo
+}
+
+function dialog_network_table() {
+ while : ; do
+ echo $"Scanning for available network devices..."
+ # This may take a long time so we show "progress":
+ #( while true; do echo -n "."; sleep 1; done ) &
+ #local childpid=$!
+ read_lsznet_output
+ #kill $childpid
+ #echo
+ echo $"Autodetection found ${count} devices."
+ # count==0: there might still be a blacklist the user wants to clear.
+ # do not flood user with long list if there are many devices
+ if [ "$count" -le 15 ]; then
+ # Show list
+ answer=s
+ else # [ $count -gt 15 ]
+ echo
+ while : ; do
+ echo $"s) show all, m) manual config:"
+ local answer
+ read answer
+ case $answer in
+ s|m) break ;;
+ esac
+ done
+ fi
+ [ "$answer" = "m" ] && break
+ # show network table to select network hardware configuration from
+ if [ "$count" -gt 0 ]; then
+ clear_screen
+ print_nettable
+ echo
+ fi
+ # account for possibly ignored common I/O devices
+ # cio_wc_bytes is NOT local so it can be re-used outside this function
+ cio_wc_bytes=0
+ local cio_wc_filename cio_wc_foo
+ if [ -f /proc/cio_ignore ]; then
+ local cio_wc=$(wc -c /proc/cio_ignore)
+ read cio_wc_bytes cio_wc_filename cio_wc_foo <<< "$cio_wc"
+ if [ "$cio_wc_bytes" != "0" ]; then
+ echo $"Note: There is a device blacklist active! (Clearing might take long)"
+ #cat /proc/cio_ignore | tr '\n' ','
+ #echo
+ else
+ if [ "$count" -eq 0 ]; then
+ # count==0 AND no device blacklist => manual mode
+ echo $"Entering manual configuration mode."
+ break
+ fi
+ fi
+ fi
+ # selection dialog
+ while : ; do
+ [ "$count" -gt 0 ] && echo -n $"<num>) use config, "
+ [ "$cio_wc_bytes" != "0" ] && echo -n $"c) clear blacklist, "
+ echo $"m) manual config, r) rescan, s) shell:"
+ local choice
+ read choice
+ [ -z "$choice" ] && continue
+ if [ "$choice" = "s" ]; then
+ echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
+ /bin/bash
+ continue 2
+ fi
+ [ "$choice" = "m" ] && break
+ [ "$choice" = "r" ] && continue 2
+ [ "$cio_wc_bytes" != "0" -a "$choice" = "c" ] && break
+ [[ "$choice" =~ ^[[:digit:]]+$ ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ [ "$choice" -ge 1 -a "$choice" -le "$count" ] && break
+ ;;
+ 1)
+ # string did not match the pattern
+ continue
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ done
+ if [ "$choice" = "c" ]; then
+ echo $"Clearing device blacklist..."
+ if sysecho /proc/cio_ignore "free all"; then
+ cio_wc_bytes=0
+ # /proc/cio_ignore won't block on freeing devices
+ # until resensing has been completed, so wait until
+ # the udev event queue depletes.
+ # This may take a long time so we show "progress":
+ #( while true; do echo -n "."; sleep 3; done ) &
+ #local childpid=$!
+ #debug ls -laF /dev/.udev
+ udevsettle
+ # (virtual) CTC/A takes some more time to appear in sysfs
+ # FIXME: how long to wait? 3 seconds seems to be enough.
+ sleep 3
+ #kill $childpid
+ #echo
+ # udevsettle only works if udevd is running (/dev/.udev/queue)!
+ # (without udevsettle we could wait 5-10 seconds uncond.)
+ continue
+ else
+ echo $"Device blacklist could not be cleared"
+ fi
+ fi
+ [ "$choice" = "m" ] && break
+ # finally extract config info from selected item
+ # array nettable starts at index zero, user input starts at index one
+ choice=$((choice - 1))
+ local item cutype chp chpidtype devdrv devname chlist cardtype
+ read item cutype chp chpidtype devdrv devname chlist cardtype <<< ${nettable[$choice]}
+ # $NETTYPE happens to be exactly the network driver name
+ NETTYPE=$devdrv
+ SUBCHANNELS=$chlist
+ break
+ done
+ echo
+}
+
+declare -r PREFIXFORMAT=[[:xdigit:]]*
+declare -r SSIDFORMAT=[0-3]
+declare -r BUSIDFORMAT=[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]
+declare -r IDFORMAT=$PREFIXFORMAT.$SSIDFORMAT.$BUSIDFORMAT
+declare -r SUBCHANNEL_TYPE_IO=0
+
+# The following combinations of control unit type and model were taken from the
+# Linux network device drivers for s390 on 2008-06-09 from Linux 2.6.25.4.
+# The list (among other things) should be adapted, if any of those device
+# drivers start supporting different CU types/models.
+# (Alternatively, the list could be generated by reading the modaliases
+# directly out of the device driver modules:
+# modinfo qeth/cu3088 | fgrep 'alias:'
+# However, this would still require a list of device driver modules.)
+
+declare -r -a CU=(
+ 1731/01
+ 1731/05
+ 3088/08
+ 3088/1f
+ 3088/1e
+ 3088/01
+ 3088/60
+)
+
+declare -r -a CU_DEVDRV=(
+ qeth
+ qeth
+ ctc
+ ctc
+ ctc
+ lcs
+ lcs
+)
+
+# Searches for a match of argument 1 on the array $CU and sets $cu_idx
+# to the matched array index on success.
+# Returns 0 on success, 1 on failure.
+function search_cu() {
+ local scu=$1
+ local i
+ for ((i=0; i < ${#CU[@]}; i++)); do
+ if [ "$scu" == "${CU[i]}" ]; then
+ cu_idx=$i
+ return 0
+ fi
+ done
+ return 1
+}
+
+function cardtype2cleartext() {
+ local cardtype=$1
+ case $cardtype in
+ OSD_10GIG) echo "OSA card in OSD mode, 10 Gigabit Ethernet" ;;
+ OSD_1000) echo "OSA card in OSD mode, Gigabit Ethernet" ;;
+ OSD_100) echo "OSA card in OSD mode, Fast Ethernet" ;;
+ OSD_GbE_LANE) echo "OSA card in OSD mode, Gigabit Ethernet, LAN Emulation" ;;
+ OSD_FE_LANE) echo "OSA card in OSD mode, Fast Ethernet, LAN Emulation" ;;
+ OSD_TR_LANE) echo "OSA card in OSD mode, Token Ring, LAN Emulation" ;;
+ OSD_ATM_LANE) echo "OSA card in OSD mode, ATM, LAN Emulation" ;;
+ OSD_Express) echo "OSA card in OSD mode, unknown link type" ;;
+ HSTR) echo "OSA card in OSD mode, High Speed Token Ring" ;;
+ OSN) echo "OSA for NCP, ESCON/CDLC bridge" ;;
+ HiperSockets) echo "HiperSocket with CHPID type IQD" ;;
+ "GuestLAN QDIO") echo "GuestLAN based on OSA (QDIO)" ;;
+ "GuestLAN Hiper") echo "GuestLAN based on HiperSocket" ;;
+ unknown) echo "other" ;;
+ *) echo "unknown"
+ echo "l.$LINENO: found unknown card_type, code needs to be fixed" 1>&2
+ ;;
+ esac
+}
+
+# returns true iff running under z/VM
+function isVM() {
+ local cpu_version=$(cat /proc/cpuinfo |grep "^processor " | head -n1 | sed 's/.*version = \([[:xdigit:]][[:xdigit:]]\).*/\1/' | tr '[:lower:]' '[:upper:]')
+ if [ "$cpu_version" = "FF" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# echos one comparable integer built from 3 arguments in kernel version style
+function kernel_version() {
+ [ $# -eq 3 ] || return 1
+ local krn_ver=$1 krn_patch=$2 krn_sub=$3
+ local version=$(( (krn_ver << 16) + (krn_patch << 8) + krn_sub ))
+ # <<EOF convince syntax highlighter that above shifts are no here documents
+ echo $version
+ return 0
+}
+
+# echos one comparable integer built from actual running kernel version
+function linux_version() {
+ local krn_ver krn_patch krn_sub
+ local krn_foo krn_extra
+ IFS=.
+ read krn_ver krn_patch krn_foo < <(uname -r)
+ unset IFS
+ IFS=-
+ read krn_sub krn_extra <<< "$krn_foo"
+ unset IFS
+ kernel_version $krn_ver $krn_patch $krn_sub
+}
+
+# watch out: potential error message as side effect
+function isLayer2Default() {
+ # Read default from sysfs because according to device
+ # drivers book there are differences in the default between
+ # OSA (l2), hipersockets (l3).
+ # This only works here in installer where nobody has overwritten
+ # the default setting with another custom value already!
+ if [ ! -f /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/layer2 ]; then
+ echo $"Could not read layer mode from sysfs"
+ return 1
+ fi
+ local layer2
+ read layer2 < /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/layer2
+ if [ "$layer2" = "1" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# returns true iff either LAYER2 has been set to 1 or is the default
+# watch out: potential error message as side effect
+function isLayer2() {
+ case "x$LAYER2" in
+ x0) return 1 ;; # layer 3
+ x1) return 0 ;; # layer 2
+ x) # LAYER2 is unset or empty => qeth driver default applies.
+ isLayer2Default
+ return $?
+ ;;
+ *) echo "l.$LINENO: unknown value \"$LAYER2\" for LAYER2, code needs to be fixed" 1>&2
+ return 2 ;;
+ esac
+}
+
+# returns true iff qeth device $SCH_R_DEVBUSID and kernel version
+# is capable of supporting IPv6
+# watch out: potential error message as side effect
+function ipv6_capable() {
+ [ "$NETTYPE" = "qeth" ] || return 1
+ case $cardtype in
+ OSD_10GIG|OSD_1000|OSD_100|OSD_Express|"GuestLAN QDIO") return 0 ;;
+ HiperSockets)
+ if isLayer2; then
+ return 0
+ elif [ $(linux_version) -ge $(kernel_version 2 6 26) ]; then
+ return 0
+ else
+ return 1
+ fi
+ ;;
+ OSD_GbE_LANE|OSD_FE_LANE|OSD_TR_LANE|OSD_ATM_LANE) return 1 ;;
+ HSTR|OSN|unknown) return 1 ;;
+ "GuestLAN Hiper") return 1 ;;
+ *) echo $"Unknown card_type to determine IPv6 support"
+ return 1 ;;
+ esac
+}
+
+function insert_module() {
+ local module=${1}
+ if grep "^${module%.ko} .*$" /proc/modules &> /dev/null ; then
+ # module has already been loaded => do not try to load again
+ return 0
+ fi
+ if ! insmod $module; then
+ echo $"Could not load kernel module $module"
+ fi
+}
+
+function load_kernel_modules() {
+ if [ ":$NETTYPE" = ":ctc" ]; then
+ insert_module ccwgroup$LO
+ insert_module cu3088$LO
+ insert_module fsm$LO
+ insert_module ctc$LO
+ elif [ ":$NETTYPE" = ":iucv" ]; then
+ insert_module fsm$LO
+ insert_module iucv$LO
+ insert_module netiucv$LO
+ elif [ "$NETTYPE" = "lcs" ]; then
+ insert_module ccwgroup$LO
+ insert_module cu3088$LO
+ insert_module lcs$LO
+ elif [ "$NETTYPE" = "qeth" ]; then
+ insert_module crypto_api$LO
+ insert_module xfrm_nalgo$LO
+ insert_module ipv6$LO
+ insert_module ccwgroup$LO
+ insert_module qdio$LO
+ insert_module qeth$LO
+ fi
+}
+
+function remove_module() {
+ if ! rmmod $1; then
+ #echo $"Could not remove kernel module $1"
+ :
+ fi
+}
+
+function remove_kernel_modules() {
+ if [ ":$NETTYPE" = ":ctc" ]; then
+ remove_module ctc
+ remove_module fsm
+ remove_module cu3088
+ remove_module ccwgroup
+ elif [ ":$NETTYPE" = ":iucv" ]; then
+ remove_module netiucv
+ remove_module iucv
+ remove_module fsm
+ elif [ "$NETTYPE" = "lcs" ]; then
+ remove_module lcs
+ remove_module cu3088
+ remove_module ccwgroup
+ elif [ "$NETTYPE" = "qeth" ]; then
+ remove_module qeth
+ remove_module qdio
+ remove_module ccwgroup
+ # The remaining 3 modules can hardly be unloaded
+ # since e.g. loopback holds an inet6 address and thus a reference.
+ # But that's no problem as long as the device drivers are removed.
+ remove_module ipv6
+ remove_module xfrm_nalgo
+ remove_module crypto_api
+ fi
+}
+
+# sets device online _and_ retrieves DEVICE at the same time
+# iucv cannot be set online since it's not based on ccw(group)
+function set_device_online() {
+ echo $"Activating network device..."
+ local sysnettype
+ case "${NETTYPE}" in
+ qeth) sysnettype=${NETTYPE} ;;
+ lcs|ctc) sysnettype=cu3088 ;;
+ esac
+ if ! [ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online ]; then
+ echo $"Sysfs path to set device online does not exist."
+ return 1
+ fi
+ if ! sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online "1"; then
+ echo $"Could not set device ($SUBCHANNELS) online"
+ return 1
+ fi
+ local i=1
+ while : ; do
+ local online
+ read online < /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online
+ [ "$online" == "1" ] && break
+ sleep 1
+ i=$((i+1))
+ if [ "$i" -gt 10 ]; then
+ echo $"Could not set device ($SUBCHANNELS) online within timeout"
+ return 1
+ fi
+ done
+ if [ "$NETTYPE" = "lcs" -o "$NETTYPE" = "ctc" ]; then
+ # KH FIXME: Workaround for missing sysfs interface
+ # DEVICE=`cat /sys/devices/lcs/${SUBCHANNELS//,*/}/if_name`
+ # replaced with flexible solution:
+ # https://bugzilla.redhat.com/show_bug.cgi?id=204803#c9
+ # "sys/bus/ccwgroup/devices/${SUBCHANNEL}/net\:*
+ # for lcs after setting online"
+ if [ ! -h /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/net:* ]; then
+ echo $"Device $SUBCHANNELS does not have required sysfs attribute 'net:*'"
+ return 1
+ fi
+ DEVICE=$(echo /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/net:*)
+ DEVICE=${DEVICE//*:/}
+ if [ "$DEVICE" = "" ]; then
+ echo $"Could not get device name for $SUBCHANNELS"
+ return 1
+ fi
+ else # qeth
+ if [ ! -f /sys/devices/qeth/$SCH_R_DEVBUSID/if_name ]; then
+ echo $"Device $SUBCHANNELS does not have required sysfs attribute 'if_name'"
+ return 1
+ fi
+ # (device needs to be online to read if_name from sysfs attribute!)
+ read DEVICE < /sys/devices/qeth/$SCH_R_DEVBUSID/if_name
+ if [ "$DEVICE" = "" ]; then
+ echo $"Could not get device name for $SUBCHANNELS"
+ return 1
+ fi
+ if [ -f /sys/devices/qeth/$SCH_R_DEVBUSID/card_type ]; then
+ read cardtype < /sys/devices/qeth/$SCH_R_DEVBUSID/card_type
+ #debug echo "$cardtype"
+ # device is now online and link type will be known
+ echo -n $"Detected: "
+ cardtype2cleartext "$cardtype"
+ else
+ echo $"Could not read qeth network card type from sysfs."
+ fi
+ fi
+}
+
+# sets device up and blocks until device appears to be up
+function set_device_up() {
+ if [ -z "$DEVICE" ]; then
+ echo $"Could not determine interface name to bring up device $SUBCHANNELS"
+ return 1
+ fi
+ # Device does not come up fast enough to use "ip" to configure, so block.
+ # While OSA come up themselves after setting online,
+ # e.g. HiperSocket won't, so set them up explicitly for the following check
+ debug ip link set up $DEVICE
+ local i=1
+ while : ; do
+ local tst=$(ip -o link show up dev $DEVICE)
+ [ -n "$tst" ] && break
+ sleep 1
+ i=$((i+1))
+ if [ "$i" -gt 10 ]; then
+ echo $"Could not bring up device $DEVICE within timeout"
+ return 1
+ fi
+ done
+ return 0
+}
+
+function syntax_check_domainname() {
+ # - match against regex adopted from RFC1035,sec.2.3.1 or RFC1034,sec.3.5
+ # (Internationalized Domain Names in Applications (IDNA) [RFC4690]
+ # have to be entered after encoding by punycode [RFC3492])
+ [[ "$1" =~ ^[[:alpha:]]([[:alnum:]-]{0,61}[[:alnum:]])?(\\.[[:alpha:]]([[:alnum:]-]{0,61}[[:alnum:]])?)*$ ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ return 0
+ ;;
+ 1)
+ # string did not match the pattern
+ echo "$2"
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ return 1
+}
+
+function modprobe_alias() {
+ if [ ":$NETTYPE" = ":iucv" ]; then
+ echo "alias $DEVICE netiucv" >> /tmp/modprobe.conf
+ else
+ echo "alias $DEVICE $NETTYPE" >> /tmp/modprobe.conf
+ fi
+ if [ $? -ne 0 ]; then
+ echo $"Could not append alias for network device $DEVICE to modprobe.conf"
+ return 1
+ fi
+ return 0
+}
+
+function disable_ipv6_autoconf() {
+ sysctl -w net.ipv6.conf.all.accept_ra=0 > /dev/null
+ sysctl -w net.ipv6.conf.all.accept_redirects=0 > /dev/null
+ sysctl -w net.ipv6.conf.all.autoconf=0 > /dev/null
+ sysctl -w net.ipv6.conf.default.accept_ra=0 > /dev/null
+ sysctl -w net.ipv6.conf.default.accept_redirects=0 > /dev/null
+ sysctl -w net.ipv6.conf.default.autoconf=0 > /dev/null
+}
+
+function configure_ipv6_address() {
+ # device needs to be online
+ # arp flag needs to be on for ipv6 over osa because of ndisc.
+ # happens automatically by the driver. do NOT mess with default setting.
+ #NO#debug ip link set dev $DEVICE arp on
+ if ! debug ip -6 address add $IPADDR/$NETMASK dev $DEVICE; then
+ echo $"Could net set IPv6 address $IPADDR/$NETMASK for device $DEVICE"
+ return 1
+ fi
+ # network route has been set by above "ip address add" already
+ # take care of MTU, which is bundled with ifconfig in the other IPv4 cases
+ if [ -n "$MMTU" ]; then
+ if ! debug ip link set $DEVICE $MMTU; then
+ echo $"Could net set maximum transfer unit ($MMTU) for device $DEVICE"
+ return 1
+ fi
+ fi
+ return 0
+}
+
+function configure_ipv4_address() {
+ # it's IPv4 and we can make use of ipcalc for better usability
+ if ipcalc -bmnp $ipcalc_arg > /tmp/ipcalc.$$.out 2> /dev/null; then
+ . /tmp/ipcalc.$$.out
+ else
+ echo $"Could not calculate network address and broadcast address from"
+ echo $" IPv4 address $IPADDR and netmask $NETMASK"
+ return 1
+ fi
+ rm /tmp/ipcalc.$$.out
+ # device needs to be online
+ if ! debug ifconfig $DEVICE $IPADDR $MMTU netmask $NETMASK broadcast $BROADCAST; then
+ echo $"Could not set IPv4 address $IPADDR for device $DEVICE"
+ echo $" with network mask $NETMASK and broadcast address $BROADCAST"
+ [ -n "$MMTU" ] && echo $" and maximum transfer unit: $MMTU"
+ return 1
+ fi
+ # This network route is already there after ifconfig!
+ #if ! debug route add -net $NETWORK netmask $NETMASK dev $DEVICE; then
+ # echo $"Could not add network route to $NETWORK/$NETMASK on device $DEVICE"
+ # return 1
+ #fi
+ return 0
+}
+
+function handle_mtu() {
+ # don't ask for MTU, but use it if it has been set in the .parm file
+ # don't overwrite MMTU if it has been set for CTC
+ [ -n "$MTU" -a -z "$MMTU" ] && MMTU="mtu $MTU"
+}
+
+function rollback_config() {
+ # each transaction to roll back may fail, if previous setup has not
+ # made progress that far to reach a certain transation
+ # => error output is misleading and should be avoided
+ [ -n "$DEVICE" ] && tv ip -4 route flush default dev $DEVICE
+ [ -n "$DEVICE" ] && tv ip -6 route flush default dev $DEVICE
+ # address flush seems to be effective for all address families
+ [ -n "$DEVICE" ] && ip address flush dev $DEVICE
+ # iucv device needs to be down before removal
+ [ -n "$DEVICE" ] && ip link set down $DEVICE &> /dev/null
+ if [ -n "$NETTYPE" ]; then
+ if [ "$NETTYPE" = "iucv" ]; then
+ if [ -n "$DEVICE" ]; then
+ sysecho /sys/bus/iucv/drivers/netiucv/remove $DEVICE
+ fi
+ else # "$NETTYPE" != "iucv"
+ if [ -n "$SCH_R_DEVBUSID" ]; then
+ local sysnettype
+ case "${NETTYPE}" in
+ qeth) sysnettype=${NETTYPE} ;;
+ lcs|ctc) sysnettype=cu3088 ;;
+ esac
+ [ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online ] && \
+ sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online "0"
+ [ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/ungroup ] && \
+ sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/ungroup "1"
+ fi
+ fi
+ fi
+ [ -z "$mtu_was_set" ] && unset MTU
+ [ -z "$mmtu_was_set" ] && unset MMTU
+ [ -z "$vswitch_was_set" ] && unset VSWITCH
+ # Try to silently unload modules. We ignore failures since
+ # load_kernel_modules only tries to load missing modules.
+ tv remove_kernel_modules
+ # prevent possible reuse of an old DEVICE on restarting dialog
+ unset DEVICE
+}
+
+### workflow helper functions
+
+# workflow ideas:
+# - setting/applying single configuration steps right away save us explicit
+# syntactical & semantic checks PLUS we get direct feedback on error
+# - check error level of forked external programs and react on errors
+
+unset reenter
+unset redoitem
+unset interaction_happened
+
+function reenter() {
+ [ -z "$reenter" ] && return 1
+ # reenter menu should only be shown if NOT redoing item
+ if [ -n "$redoitem" ]; then
+ # unset redoitem # wrong => do NOT do this here
+ return 1
+ fi
+ return 0
+}
+
+function reenter_menu() {
+ local oldvalue=$1
+ interaction_happened="yes"
+ # unsetting input here is not sufficient, since reenter_menu
+ # is not called for predefined parameters
+ # which then might get assigned a previous old input of another parameter!
+ #unset input
+ reenter || return 0
+ # don't present reenter menu for empty parameters
+ # (currently ignoring parameters that are allowed to be empty!)
+ # this could be improved by checking if variable has been set/defined
+ #[ -z "$1" ] && return 0
+ while : ; do
+ if [ -n "$helptext" ]; then
+ echo $"0) default is previous \"$oldvalue\", 1) new value, ?) help"
+ else
+ echo $"0) default is previous \"$oldvalue\", 1) new value"
+ fi
+ # uncoded alternative: 2) skip parameter
+ local answer
+ read answer
+ [ -z "$answer" ] && return 1
+ case $answer in
+ 0) return 1 ;;
+ 1) # Deciding to enter new value gets user out of reenter-mode
+ # temporarily for this parameter.
+ # To put it differently: redoing does NOT present old values.
+ redoitem="yes"
+ echo -n $"new value: "
+ return 0
+ ;;
+ "?") input="?"
+ return 1
+ ;;
+ esac
+ done
+}
+
+function workflow_item_menu() {
+ local noredo=$1
+ # default is to continue if running kickstart to prevent interaction
+ [ -n "$RUNKS" ] && return 0
+ interaction_happened="yes"
+ while : ; do
+ unset redoitem
+ if [ "$noredo" = "noredo" ]; then
+ echo $"1) continue, 2) restart dialog, 3) halt, 4) shell"
+ else
+ echo $"0) redo this parameter, 1) continue, 2) restart dialog, 3) halt, 4) shell"
+ fi
+ local answer
+ read answer
+ case $answer in
+ 0) [ "$noredo" = "noredo" ] && continue
+ redoitem="yes"
+ continue 2
+ ;;
+ 1) return 0 ;; # can be used to break at caller on ignore
+ 2) reenter="yes"
+ rollback_config
+ continue 3
+ ;;
+ 3) tv doshutdown
+ exit 0
+ ;;
+ 4) echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
+ /bin/bash
+ if [ "$noredo" != "noredo" ] && [ -n "$question_prefix" ]; then
+ $question_prefix
+ echo
+ fi
+ ;; # stay in workflow item menu
+ esac
+ done
+}
+
+# input variables: PARMNAME, question_prefix, question_choices,
+# "options" ...
+# output variables: $question_prefix, $helptext
+# modifies: the variable named $PARMNAME, $OPTIND
+function ask() {
+ [ $# -lt 3 ] && echo "l.$LINENO: too few arguments (<3), please fix calling code." 1>&2
+ local PARMNAME=$1
+ shift
+ question_prefix=$1
+ shift
+ local question_choices=$1
+ shift
+ local exception
+ local syntax_check
+ unset helptext
+ local handle
+ local finish
+ local optname
+ OPTIND=1
+ while getopts ":e:s:h:c:f:" optname; do
+ case $optname in
+ e) exception=$OPTARG ;;
+ s) syntax_check=$OPTARG ;;
+ h) helptext=$OPTARG ;;
+ c) handle=$OPTARG ;;
+ f) finish=$OPTARG ;;
+ "?") ;; # ignore invalid option
+ :) echo $"l.$LINENO: Missing parameter to option -$OPTARG" 1>&2 ;;
+ esac
+ done
+ while : ; do
+ unset input
+ local input
+ # actually ask question if one of the following is true:
+ # - $PARMNAME parameter has not been set yet, e.g. not in parm file
+ # - on 2nd and further attempts, i.e. redoing the parameter
+ # - on having restarted the whole dialog
+ # describing the same from another viewpoint:
+ # - if $PARMNAME has been set, try to check syntax and apply
+ # - on redo, $PARMNAME has been set and reenter is false,
+ # but still ask question again
+ # - on reenter, $PARMNAME might have been set, but still ask question
+ if [ -z "${!PARMNAME}" -o -n "$redoitem" -o -n "$reenter" ]; then
+ # one empty line to separate parameter questions from each other
+ echo
+ $question_prefix
+ if reenter; then
+ echo
+ else
+ $question_choices
+ fi
+ # on reenter, give choice between old value and entering new one
+ reenter_menu ${!PARMNAME} && read input \
+ && [ "$input" != "?" ] && eval ${PARMNAME}=\$input
+ # escaping the $ in the RHS of the eval statement makes it safe
+ fi
+ if [ -n "$helptext" ] && [ "$input" = "?" ]; then
+ $helptext
+ continue
+ fi
+ # optional: default or exceptional handling
+ [ -n "$exception" ] && $exception
+ if [ -n "$syntax_check" -a -z "$handle" ]; then
+ # some parameters have only syntax check (and deferred config):
+ if $syntax_check; then
+ break
+ else
+ workflow_item_menu && break
+ fi
+ elif [ -n "$syntax_check" -a -n "$handle" ]; then
+ # most common parameters have syntax and configuration:
+ # user might still continue on syntax error
+ $syntax_check || workflow_item_menu
+ # optional: actual configuration
+ if $handle; then
+ # parmname has been configured successfully
+ break
+ else
+ # user might still continue on configuration failure
+ workflow_item_menu && break
+ fi
+ elif [ -n "$finish" ]; then
+ # few parameters need special handling done by their own function:
+ $finish
+ else
+ echo "Unsupported calling of ask function, please fix calling code"
+ fi
+ done # PARMNAME
+ # disable potential temporary redoing-mode during reenter-mode
+ unset redoitem
+}
+
+### NETTYPE
+
+function syntax_check_nettype() {
+ # - NETTYPE \in {qeth,lcs,ctc,iucv}
+ [[ "$NETTYPE" =~ (^qeth$)|(^lcs$)|(^ctc$)|(^iucv$) ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ if [ "$NETTYPE" = "iucv" ] && ! isVM; then
+ echo $"IUCV network type is only available under z/VM (NETTYPE)."
+ return 1
+ fi
+ return 0
+ ;;
+ 1)
+ # string did not match the pattern
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ echo $"Incorrect format or value for network type (NETTYPE): $NETTYPE"
+ return 1
+}
+
+function question_prefix_nettype() {
+ echo -n $"Network type"
+}
+
+function question_choices_nettype() {
+ if isVM; then
+ echo $" (qeth, lcs, ctc, iucv, ? for help). Default is qeth:"
+ else
+ echo $" (qeth, lcs, ctc, ? for help). Default is qeth:"
+ fi
+}
+
+function helptext_nettype() {
+ echo $" Help text for network type:"
+ echo $" qeth: OSA-Express Fast Ethernet, Gigabit Ethernet (including 1000Base-T),"
+ echo $" High Speed Token Ring, and ATM (running Ethernet LAN emulation)"
+ echo $" features in QDIO mode."
+ echo $" [default]"
+ echo $" lcs: OSA-2 Ethernet/Token Ring, OSA-Express Fast Ethernet in non-QDIO mode,"
+ echo $" OSA-Express High Speed Token Ring in non-QDIO mode and Gigabit Ethernet"
+ echo $" in non-QDIO mode."
+ echo $" ctc: Deprecated, useful for migration."
+ isVM && echo $" iucv: Deprecated, useful for migration."
+}
+
+function exception_nettype() {
+ # - default is qeth since it should be common
+ if [ -z "$NETTYPE" ]; then
+ NETTYPE=qeth
+ break
+ fi
+}
+
+function finish_nettype() {
+ if syntax_check_nettype; then
+ break
+ else
+ # necessary parts which would otherwise be done by workflow_item_menu
+ interaction_happened="yes"
+ redoitem="yes"
+ fi
+}
+
+function do_nettype() {
+ ask NETTYPE \
+ question_prefix_nettype question_choices_nettype \
+ -h helptext_nettype -e exception_nettype -f finish_nettype
+}
+
+### CHANDEV
+
+function do_chandev() {
+ echo
+ echo $"The CHANDEV variable isn't used anymore, please update your "
+ echo $".parm or the .conf file to use NETTYPE, SUBCHANNELS, etc. instead."
+ echo
+}
+
+### SUBCHANNELS
+
+function syntax_check_subchannels() {
+ SUBCHANNELS=`echo $SUBCHANNELS | tr ABCDEF abcdef`
+ # - make subchannel question dependent on NETTYPE (2 vs. 3 subchannels)
+ if [ "$NETTYPE" = "qeth" ]; then
+ # - match against regex, depending on qeth
+ [[ "$SUBCHANNELS" =~ ^[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4},[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4},[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}$ ]]
+ else
+ # - match against regex, depending on lcs/ctc
+ [[ "$SUBCHANNELS" =~ ^[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4},[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}$ ]]
+ fi
+ case $? in
+ 0)
+ # string matched the pattern
+ return 0
+ ;;
+ 1)
+ # string did not match the pattern
+ echo $"Incorrect format for channels (SUBCHANNELS): $SUBCHANNELS"
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ return 1
+}
+
+function semantic_check_subchannels() {
+ local subch_count
+ if [ "$NETTYPE" = "qeth" ]; then
+ subch_count=3
+ else
+ subch_count=2
+ fi
+ # done: make subchannel handling more robust by not relying on REMATCH
+ local -a subch_array
+ IFS=,
+ read -a subch_array <<< "indexzero,$SUBCHANNELS"
+ unset IFS
+ local i
+ local all_subch_good=0
+ for ((i=1; i <= $subch_count; i++)); do
+ local devbusid=${subch_array[$i]}
+ # remember first subchannel for potential undo of ccwgroup
+ # (via /sys/devices/qeth/$SCH_R_DEVBUSID/ungroup)
+ [ "$i" -eq 1 ] && SCH_R_DEVBUSID=$devbusid
+ local prefix ssid devno foo
+ IFS=.
+ read prefix ssid devno foo <<< "$devbusid"
+ unset IFS
+ local dev_p=$(echo /sys/devices/css$prefix/$IDFORMAT/$devbusid)
+ # - check for existence of devnos in sysfs
+ if [ ! -d "$dev_p" -a "$cio_wc_bytes" != "0" ]; then
+ # - try to free from /proc/cio_ignore if they don't exist
+ echo $"Device $devbusid not present, trying to clear from blacklist and resense..."
+ if sysecho /proc/cio_ignore "free $devbusid"; then
+ # /proc/cio_ignore won't block on freeing devices
+ # until resensing has been completed, so wait until
+ # the udev event queue depletes (without udevsettle we
+ # could wait 2 seconds unconditionally)
+ #debug ls -laF /dev/.udev
+ udevsettle
+ # even though the device might now be online, some of its
+ # sysfs attributes (e.g. cutype) might not yet be available
+ sleep 1
+ else
+ echo $"Device $devbusid could not be cleared from device blacklist"
+ fi
+ fi
+ # reevaluate since globbing might not have worked before device existed
+ dev_p=$(echo /sys/devices/css$prefix/$IDFORMAT/$devbusid)
+ if [ ! -d "$dev_p" ]; then
+ echo $"Device $devbusid does not exist"
+ all_subch_good=1
+ continue
+ fi
+ # devno does exist now
+ local subch_p=${dev_p%/*}
+ local subch=${subch_p##*/}
+ # filter definitely unusable subchannels ...
+ # - check for subchannel type I/O
+ if [ -f $subch_p/type ]; then
+ local type
+ read type < $subch_p/type
+ if [ "$type" != "$SUBCHANNEL_TYPE_IO" ]; then
+ echo $"Channel $subch (device $devbusid) is not of type I/O"
+ all_subch_good=1
+ continue
+ fi
+ fi
+ # - check for correct CU type/model, depending on qeth/lcs/ctc
+ if [ ! -f $dev_p/cutype ]; then
+ echo $"Device $devbusid does not have required sysfs attribute 'cutype'"
+ all_subch_good=1
+ continue
+ fi
+ local cutype
+ read cutype < $dev_p/cutype
+ if search_cu $cutype; then
+ if [ "${CU_DEVDRV[$cu_idx]}" != "$NETTYPE" ]; then
+ echo $"Device $devbusid has control unit type $cutype,"
+ echo $" which does not match your selected network type $NETTYPE"
+ all_subch_good=1
+ continue
+ fi
+ else
+ echo $"Device $devbusid has control unit type $cutype which is unknown"
+ all_subch_good=1
+ continue
+ fi
+ # read CHPIDs information about subchannels
+ if [ ! -f $subch_p/chpids ]; then
+ echo $"Channel $subch (device $devbusid) does not have required sysfs attribute 'chpids'"
+ all_subch_good=1
+ continue
+ fi
+ local chpid_list
+ read chpid_list < $subch_p/chpids
+ local -a chpids
+ read -a chpids <<< "$chpid_list"
+ if [ ${#chpids[@]} -ne 8 ]; then
+ echo $"sysfs reported ${#chpids[@]} CHPIDs instead of expected 8, code needs fix"
+ fi
+ if [ ! -f $subch_p/pimpampom ]; then
+ echo $"Channel $subch (device $devbusid) does not have required sysfs attribute 'pimpampom'"
+ all_subch_good=1
+ continue
+ fi
+ local pim pam pom foo
+ read pim pam pom foo < $subch_p/pimpampom
+ local pimchpidZ=""
+ for ((chp=0; chp < 8; chp++)); do
+ local mask=$((0x80 >> chp))
+ if (( 0x$pim & $mask )); then
+ pimchpidZ=${pimchpidZ}${chpids[chp]}
+ else
+ pimchpidZ=${pimchpidZ}"ZZ"
+ fi
+ done
+ local pimchpids=${pimchpidZ//ZZ/}
+ if [ "x$pimchpids" == "x" ]; then
+ echo $"Channel $subch (device $devbusid) does not have any installed channel path"
+ all_subch_good=1
+ continue
+ fi
+ # compare parts of different subchannels for required matches
+ if [ "$i" -eq 1 ]; then
+ # remember parts of first subchannel for comparison
+ local sch_r_prefix=$prefix
+ local sch_r_ssid=$ssid
+ local sch_r_devno=$devno
+ local sch_r_pimchipidZ=$pimchpidZ
+ local sch_r_cutype=$cutype
+ else
+ local comparison=0
+ # $sch_r_... might be empty if first channel was wrong
+ # => be sure to quote all variable accesses in test statements.
+ # - all subchannels must be of same CU type/model
+ if [ "$cutype" != "$sch_r_cutype" ]; then
+ echo $"Device $devbusid does not have the same control unit type as device $SCH_R_DEVBUSID"
+ comparison=1
+ fi
+ # - all subchannels must have same CHPIDs
+ if [ "$pimchpidZ" != "$sch_r_pimchipidZ" ]; then
+ echo $"Device $devbusid does not have the same CHPIDs as device $SCH_R_DEVBUSID"
+ comparison=1
+ fi
+ # - all subchannels should have same prefix & ssid ?
+ if [ "$prefix" != "$sch_r_prefix" \
+ -o "$ssid" != "$sch_r_ssid" ]; then
+ echo $"Device $devbusid does not have the same prefix and subchannel set ID as device $SCH_R_DEVBUSID"
+ comparison=1
+ fi
+ if [ "$i" -eq 2 ]; then
+ local sch_w_devbusid=$devbusid
+ local sch_w_devno=$devno
+ # - write_devbusid == read_devbusid+1
+ if [ $((0x$devno)) -ne $((0x$sch_r_devno + 1)) ]; then
+ echo $"Device bus ID of write channel (dev $devbusid) must be one larger than"
+ echo $" that of read channel (dev $SCH_R_DEVBUSID)"
+ comparison=1
+ fi
+ elif [ "$i" -eq 3 ]; then
+ # check data subchannel unequal to read/write subchannel
+ # (also seems to be handled by ccwgroup kernel subsystem)
+ if [ "$devbusid" = "$sch_w_devbusid" \
+ -o "$devbusid" = "$SCH_R_DEVBUSID" ]; then
+ echo $"Device bus ID of data channel (dev $devbusid) must be different to that of"
+ echo $" read channel ($SCH_R_DEVBUSID) and write channel ($sch_w_devbusid)"
+ comparison=1
+ fi
+ fi
+ if [ "$comparison" != 0 ]; then
+ all_subch_good=1
+ continue
+ fi
+ fi
+ # filter potentially good subchannels ...
+ if [ -h $dev_p/group_device ]; then
+ echo $"Device $devbusid is already in a ccwgroup and thus unavailable"
+ all_subch_good=1
+ continue
+ fi
+ if [ ! -f $dev_p/online ]; then
+ echo $"Device $devbusid does not have required sysfs attribute 'online'"
+ all_subch_good=1
+ continue
+ fi
+ local online
+ read online < $dev_p/online
+ if [ "$online" = "1" ]; then
+ echo $"Device $devbusid is already in use and thus unavailable"
+ all_subch_good=1
+ continue
+ fi
+ # - check availability
+ if [ ! -f $dev_p/availability ]; then
+ echo $"Device $devbusid does not have required sysfs attribute 'availability'"
+ all_subch_good=1
+ continue
+ fi
+ local availability
+ read availability < $dev_p/availability
+ if [ "$availability" != "good" ]; then
+ echo $"Device $devbusid is not available but '$availiability'"
+ all_subch_good=1
+ continue
+ fi
+
+ done # for ((i=1; i <= $subch_count; i++))
+ if [ "$all_subch_good" = "0" ]; then
+ return 0
+ fi
+ return 1
+}
+
+function handle_subchannels() {
+ # - try to establish ccwgroup right here and fail out on error
+ if sysecho /sys/bus/ccwgroup/drivers/${NETTYPE}/group "$SUBCHANNELS"; then
+ case "$NETTYPE" in
+ qeth)
+ # Just preliminary card_type info until device goes online!
+ # In fact it seems enough to separate OSA from HiperSocket.
+ if [ -f /sys/devices/qeth/$SCH_R_DEVBUSID/card_type ]; then
+ read cardtype < /sys/devices/qeth/$SCH_R_DEVBUSID/card_type
+ else
+ echo $"Could not read qeth network card type from sysfs."
+ fi
+ ;;
+ ctc|lcs)
+ if [ -f /sys/devices/cu3088/$SCH_R_DEVBUSID/type ]; then
+ local type=$(cat /sys/devices/cu3088/$SCH_R_DEVBUSID/type)
+ [ "$type" = "CTC/A" ] && type="channel-to-channel adapter"
+ echo "Detected: $type"
+ else
+ echo $"Could not read ctc network card type from sysfs."
+ fi
+ ;;
+ esac
+ return 0
+ else
+ echo $"Channels $SUBCHANNELS could not be grouped"
+ fi
+ return 1
+}
+
+function question_prefix_subchannels() {
+ if [ "$NETTYPE" = "qeth" ]; then
+ echo -n $"Read,write,data channel"
+ else
+ echo -n $"Read,write channel"
+ fi
+}
+
+function question_choices_subchannels() {
+ if [ "$NETTYPE" = "qeth" ]; then
+ echo $" (e.g. 0.0.0300,0.0.0301,0.0.0302 or ? for help)."
+ else
+ echo $" (e.g. 0.0.0600,0.0.0601 or ? for help)"
+ fi
+}
+
+function helptext_subchannels() {
+ if [ "$NETTYPE" = "qeth" ]; then
+ echo $" Help text for qeth channels:"
+ echo $" Enter the device bus ID of your CCW devices."
+ echo $" QETH needs three channels for read, write, and data,"
+ echo $" e.g. 0.0.0300,0.0.0301,0.0.0302"
+ else
+ echo $" Help text for lcs/ctc channels:"
+ echo $" Enter the device bus ID of your CCW devices."
+ echo $" CTC/ESCON and LCS need two channels for read and write,"
+ echo $" e.g. 0.0.0600,0.0.0601 will configure the CTC or ESCON interface"
+ echo $" with the channels 0x600 and 0x601"
+ fi
+}
+
+function finish_subchannels() {
+ syntax_check_subchannels || workflow_item_menu
+ # continuing on syntax error is doomed to fail,
+ # since handle_subchannels relies on the regex-based strict parsing
+ # in syntax_check_subchannels which does not match anything then
+ # news: relaxed by splitting semantic check and actual handling
+ semantic_check_subchannels || workflow_item_menu
+ if handle_subchannels; then
+ break
+ else
+ workflow_item_menu && break
+ fi
+}
+
+function do_subchannels() {
+ ask SUBCHANNELS \
+ question_prefix_subchannels question_choices_subchannels \
+ -h helptext_subchannels -f finish_subchannels
+}
+
+### PORTNAME (qeth)
+
+function syntax_check_portname() {
+ # - 1-8 characters, we convert it to upper case
+ PORTNAME=`echo $PORTNAME | tr '[:lower:]' '[:upper:]'`
+ local portname_len=${#PORTNAME}
+ if [ "$portname_len" -ge 1 -a "$portname_len" -le 8 ]; then
+ return 0
+ fi
+ echo $"Incorrect string length [1..8] for portname (PORTNAME): $PORTNAME"
+ return 1
+}
+
+function handle_portname() {
+ [ -n "$PORTNAME" ] || return 0
+ # - try to set portname right here w/ error handling
+ if sysecho /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/portname "$PORTNAME"; then
+ return 0
+ else
+ echo $"Portname '$PORTNAME' could not be configured for $SUBCHANNELS"
+ fi
+ return 1
+}
+
+function hint_portname() {
+ if [ -f /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/portname ]; then
+ local pname_hint
+ read pname_hint < /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/portname
+ if [ "$pname_hint" = "no portname required" ]; then
+ echo $" * Your configuration does not require a portname. *"
+ fi
+ fi
+}
+
+function question_prefix_portname(){
+ echo -n $"Portname"
+}
+
+function question_choices_portname(){
+ echo $" (1..8 characters, or ? for help). Default is no portname:"
+}
+
+function helptext_portname(){
+ echo $" Help text for portname:"
+ # updated text describing when portname is obsolete;
+ # taken from:
+ # SA22-7935-09, Open Systems Adapter-Express Customer's
+ # Guide and Reference, 10th ed. May 2008, IBM, p.17f.
+ # SC33-8411-00, Device Drivers, Features, and Commands,
+ # 1st ed. May 2008, IBM, p.116.
+ echo $" Portname of the OSA-Express feature in QDIO mode and z/VM Guest LAN."
+ echo $" This parameter is optional with:"
+ echo $" - z/VM 4.4.0 or z/VM 4.3.0 with APARs VM63308 and PQ73878"
+ echo $" - z800, z900 with >= Driver 3G - EC stream J11204, MCL032 (OSA level 3.33)"
+ echo $" - z890, z990, z9, z10 mainframes"
+ hint_portname
+ echo $" If portname is used, all operating systems sharing port must use same name."
+ echo $" Input empty string if you don't want to enter a portname. [default]"
+}
+
+function exception_portname(){
+ [ -z "$PORTNAME" ] && break
+}
+
+function do_portname() {
+ ask PORTNAME \
+ question_prefix_portname question_choices_portname \
+ -h helptext_portname \
+ -e exception_portname -s syntax_check_portname -c handle_portname
+}
+
+### PORTNO (qeth)
+
+function syntax_check_qeth_portno() {
+ case $PORTNO in
+ 0|1)
+ return 0
+ ;;
+ esac
+ echo $"Incorrect format or value for relative port number (PORTNO): $PORTNO"
+ return 1
+}
+
+function handle_qeth_portno() {
+ if sysecho /sys/devices/qeth/$SCH_R_DEVBUSID/portno "$PORTNO"; then
+ return 0
+ fi
+ echo $"Could not configure relative port number $PORTNO for $SUBCHANNELS"
+ return 1
+}
+
+function question_prefix_portno() {
+ echo -n $"Relative port number for OSA"
+}
+
+function question_choices_portno() {
+ echo $" (0, 1, or ? for help). Default is 0:"
+}
+
+function helptext_portno() {
+ echo $" Help text for relative port number for OSA with 2 ports per CHPID:"
+ echo $" This applies to:"
+ echo $" - OSA-Express3 Gigabit Ethernet on z10 systems"
+ echo $" - OSA-Express ATM on zSeries 800 and 900 systems"
+ echo $" 0 for relative port number 0 [default]"
+ echo $" 1 for relative port number 1"
+ echo $" Input empty string to not modify the default configuration."
+}
+
+function exception_portno() {
+ # Writing portno of e.g. hipersocket device fails.
+ # Therefore, do not configure on empty default value.
+ [ -z "$PORTNO" ] && break
+}
+
+function do_portno() {
+ ask PORTNO \
+ question_prefix_portno question_choices_portno \
+ -h helptext_portno -e exception_portno \
+ -s syntax_check_qeth_portno -c handle_qeth_portno
+}
+
+### LAYER2
+
+function syntax_check_layer2() {
+ # - $LAYER2 \in {0,1}
+ case $LAYER2 in
+ 0|1)
+ return 0
+ ;;
+ esac
+ echo $"Incorrect format or value for layer2 mode (LAYER2): $LAYER2"
+ return 1
+}
+
+function handle_layer2() {
+ [ "$NETTYPE" == "qeth" ] || return 0
+ [ -n "$LAYER2" ] || return 0
+ # - try to set layer2 mode right here w/ error handling
+ if sysecho /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/layer2 "$LAYER2"; then
+ return 0
+ else
+ echo $"Layer2 mode '$LAYER2' could not be configured for $SUBCHANNELS"
+ fi
+ return 1
+}
+
+function question_prefix_layer2() {
+ echo -n $"Layer mode"
+}
+
+function question_choices_layer2() {
+ echo -n $" (0 for layer3, 1 for layer2, or ? for help)."
+ if [ "$isLayer2Default" = "yes" ]; then
+ echo $" Default is 1:"
+ else
+ echo $" Default is 0:"
+ fi
+}
+
+function helptext_layer2() {
+ echo $" Help text for OSA mode of operation: layer 2 vs. layer 3"
+ if [ "$isLayer2Default" = "yes" ]; then
+ echo $" 0 for layer 3 mode (may not work with dhcp, tcpdump, etc.)"
+ echo $" 1 for layer 2 mode [default]"
+ else
+ echo $" 0 for layer 3 mode [default] (may not work with dhcp, tcpdump, etc.)"
+ echo $" 1 for layer 2 mode"
+ fi
+}
+
+function exception_layer2() {
+ [ -z "$LAYER2" ] && break
+}
+
+function do_layer2() {
+ isLayer2Default && isLayer2Default=yes || isLayer2Default=no
+ ask LAYER2 \
+ question_prefix_layer2 question_choices_layer2 \
+ -h helptext_layer2 -e exception_layer2 \
+ -s syntax_check_layer2 -c handle_layer2
+}
+
+### MACADDR
+
+function syntax_check_macaddr() {
+ # - match against regex
+ [[ "$MACADDR" =~ ^[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]$ ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ return 0
+ ;;
+ 1)
+ # string did not match the pattern
+ echo $"Incorrect format for mac address (MACADDR): $MACADDR"
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ return 1
+}
+
+function handle_macaddr() {
+ # - try to set macaddr right here w/ error handlg.
+ # device needs to be online
+ if debug ifconfig $DEVICE hw ether $MACADDR; then
+ return 0
+ fi
+ echo $"MAC address $MACADDR could not be configured for"
+ echo $" $SUBCHANNELS (network device $DEVICE)"
+ return 1
+}
+
+function question_prefix_macaddr() {
+ echo -n $"Unique MAC address"
+}
+
+function question_choices_macaddr() {
+ echo -n $" (e.g. 02:00:00:00:00:00, ? for help)."
+ # for virtual OSAs macaddr is optional and defaults to not specifying one
+ if [ -z "${cardtype//OSD_*/}" ]; then
+ echo
+ else
+ echo $" Default is automatic:"
+ fi
+}
+
+function helptext_macaddr() {
+ echo $" Help text for MAC address:"
+ echo $" This is required for real OSA in layer 2 mode."
+ echo $" If connecting to a layer 2 VSWITCH, a MAC address is automatically assigned."
+ echo -n $" You may accept the automatic MAC address with an empty input."
+ if [ -z "${cardtype//OSD_*/}" ]; then
+ echo
+ else
+ echo $" [default]"
+ fi
+ echo $" You may override the automatic MAC address with non-empty input."
+ echo $" An example MAC address would be: 02:00:00:00:00:00"
+}
+
+function exception_macaddr() {
+ # for real OSAs macaddr is required
+ if [ -n "${cardtype//OSD_*/}" ]; then
+ # for virtual OSAs macaddr is optional
+ if [ -z "$MACADDR" ]; then
+ VSWITCH=1
+ break
+ fi
+ fi
+}
+
+function do_macaddr() {
+ ask MACADDR \
+ question_prefix_macaddr question_choices_macaddr \
+ -h helptext_macaddr -e exception_macaddr \
+ -s syntax_check_macaddr -c handle_macaddr
+}
+
+### CTCPROT
+
+function syntax_check_ctcprot() {
+ case "x$CTCPROT" in
+ x|x0)
+ unset CTCPROT
+ return 0
+ ;;
+ x1|x3)
+ return 0
+ ;;
+ x2)
+ echo $"CTC tty's are not usable for this installation (CTCPROT)"
+ ;;
+ *)
+ echo $"Incorrect format or value for CTC protocol (CTCPROT): $CTCPROT"
+ ;;
+ esac
+ return 1
+}
+
+function handle_ctcprot() {
+ [ -n "$CTCPROT" ] || return 0
+ if sysecho /sys/devices/cu3088/${SCH_R_DEVBUSID}/protocol "$CTCPROT"; then
+ return 0
+ fi
+ echo $"Could not configure CTC protocol $CTCPROT for $SUBCHANNELS"
+ return 1
+}
+
+function question_prefix_ctcprot() {
+ echo -n $"CTC protocol"
+}
+
+function question_choices_ctcprot() {
+ echo $" (0, 1, 3, or ? for help). Default is 0:"
+}
+
+function helptext_ctcprot() {
+ echo $" Help text for CTC protocol:"
+ echo $" Protocol which should be used for the CTC interface"
+ echo $" 0 for compatibility with p.e. VM TCP service machine [default]"
+ echo $" 1 for enhanced package checking for Linux peers"
+ echo $" 3 for compatibility with OS/390 or z/OS peers"
+}
+
+function do_ctcprot() {
+ ask CTCPROT \
+ question_prefix_ctcprot question_choices_ctcprot \
+ -h helptext_ctcprot -s syntax_check_ctcprot -c handle_ctcprot
+}
+
+### PORTNAME (LCS portno)
+
+function syntax_check_lcs_portno() {
+ [[ "$PORTNAME" =~ ^[[:digit:]]+$ ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ return 0
+ ;;
+ 1)
+ # string did not match the pattern
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ echo $"Incorrect format for LCS port number (PORTNAME): $PORTNAME"
+ return 1
+}
+
+function handle_lcs_portno() {
+ [ -n "$PORTNAME" ] || return 0
+ if sysecho /sys/devices/cu3088/$SCH_R_DEVBUSID/portno "$PORTNAME"; then
+ return 0
+ fi
+ echo $"Could not configure relative port number $PORTNAME for $SUBCHANNELS"
+ return 1
+}
+
+function question_prefix_lcs_portno() {
+ echo -n $"Relative port number of your LCS device"
+}
+
+function question_choices_lcs_portno() {
+ echo $" (number or ? for help). Default is 0:"
+}
+
+function helptext_lcs_portno() {
+ echo $" Help text for relative port number of LCS device:"
+ echo $" Required for OSA-Express ATM cards only."
+}
+
+function exception_lcs_portno() {
+ [ -z "$PORTNAME" ] && break
+}
+
+function do_lcs_portno() {
+ # LCS portno and QETH portname share the parameter variable PORTNAME.
+ # For compatibility with existing parm files we keep this scheme.
+ ask PORTNAME \
+ question_prefix_lcs_portno question_choices_lcs_portno \
+ -e exception_lcs_portno \
+ -h helptext_lcs_portno -s syntax_check_lcs_portno -c handle_lcs_portno
+}
+
+### PEERID
+
+function syntax_check_peerid() {
+ if [ "${#PEERID}" -lt 0 -o "${#PEERID}" -gt 8 ]; then
+ echo $"Incorrect string length [0..8] for IUCV connection to peer (PEERID): $PEERID"
+ return 1
+ fi
+ PEERID=`echo $PEERID | tr '[:lower:]' '[:upper:]'`
+ [[ "$PEERID" =~ ^[[:alnum:]$]{0,8}$ ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ return 0
+ ;;
+ 1)
+ # string did not match the pattern
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ echo $"Incorrect format for IUCV connection to peer (PEERID): $PEERID"
+ return 1
+}
+
+function handle_peerid() {
+ if ! sysecho /sys/bus/iucv/drivers/netiucv/connection "$PEERID"; then
+ echo $"Could not create new IUCV connection to peer $PEERID"
+ return 1
+ fi
+ # find netiucv with proper guest user ID in
+ # /sys/bus/iucv/drivers/netiucv/netiucv[0-9]+/user
+ local userpath
+ while read userpath; do
+ local user
+ read user < $userpath
+ [ "$user" = "$PEERID" ] && break
+ done < <(ls -1 /sys/devices/iucv/netiucv[0-9]*/user 2> /dev/null)
+ if [ "$user" != "$PEERID" ]; then
+ echo $"Could not find configured connection to peer $PEERID"
+ return 1
+ fi
+ local netiucv=${userpath%%/user}
+ netiucv=${netiucv##*/}
+ if [ "$netiucv" = "" ]; then
+ echo $"Could not get netiucv instance for peer $PEERID"
+ return 1
+ fi
+ if [ ! -h /sys/devices/iucv/${netiucv}/net:* ]; then
+ echo $"Device $netiucv does not have required sysfs attribute 'net:*'"
+ return 1
+ fi
+ DEVICE=$(echo /sys/devices/iucv/${netiucv}/net:*)
+ DEVICE=${DEVICE//*:/}
+ if [ "$DEVICE" = "" ]; then
+ echo $"Could not get device name for $netiucv"
+ return 1
+ fi
+ return 0
+}
+
+function question_prefix_peerid() {
+ echo -n $"Peer ID of the VM guest to connect to"
+}
+
+function question_choices_peerid() {
+ echo $" (0..8 characters or ? for help):"
+}
+
+function helptext_peerid() {
+ echo $" Help text for the peer ID of the VM guest you want to connect to:"
+ echo $" User ID of a VM guest you want to connect to."
+ echo $" 0..8 alphabetic/numeric characters or dollar-signs '$'."
+ echo $" Your input will be converted to uppercase."
+}
+
+function do_peerid() {
+ ask PEERID \
+ question_prefix_peerid question_choices_peerid \
+ -h helptext_peerid -s syntax_check_peerid -c handle_peerid
+}
+
+### HOSTNAME
+
+function syntax_check_hostname() {
+ syntax_check_domainname "$HOSTNAME" $"Incorrect format for hostname (HOSTNAME): $HOSTNAME"
+}
+
+function handle_hostname() {
+ if ! hostname $HOSTNAME; then
+ echo $"Could not configure hostname $HOSTNAME"
+ return 1
+ fi
+ return 0
+}
+
+function question_prefix_hostname() {
+ echo -n $"Hostname of your new Linux guest"
+}
+
+function question_choices_hostname() {
+ echo $" (FQDN e.g. s390.redhat.com or ? for help):"
+}
+
+function helptext_hostname() {
+ echo $" Help text for hostname:"
+ echo $" Enter the full qualified domain name of your host."
+}
+
+function do_hostname() {
+ ask HOSTNAME \
+ question_prefix_hostname question_choices_hostname \
+ -h helptext_hostname -s syntax_check_hostname -c handle_hostname
+}
+
+### IPADDR
+
+function syntax_check_ipaddr() {
+ unset ipv4
+ unset ipv6
+ if checkipv4 $IPADDR; then
+ ipv4="yes"
+ return 0
+ elif [ "$ipv6_capable" = "yes" ] && checkipv6 $IPADDR; then
+ ipv6="yes"
+ return 0
+ fi
+ echo $"Incorrect format for IP address (IPADDR): $IPADDR"
+ return 1
+}
+
+function question_prefix_ipaddr() {
+ echo -n $"IPv4 address"
+ [ "$ipv6_capable" = "yes" ] && echo -n $" / IPv6 addr."
+}
+
+function question_choices_ipaddr() {
+ echo -n $" (e.g. 10.0.0.2"
+ [ "$ipv6_capable" = "yes" ] && echo -n $" / 2001:0DB8::"
+ echo $" or ? for help)"
+}
+
+function helptext_ipaddr() {
+ echo $" Help text for IP address:"
+ echo $" Enter a valid IPv4 address of your new Linux guest (e.g. 10.0.0.2)"
+ if [ "$ipv6_capable" = "yes" ]; then
+ echo $" or alternatively a valid IPv6 address without CIDR prefix (e.g. 2001:0DB8::)"
+ echo $" IPv6 is supported on:"
+ echo $" - Ethernet interfaces of the OSA-Express adapter running in QDIO mode."
+ echo $" - HiperSockets layer 2 interfaces"
+ [ $(linux_version) -ge $(kernel_version 2 6 26) ] && \
+ echo $" - HiperSockets layer 3 interfaces"
+ echo $" - z/VM guest LAN interfaces running in QDIO mode."
+ echo $" IPv6 is not supported on HiperSocket guest LAN, OSA-Express Token Ring, ATM."
+ fi
+}
+
+function do_ipaddr() {
+ ipv6_capable && ipv6_capable=yes || ipv6_capable=no
+ ask IPADDR \
+ question_prefix_ipaddr question_choices_ipaddr \
+ -h helptext_ipaddr -s syntax_check_ipaddr
+ # no handling/configuring of IPADDR yet, since more parameters needed
+}
+
+### NETMASK (IPv4)
+
+function syntax_check_netmask_v4() {
+ # also support CIDR prefix
+ if [[ "$NETMASK" =~ ^[[:digit:]]+$ ]]; then
+ if [ "$NETMASK" -ge 1 -a "$NETMASK" -le 32 ]; then
+ ipcalc_arg="$IPADDR/$NETMASK"
+ return 0
+ fi
+ echo $"Incorrect value for network prefix [1..32] (NETMASK): $NETMASK"
+ return 1
+ elif checkipv4 $NETMASK; then
+ ipcalc_arg="$IPADDR $NETMASK"
+ return 0
+ fi
+ echo $"Incorrect format or value for network mask (NETMASK): $NETMASK"
+ return 1
+}
+
+function question_prefix_netmask() {
+ echo -n $"IPv4 netmask or CIDR prefix"
+}
+
+function hint_netmask_v4() {
+ # default based on class a/b/c address
+ local a b c d
+ IFS=.
+ read a b c d <<< "$IPADDR"
+ unset IFS
+ local ip=$(( ( a << 24 ) + ( b << 16 ) + ( c << 8 ) + ( d ) ))
+ # <<EOF convince syntax highlighter that above shifts are no here documents
+ if [ $(( ip & 0x80000000 )) -eq $(( 0x00000000 )) ]; then
+ # class a
+ echo $"255.0.0.0"
+ elif [ $(( ip & 0xC0000000 )) -eq $(( 0x80000000 )) ]; then
+ # class b
+ echo $"255.255.0.0"
+ elif [ $(( ip & 0xE0000000 )) -eq $(( 0xC0000000 )) ]; then
+ # class c
+ echo $"255.255.255.0"
+ else
+ # some other class that should not be used as host address
+ return 1
+ fi
+ return 0
+}
+
+function question_choices_netmask() {
+ echo -n $" (e.g. 255.255.255.0 or 1..32 or ? for help)"
+ local default=$(hint_netmask_v4)
+ if [ -n "$default" ]; then
+ echo $". Default is $default:"
+ else
+ echo $":"
+ echo $"The IP address you entered previously should probably not be used for a host."
+ fi
+}
+
+function helptext_netmask() {
+ echo $" Help text for IPv4 netmask or CIDR prefix:"
+ echo $" Enter a valid IPv4 netmask or CIDR prefix (e.g. 255.255.255.0 or 1..32)"
+ local default=$(hint_netmask_v4)
+ if [ -n "$default" ]; then
+ echo $" Default is $default"
+ else
+ echo $"The IP address you entered previously should probably not be used for a host."
+ fi
+}
+
+function exception_netmask() {
+ if [ -z "$NETMASK" ]; then
+ NETMASK=$(hint_netmask_v4)
+ fi
+}
+
+function do_netmask() {
+ ask NETMASK \
+ question_prefix_netmask question_choices_netmask \
+ -h helptext_netmask \
+ -s syntax_check_netmask_v4 -e exception_netmask
+ # no handling/configuring of NETMASK yet, since more parameters needed
+}
+
+### NETMASK (IPv6)
+
+function syntax_check_prefix_v6() {
+ if [[ "$NETMASK" =~ ^[[:digit:]]+$ ]]; then
+ if [ "$NETMASK" -ge 1 -a "$NETMASK" -le 128 ]; then
+ return 0
+ fi
+ fi
+ echo $"Incorrect value for network prefix [1..128] (NETMASK): $NETMASK"
+ return 1
+}
+
+function question_prefix_netmask_v6() {
+ echo -n $"CIDR prefix for the IPv6 address"
+}
+
+function question_choices_netmask_v6() {
+ echo $" (1..128):"
+}
+
+function do_netmask_v6() {
+ ask NETMASK \
+ question_prefix_netmask_v6 question_choices_netmask_v6 \
+ -s syntax_check_prefix_v6
+ # no handling/configuring of NETMASK yet, since more parameters needed
+}
+
+### GATEWAY (IPv4)
+
+function configure_ipv4_gateway() {
+ # FIXME:
+ # - Strictly speaking we should first check reachability of gateway
+ # and then configure the gateway route.
+ # This would require a new intermediate workflow_item step
+ # so that the user might continue despite unreachable gateway.
+ # done: Only adding default route might add multiple undesired default
+ # routes on redoing the parameter item, so delete default route
+ # before adding a new one.
+ ip -4 route del default dev $DEVICE >& /dev/null
+ [ -z "$GATEWAY" ] && return 0
+ if ! tv route add default gw $GATEWAY dev $DEVICE; then
+ echo $"Could net set default route on device $DEVICE via gateway $GATEWAY"
+ return 1
+ fi
+ # BH FIXME: Workaround for manual MACADDR, need ping to update arp table
+ echo $"Trying to reach gateway $GATEWAY..."
+ if [ "$NETTYPE" = "ctc" ]; then
+ # (virtual) CTC(/A) seems to need some time to get functional
+ local i=1
+ while : ; do
+ ping -c 1 $GATEWAY >& /dev/null && break
+ i=$((i+1))
+ if [ "$i" -gt 3 ]; then
+ echo $"Could not reach gateway $GATEWAY within timeout"
+ return 1
+ fi
+ done
+ else
+ if ! ping -c 1 $GATEWAY >& /dev/null; then
+ echo $"Could not reach your default gateway $GATEWAY"
+ return 1
+ fi
+ fi
+ return 0
+}
+
+function hint_ipv4_gateway() {
+ # - provide default suggestion based on network,
+ # for a class C network this would be either .1 or .254 at the end
+ local a b c d
+ IFS=.
+ read a b c d <<< "$NETWORK"
+ unset IFS
+ local ip=$(( ( a << 24 ) + ( b << 16 ) + ( c << 8 ) + ( d ) ))
+ # <<EOF convince syntax highlighter that above shifts are no here documents
+ local lo=$(( ip | 1 ))
+ local lo_a=$(( (lo & 0xFF000000) >> 24 ))
+ local lo_b=$(( (lo & 0x00FF0000) >> 16 ))
+ local lo_c=$(( (lo & 0x0000FF00) >> 8 ))
+ local lo_d=$(( (lo & 0x000000FF) ))
+ local hi=$(( ip | ( (2**(32 - PREFIX)) - 1 ) ))
+ local hi_a=$(( (hi & 0xFF000000) >> 24 ))
+ local hi_b=$(( (hi & 0x00FF0000) >> 16 ))
+ local hi_c=$(( (hi & 0x0000FF00) >> 8 ))
+ local hi_d=$(( (hi & 0x000000FE) ))
+ echo $" Depending on your network design patterns, the default gateway"
+ echo $" might be $lo_a.$lo_b.$lo_c.$lo_d or $hi_a.$hi_b.$hi_c.$hi_d"
+}
+
+function question_prefix_gateway() {
+ echo -n $"IPv4 address of your default gateway"
+}
+
+function question_choices_gateway() {
+ echo $" or ? for help:"
+}
+
+function helptext_gateway() {
+ echo $" Help text for IPv4 default gateway:"
+ echo $" For HiperSockets with internal traffic only you may want to leave this empty"
+ echo $" and choose continue afterwards to go on without gateway."
+ hint_ipv4_gateway
+}
+
+function finish_gateway() {
+ if ! checkipv4 $GATEWAY; then
+ # above checkipv4 is silent, so make up for syntax error
+ echo $"Incorrect format for IPv4 address of gateway (GATEWAY): $GATEWAY"
+ workflow_item_menu
+ fi
+ if configure_ipv4_gateway; then
+ break
+ else
+ workflow_item_menu && break
+ fi
+}
+
+# FIXME: allow empty/no gateway?
+
+function do_gateway() {
+ ask GATEWAY \
+ question_prefix_gateway question_choices_gateway \
+ -h helptext_gateway -f finish_gateway
+}
+
+### GATEWAY (IPv6)
+
+function configure_ipv6_gateway() {
+ # FIXME:
+ # - Strictly speaking we should first check reachability of gateway
+ # and then configure the gateway route.
+ # This would require a new intermediate workflow_item step
+ # so that the user might continue despite unreachable gateway.
+ # done: Only adding default route might add multiple undesired default
+ # routes on redoing the parameter item, so delete default route
+ # before adding a new one.
+ ip -6 route del default dev $DEVICE >& /dev/null
+ [ -z "$GATEWAY" ] && return 0
+ # IPv6 http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/Linux+IPv6-HOWTO.html#AEN1147
+ # ip -6 route add ::/0 dev $DEVICE via $GATEWAY
+ # (Could also be learned by autoconfiguration on the link:
+ # after IP address setup and device up,
+ # see if default route has been learned
+ # ip -6 route show | grep ^default
+ # However, we currently use manual IPv6 configuration only.)
+ if ! debug ip -6 route add ::/0 dev $DEVICE via $GATEWAY; then
+ echo $"Could net set default route on device $DEVICE"
+ echo $" via gateway $GATEWAY"
+ return 1
+ fi
+ # BH FIXME: Workaround for manual MACADDR, need ping to update arp table
+ echo $"Trying to reach gateway $GATEWAY..."
+ if ! ping6 -c 1 $GATEWAY >& /dev/null; then
+ echo $"Could not reach your default gateway $GATEWAY"
+ return 1
+ fi
+ return 0
+}
+
+function question_prefix_gateway_v6() {
+ echo -n $"IPv6 address of your default gateway"
+}
+
+function question_choices_gateway_v6() {
+ echo $":"
+}
+
+function helptext_gateway_v6() {
+ echo $" Help text for IPv6 default gateway:"
+ echo $" For HiperSockets with internal traffic only you may want to leave this empty"
+ echo $" and choose continue afterwards to go on without gateway."
+}
+
+function finish_gateway_v6() {
+ if ! checkipv6 $GATEWAY; then
+ # above checkipv6 is silent, so make up for syntax error
+ echo $"Incorrect format for IPv6 address of gateway (GATEWAY): $GATEWAY"
+ workflow_item_menu
+ fi
+ if configure_ipv6_gateway; then
+ break
+ else
+ workflow_item_menu && break
+ fi
+}
+
+# FIXME: allow empty/no gateway?
+
+function do_gateway_v6() {
+ ask GATEWAY \
+ question_prefix_gateway_v6 question_choices_gateway_v6 \
+ -h helptext_gateway_v6 -f finish_gateway_v6
+}
+
+### GATEWAY (IPv4, point-to-point)
+
+function configure_ipv4_ptp() {
+ # device needs to be online
+ if debug ifconfig $DEVICE $IPADDR $MMTU pointopoint $GATEWAY; then
+ configure_ipv4_gateway
+ return $?
+ fi
+ echo $"Could not set IPv4 address $IPADDR for device $DEVICE"
+ echo $" to peer $GATEWAY"
+ [ -n "$MMTU" ] && echo $" and maximum transfer unit: $MMTU"
+ return 1
+}
+
+function question_prefix_ptp_gateway() {
+ echo -n $"IPv4 address of your point-to-point partner"
+}
+
+function question_choices_ptp_gateway() {
+ echo $" or ? for help:"
+ # no hinting possible here
+}
+
+function helptext_ptp_gateway() {
+ echo $" Help text for point-to-point partner:"
+ echo $" IPv4 address of your CTC / ESCON / IUCV point-to-point partner."
+}
+
+function finish_ptp_gateway() {
+ if checkipv4 $GATEWAY; then
+ if [ "$GATEWAY" = "$IPADDR" ]; then
+ echo $"IPv4 address of partner should probably be different from the guest's address"
+ workflow_item_menu && break
+ else
+ break
+ fi
+ else
+ # above checkipv4 is silent, so make up for syntax error
+ echo $"Incorrect format for IPv4 address of partner (GATEWAY): $GATEWAY"
+ workflow_item_menu && break
+ fi
+ # too early to actually configure gateway
+}
+
+function do_ptp_gateway() {
+ ask GATEWAY \
+ question_prefix_ptp_gateway question_choices_ptp_gateway \
+ -h helptext_ptp_gateway -f finish_ptp_gateway
+}
+
+### DNS
+
+function syntax_check_dns() {
+ if [ -z "$DNS" ]; then
+ echo $"You might encounter problems without a nameserver, especially with FTP installs"
+ return 1
+ fi
+ local dnsitem
+ local allgood="yes"
+ if [ "$ipv6" ]; then
+ while read dnsitem; do
+ if ! checkipv6 $dnsitem; then
+ echo $"Not a valid IPv6 address for DNS server: $dnsitem"
+ allgood="no"
+ fi
+ done < <(echo $DNS | sed 's/,/\n/g')
+ else
+ while read dnsitem; do
+ if ! checkipv4 $dnsitem; then
+ echo $"Not a valid IPv4 address for DNS server: $dnsitem"
+ allgood="no"
+ fi
+ done < <(echo $DNS | sed 's/:/\n/g')
+ fi
+ if [ "$allgood" = "yes" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function handle_dns() {
+ # - foreach DNS try if server is reachable by one ping
+ [ -z "$DNS" ] && return 0
+ local dnsitem
+ local allgood="yes"
+ echo $"Trying to reach DNS servers..."
+ if [ "$ipv6" ]; then
+ while read dnsitem; do
+ if ! ping6 -c 1 $dnsitem >& /dev/null; then
+ echo $"Could not ping DNS server (might still serve DNS requests): $dnsitem"
+ allgood="no"
+ # this should not be a hard failure since some network
+ # environments may prevent pings to DNS servers
+ # => prevent workflow_item_menu in kickstart mode
+ fi
+ done < <(echo $DNS | sed 's/,/\n/g')
+ else
+ while read dnsitem; do
+ # Some network environment may prevent a DNS server from being
+ # reachable by ping, so it would make sense to use nslookup.
+ # However, nslookup fails with "Resolver Error 0 (no error)"
+ # at this stage of the setup progress => not useful
+ if ! ping -c 1 $dnsitem >& /dev/null; then
+ echo $"Could not ping DNS server: $dnsitem"
+# if nslookup $dnsitem $dnsitem >& /dev/null; then
+# echo $" but could resolve DNS server with itself: $dnsitem"
+# else
+# echo $"Could not resolve DNS server with itself: $dnsitem"
+# allgood="no"
+# fi
+# elif ! nslookup $dnsitem $dnsitem >& /dev/null; then
+# echo $"Could not resolve DNS server with itself: $dnsitem"
+ allgood="no"
+ fi
+ done < <(echo $DNS | sed 's/:/\n/g')
+ fi
+ if [ "$allgood" = "yes" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function question_prefix_dns() {
+ if [ "$ipv6" ]; then
+ echo -n $"IPv6 addresses of DNS servers"
+ else
+ echo -n $"IPv4 addresses of DNS servers"
+ fi
+}
+
+function question_choices_dns() {
+ if [ "$ipv6" ]; then
+ echo $" (separated by commas ',' or ? for help):"
+ else
+ echo $" (separated by colons ':' or ? for help):"
+ fi
+}
+
+function helptext_dns() {
+ echo $" Help text for DNS servers:"
+ if [ "$ipv6" ]; then
+ echo $" Enter IPv6 addresses of DNS servers separated by commas ','"
+ else
+ echo $" Enter IPv4 addresses of DNS servers separated by colons ':'"
+ fi
+ echo $" Default are no DNS servers at all."
+ echo $" However, you might encounter problems without a nameserver,"
+ echo $" especially with FTP installs."
+ if [ "$ipv6" ]; then
+ echo $" An example with 2 servers would be: 2001:0DB8::42,2001:0DB8::BE:AF"
+ else
+ echo $" An example with 2 servers would be: 10.0.0.250:10.1.1.1"
+ fi
+}
+
+function do_dns() {
+ ask DNS \
+ question_prefix_dns question_choices_dns \
+ -h helptext_dns -s syntax_check_dns -c handle_dns
+}
+
+### SEARCHDNS
+
+function syntax_check_searchdns() {
+ [ -z "$SEARCHDNS" ] && return 0
+ local dnsitem
+ local allgood="yes"
+ while read dnsitem; do
+ syntax_check_domainname "$dnsitem" $"Not a valid DNS search domain: $dnsitem" || allgood="no"
+ done < <(echo $SEARCHDNS | sed 's/:/\n/g')
+ if [ "$allgood" = "yes" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function question_prefix_searchdns() {
+ echo -n $"DNS search domains"
+}
+
+function question_choices_searchdns() {
+ echo $" (separated by colons ':' or ? for help):"
+}
+
+function helptext_searchdns() {
+ echo $" Help text for DNS search domains:"
+ echo $" Enter search domains according to hostname syntax separated by colons."
+ echo $" Default are no DNS search domains at all."
+ echo $" An example would be: subdomain.domain.com:domain.com"
+}
+
+function do_searchdns() {
+ ask SEARCHDNS \
+ question_prefix_searchdns question_choices_searchdns \
+ -h helptext_searchdns -s syntax_check_searchdns
+}
+
+### DASD
+
+function parse_dasd() {
+ local handle
+ [ "$1" = "-h" ] && handle=yes || unset handle
+ local dasditem
+ local allgood="yes"
+ while read dasditem; do
+ case $dasditem in
+ autodetect|probeonly|nopav) continue ;;
+ "") continue ;; # empty range
+ *) local range features
+ IFS='('
+ read range features <<< "$dasditem"
+ unset IFS
+ # parse: dev OR dev'-'dev
+ local lo=${range%%-*}
+ [[ "$lo" =~ (^[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]]
+ case $? in
+ 0) ;; # string matched the pattern
+ 1) # string did not match the pattern
+ if [ -z "$handle" ]; then
+ echo $"Incorrect format for lower bound of DASD range $range: $lo"
+ allgood="no"
+ fi
+ ;;
+ 2) echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;;
+ *) echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;;
+ esac
+ if [ "${range//*-*/}" = "" ]; then
+ local hi=${range##*-}
+ [[ "$hi" =~ (^[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]]
+ case $? in
+ 0) ;; # string matched the pattern
+ 1) # string did not match the pattern
+ if [ -z "$handle" ]; then
+ echo $"Incorrect format for upper bound of DASD range $range: $hi"
+ allgood="no"
+ fi
+ ;;
+ 2) echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;;
+ *) echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;;
+ esac
+ fi
+ if [ "$handle" = "yes" ]; then
+ if ! sysecho /proc/cio_ignore "free $range"; then
+ echo $"Could not free DASD device $range from device blacklist"
+ allgood="no"
+ fi
+ fi
+ if [ "${features//*)/}" != "" ]; then
+ if [ -z "$handle" ]; then
+ echo $"Missing closing parenthesis at features of DASD range $range: ($features"
+ allgood="no"
+ fi
+ fi
+ [ -z "$features" ] && continue
+ features="${features%)}"
+ while read feature; do
+ case $feature in
+ ro|diag|erplog) continue ;;
+ *) if [ -z "$handle" ]; then
+ echo $"Unknown DASD feature for device range $range: $feature"
+ allgood="no"
+ fi
+ ;;
+ esac
+ done < <(echo $features | sed 's/:/\n/g')
+ ;;
+ esac
+ done < <(echo $DASD | sed 's/,/\n/g')
+ if [ "$handle" = "yes" ]; then
+ udevsettle
+ sleep 1
+ fi
+ if [ "$allgood" = "yes" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function syntax_check_dasd() {
+ parse_dasd
+ return $?
+}
+
+function handle_dasd() {
+ parse_dasd -h
+ return $?
+}
+
+function question_prefix_dasd() {
+ echo -n $"DASD range"
+}
+
+function question_choices_dasd() {
+ echo $" (e.g. 200-203,205 or ? for help). Default is autoprobing:"
+}
+
+function helptext_dasd() {
+ echo $" Help text for DASD range:"
+ echo $" Comma separated list of ranges of device bus IDs."
+ echo $" Default is autoprobing (not recommended)."
+ echo $" Examples would be: 200-203 or 200,201,202,203 or 0.0.0200-0.0.0203,0.0.0205"
+}
+
+function exception_dasd() {
+ [ -z "$DASD" ] && break
+}
+
+function do_dasd() {
+ ask DASD \
+ question_prefix_dasd question_choices_dasd \
+ -h helptext_dasd -e exception_dasd -s syntax_check_dasd -c handle_dasd
+}
+
+### FCP
+
+function syntax_check_fcp() {
+ local allgood="yes"
+ local i
+ for i in ${!FCP_*}; do
+ local -a fcp
+ local devno wwpn lun
+ read -a fcp <<< "${!i}"
+ case ${#fcp[@]} in
+ 3)
+ devno=${fcp[0]}
+ wwpn=${fcp[1]}
+ lun=${fcp[2]}
+ ;;
+ 5)
+ devno=${fcp[0]}
+ wwpn=${fcp[2]}
+ lun=${fcp[4]}
+ echo $"Deprecated number of FCP arguments (5 instead of 3): "
+ echo $" $i=\"${!i}\""
+ echo $" should instead be: "
+ echo $" $i=\"$devno $wwpn $lun\""
+ ;;
+ *)
+ echo $"Unsupported number of FCP arguments (${#fcp[@]} instead of 3) in:"
+ echo $" $i=\"${!i}\""
+ allgood="no"
+ continue
+ ;;
+ esac
+ [[ "$devno" =~ (^[[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]]
+ case $? in
+ 0) ;; # string matched the pattern
+ 1) # string did not match the pattern
+ echo $"Incorrect format for FCP device $devno in:"
+ echo $" $i=\"${!i}\""
+ allgood="no"
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ # zfcp.py:class ZFCPDevice would also accept WWPN without leading 0x
+ [[ "$wwpn" =~ ^0x[[:xdigit:]]{16}$ ]]
+ case $? in
+ 0) ;; # string matched the pattern
+ 1) # string did not match the pattern
+ echo $"Incorrect format for FCP WWPN $wwpn in:"
+ echo $" $i=\"${!i}\""
+ allgood="no"
+ ;;
+ 2) echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;;
+ *) echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;;
+ esac
+ # zfcp.py:class ZFCPDevice would also accept LUN without leading 0x
+ # zfcp.py:class ZFCPDevice would also accept 16 bit LUN and pads with 0
+ [[ "$lun" =~ ^0x[[:xdigit:]]{8}0{8}$ ]]
+ case $? in
+ 0) ;; # string matched the pattern
+ 1) # string did not match the pattern
+ echo $"Incorrect format for FCP LUN $lun in:"
+ echo $" $i=\"${!i}\""
+ allgood="no"
+ ;;
+ 2)
+ echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+ ;;
+ *)
+ echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+ ;;
+ esac
+ done
+ if [ "$allgood" = "yes" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+###
+
+function show_parms() {
+ # The only issue with this stateless approach to showing parameters based
+ # on their content being non-empty is, that parameters with defaults
+ # such as LAYER2, (PORTNAME,) CTCPROT, PORTNO (,MACADDR) won't be shown
+ # if the user just hit enter, so the parm file would be "incomplete".
+ # However this is not easy to fix in here, since it would require the
+ # inter-parameter dependenies coded below in the main part, e.g. an
+ # empty LAYER2 should only be printed with default value if $NETTYPE=qeth.
+ # For the time being, at least the parameters LAYER2, PORTNAME, and CTCPROT
+ # only get asked on being empty if not running in kickstart mode.
+ cat << EOF
+NETTYPE=$NETTYPE
+IPADDR=$IPADDR
+NETMASK=$NETMASK
+GATEWAY=$GATEWAY
+HOSTNAME=$HOSTNAME
EOF
- for i in 2 3 4 5 6 7 8 9 ; do
- ln -s console /dev/tty$i
- done
- mkdir /dev/pts
+ [ "$SUBCHANNELS" ] && echo "SUBCHANNELS=$SUBCHANNELS"
+ [ "$LAYER2" ] && echo "LAYER2=$LAYER2"
+ [ "$VSWITCH" ] && echo "VSWITCH=$VSWITCH"
+ [ "$MACADDR" ] && echo "MACADDR=$MACADDR"
+ [ "$PORTNAME" ] && echo "PORTNAME=$PORTNAME"
+ [ "$PORTNO" ] && echo "PORTNO=$PORTNO"
+ [ "$PEERID" ] && echo "PEERID=$PEERID"
+ [ "$CTCPROT" ] && echo "CTCPROT=$CTCPROT"
+ if [ -n "$mmtu_was_set" ]; then
+ echo "MMTU=\"$MMTU\""
+ elif [ -n "$mtu_was_set" ]; then
+ echo "MTU=$MTU"
+ fi
+ [ "$DNS" ] && echo "DNS=$DNS"
+ [ "$SEARCHDNS" ] && echo "SEARCHDNS=$SEARCHDNS"
+ [ "$DASD" ] && echo "DASD=$DASD"
}
+function final_check() {
+ # final check && break
+ if [ -z "$interaction_happened" ]; then
+ # if parm file was good enough just continue without interaction
+ break
+ return 0
+ fi
+ while : ; do
+ # optionally consider "continue" as default
+ # but then again the user may inadvertently continue
+ echo
+ echo $"c) continue, p) parm file/configuration, n) network state, r) restart, s) shell"
+ local answer
+ read answer
+ case $answer in
+ c) return 0 ;;
+ p) echo
+ show_parms ;;
+ n) # show interfaces and routing table
+ ifconfig -a
+ if [ "$ipv6" ]; then
+ #route -n -A inet6
+ # the following produces more compact output for 80 columns
+ ip -6 route show | grep -v "^unreachable "
+ else
+ route -n
+ fi
+ ;;
+ r) break ;;
+ s) echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
+ /bin/bash
+ ;;
+ esac
+ done
+ return 1
+}
+
+### MAIN ###
+
S390ARCH=`uname -m`
if [ "$S390ARCH" = "s390" ]; then
- export S390ARCH="S/390"
+ export S390ARCH="S/390"
else
- export S390ARCH="zSeries"
+ export S390ARCH="zSeries"
fi
+echo
echo $"Starting the $S390ARCH initrd to configure networking. Version is $VERSION"
-
# set up env vars as we do in init.c
if [ `uname -m` = "s390x" ]; then
- LD_LIBRARY_PATH=/lib64:/usr/lib64:/usr/X11R6/lib64:/usr/kerberos/lib64:/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
+ LD_LIBRARY_PATH=/lib64:/usr/lib64:/usr/X11R6/lib64:/usr/kerberos/lib64:/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
else
- LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
+ LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
fi
export LD_LIBRARY_PATH
@@ -202,358 +2775,281 @@ export HOME
PYTHONPATH=/tmp/updates
export PYTHONPATH
-mount -t proc none /proc
-mount -t tmpfs none /dev
-createDevices
-mount -t devpts /dev/pts /dev/pts
-mount -t sysfs none /sys
-# remount root fs rw
-mount /dev/root / -o remount,rw
+if [ -z "$testing" ]; then
-# limit output on x3270 console (well, not really -- need debugging now)
-echo "8 4 1 1" > /proc/sys/kernel/printk
+ mount -t proc none /proc
+ mount -t tmpfs none /dev
+ createDevices
+ mount -t devpts /dev/pts /dev/pts
+ mount -t sysfs none /sys
+ # remount root fs rw
+ mount /dev/root / -o remount,rw
-# make /tmp/ramfs
-mount -t ramfs none /tmp
+ # limit output on x3270 console
+ # (console_loglevel of 4 is just right to not get driver info, e.g. from qeth,
+ # since that would mix up with the user dialog)
+ echo "4 4 1 7" > /proc/sys/kernel/printk
-ifconfig lo 127.0.0.1 netmask 255.0.0.0
-route add -host 127.0.0.1 dev lo 2>/dev/null
+ # make /tmp/ramfs
+ mount -t ramfs none /tmp
-echo -e "127.0.0.1\tlocalhost.localdomain localhost" > /etc/hosts
-echo -e "::1\t\tlocalhost6.localdomain6 localhost6" >> /etc/hosts
+ ifconfig lo 127.0.0.1 netmask 255.0.0.0
+ route add -host 127.0.0.1 dev lo
-LO=""
+ echo -e "127.0.0.1\tlocalhost.localdomain localhost" > /etc/hosts
+ echo -e "::1\t\tlocalhost6.localdomain6 localhost6" >> /etc/hosts
-[ -L /sbin/insmod ] && LO=".ko"
+ LO=""
-# Parse configuration
-if [ -n "$CMSDASD" -a -n "$CMSCONFFILE" ]; then
- readcmsfile $CMSDASD $CMSCONFFILE
- source /tmp/$CMSCONFFILE #2>/dev/null
-fi
+ [ -L /sbin/insmod ] && LO=".ko"
+
+ # udevd req'd by udevsettle in readcmsfile, dialog_network_table, and
+ # semantic_check_subchannels.
+ # (important to start udevd at the right time, e.g. after setup of /dev)
+ udevd --daemon
+
+ # Parse configuration
+ if [ -n "$CMSDASD" -a -n "$CMSCONFFILE" ]; then
+ readcmsfile $CMSDASD $CMSCONFFILE
+ source /tmp/$CMSCONFFILE #2>/dev/null
+ fi
+
+fi # testing
+
+### MAIN (continuation) ###
if [ -r /sys/firmware/ipl/ipl_type ]; then
- if [ "`cat /sys/firmware/ipl/ipl_type`" = "fcp" ]; then
- while [ 1 ]; do
- echo $"Your IPL device is set to FCP."
- echo $"Would you like to perform a CD-ROM/DVD-ROM installation? (y/n)"
- read do_cd_install
- case $do_cd_install in
- y|Y|[Yy][Ee][Ss])
- # set up FCP cdrom here
- insmod qdio$LO
- insmod scsi_mod$LO
- insmod scsi_transport_fc$LO
- insmod zfcp$LO
- CD_DEVICE="`cat /sys/firmware/ipl/device`"
- WWPN="`cat /sys/firmware/ipl/wwpn`"
- LUN="`cat /sys/firmware/ipl/lun`"
- echo 1 > /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/online
- echo $WWPN > /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/port_add
- echo $LUN > /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/$WWPN/unit_add
- break
- ;;
- n|N|[Nn][Oo])
- break
- ;;
- *)
- echo
- echo $"*** INVALID ANSWER: $do_cd_install"
- echo
- unset do_cd_install
- ;;
- esac
- done
- fi
+ if [ "`cat /sys/firmware/ipl/ipl_type`" = "fcp" ]; then
+ while [ 1 ]; do
+ echo $"Your IPL device is set to FCP."
+ echo $"Would you like to perform a CD-ROM/DVD-ROM installation? (y/n)"
+ read do_cd_install
+ case $do_cd_install in
+ y|Y|[Yy][Ee][Ss])
+ insert_module qdio$LO
+ insert_module scsi_mod$LO
+ insert_module scsi_transport_fc$LO
+ insert_module zfcp$LO
+ CD_DEVICE="`cat /sys/firmware/ipl/device`"
+ WWPN="`cat /sys/firmware/ipl/wwpn`"
+ LUN="`cat /sys/firmware/ipl/lun`"
+ if sysecho /proc/cio_ignore "free $CD_DEVICE"; then
+ udevsettle
+ sleep 1
+ else
+ echo $"Device $CD_DEVICE could not be cleared from device blacklist"
+ fi
+ echo 1 > /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/online
+ [ $? == 0 ] || echo $"Could not set FCP device $CD_DEVICE online"
+ echo $WWPN > /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/port_add
+ [ $? == 0 ] || echo $"Could not add WWPN $WWPN on FCP device $CD_DEVICE"
+ echo $LUN > /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/$WWPN/unit_add
+ [ $? == 0 ] || echo $"Could not add LUN $LUN at WWPN $WWPN on FCP device $CD_DEVICE"
+ break
+ ;;
+ n|N|[Nn][Oo])
+ break
+ ;;
+ *)
+ echo
+ echo $"*** INVALID ANSWER: $do_cd_install"
+ echo
+ unset do_cd_install
+ ;;
+ esac
+ done
+ fi
fi
# Perform a network installation
+
+[ -n "$MTU" ] && mtu_was_set=$MTU
+[ -n "$MMTU" ] && mmtu_was_set=$MMTU
+[ -n "$VSWITCH" ] && vswitch_was_set=$VSWITCH
+
+# [ -z "${cardtype//OSD_*/}" ] can be used to check for real OSA
+
+# Parse configuration
# Check for missing parameters, prompt for them if necessary
-while [ -z "$NETTYPE" ]; do
- echo $"Which kind of network device do you intend to use"
- echo $" (e.g. ctc, iucv, qeth, lcs)."
- echo $"Enter 'qeth' for OSA-Express Fast Ethernet, Gigabit Ethernet"
- echo $" (including 1000Base-T), High Speed Token Ring, and ATM "
- echo $" (running Ethernet LAN emulation) features in QDIO mode."
- echo $"Enter 'lcs' for OSA­2 Ethernet/Token Ring, OSA-Express Fast Ethernet in"
- echo $" non-QDIO mode, OSA-Express High Speed Token Ring in non-QDIO mode and"
- echo $" Gigabit Ethernet in non-QDIO mode."
- read NETTYPE
-done
-if [ "$NETTYPE" != "iucv" ]; then # iucv is the only interface without ccw config
- if [ -n "$CHANDEV" ]; then
- echo
- echo $"The CHANDEV variable isn't used anymore, please update your "
- echo $".parm or the .conf file"
- echo
- fi
- while [ -z "$SUBCHANNELS" ]; do
- echo $"Enter the bus ID and the device number of your CCW devices."
- echo $"CTC/ESCON and LCS need two subchannels:"
- echo $"(e.g. \"0.0.0600,0.0.0601\" will configure the CTC or ESCON interface"
- echo $"with the subchannels 0x600 and 0x601)"
- echo $"QETH needs three subchannels p.e. 0.0.0300,0.0.0301,0.0.0302"
- read SUBCHANNELS
- done
- SUBCHANNELS=`echo $SUBCHANNELS | /sbin/busybox tr ABCDEF abcdef`
- if [ "$NETTYPE" = "qeth" ]; then
- if [ -z "$PORTNAME" ]; then
- echo $"Portname of the OSA-Express feature in QDIO mode and z/VM Guest LAN"
- echo $"This parameter is optional with z/VM 4.4.0 or z/VM 4.3.0 with"
- echo $"APARs VM63308 and PQ73878"
- echo $"Press enter if you don't want to enter a portname"
- read PORTNAME
- fi
- if [ -z "$LAYER2" ]; then
- echo $"Enter the mode of operation for the OSA device"
- echo $"0 for layer 3 mode (default)"
- echo $"1 for layer 2 mode"
- read LAYER2
- fi
- if [ "$LAYER2" == 1 ]; then
- if [ -z "$VSWITCH" -o "$VSWITCH" == 0 ]; then
- if [ -z "$MACADDR" ]; then
- echo $"Enter a unique MAC address (eg. 02:00:00:00:00:00)."
- echo $"Leave this blank and press enter if connecting to a"
- echo $"Layer 2 VSWITCH, as this is automatically assigned"
- read MACADDR
- fi
- fi
- fi
- fi
-fi
+while : ; do
-while [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; do
- echo $"Enter the FQDN of your new Linux guest (e.g. s390.redhat.com):"
- read HOSTNAME
-done
-while [ -z "$IPADDR" ]; do
- echo $"Enter a valid IP address of your new Linux guest:"
- read IPADDR
- checkip $IPADDR
- ret=$?
- if [ $ret -eq 1 ]; then
- echo -n "Invalid IP address format. "
- unset IPADDR
- fi
-done
-while [ -z "$NETWORK" ]; do
- echo $"Enter a valid network address of the new Linux guest:"
- read NETWORK
- checkip $NETWORK
- ret=$?
- if [ $ret -eq 1 ]; then
- echo -n "Invalid network address format. "
- unset NETWORK
- fi
-done
-if [ "$NETTYPE" = "qeth" ] || [ "$NETTYPE" = "lcs" ]; then
- while [ -z "$NETMASK" ]; do
- echo $"Enter the netmask for the new Linux guest (e.g. 255.255.255.0):"
- read NETMASK
- checkip $NETMASK
- ret=$?
- if [ $ret -eq 1 ]; then
- echo -n "Invalid netmask format. "
- unset NETMASK
- fi
- done
- while [ -z "$BROADCAST" ]; do
- echo $"Enter the broadcast address for the new Linux guest:"
- read BROADCAST
- checkip $BROADCAST
- ret=$?
- if [ $ret -eq 1 ]; then
- echo -n "Invalid broadcast address format. "
- unset BROADCAST
- fi
- done
- while [ -z "$GATEWAY" ]; do
- echo $"Enter your default gateway:"
- read GATEWAY
- checkip $GATEWAY
- ret=$?
- if [ $ret -eq 1 ]; then
- echo -n "Invalid gateway address format. "
- unset GATEWAY
- fi
- done
- if [ ":$NETTYPE" = ":lcs" ]; then
- if [ -n "$RUNKS" -a -z "$PORTNAME" ]; then
- PORTNAME=0
- fi
- while [ -z "$PORTNAME" ]; do
- echo $"Enter the relative port number of your LCS device"
- echo $"(required for OSA-Express ATM cards only):"
- read PORTNAME
- done
+ # do not show list of possible network device configurations, if:
+ # - running unattended install with kickstart
+ # - relevant parameters have already been specified in parm file
+ # (a possible optimization would be matching those parms to table entry)
+ # - dialog has not been restarted
+ [ -n "$reenter" \
+ -o -z "$RUNKS" -a \( -z "$NETTYPE" -o -z "$SUBCHANNELS" \) ] && \
+ dialog_network_table
+ if isVM; then
+ echo $"* NOTE: To enter default or empty values press enter twice. *"
+ fi
+ do_nettype
+ tv load_kernel_modules
+ # only works, if ipv6 kernel module has been loaded before:
+ [ "$NETTYPE" = "qeth" ] && tv disable_ipv6_autoconf
+ if [ "$NETTYPE" != "iucv" ]; then
+ # all interface types except for iucv have ccw config
+ [ -n "$CHANDEV" ] && do_chandev
+ do_subchannels
+ if [ "$NETTYPE" = "qeth" ]; then
+ [ -z "$reenter" -a -n "$RUNKS" -a -z "$PORTNAME" ] || \
+ [ -n "${cardtype//OSD_*/}" ] || do_portname
+ # See also https://bugzilla.redhat.com/show_bug.cgi?id=439461
+ #
+ # If running in kickstart mode (unattended), we assume no
+ # interaction and the user won't get asked for PORTNO.
+ # Otherwise the user will be asked for PORTNO.
+ # If the user specified PORTNO in parm/conf file, PORTNO gets
+ # respected (or the user will be asked if it was wrong).
+ if [ -f /sys/devices/qeth/$SCH_R_DEVBUSID/portno ]; then
+ # driver support exists since RHEL5.2
+ [ -z "$reenter" -a -n "$RUNKS" -a -z "$PORTNO" ] || \
+ [ -n "${cardtype//OSD_*/}" ] || do_portno
+ fi
+ do_layer2
+ # set device online to know the device name
+ # and to know if it's OSD/HiperSocket/GuestLAN BUT do not
+ # try to ifconfig the device up since that requires
+ # setting the mac address before (if applicable).
+ set_device_online || workflow_item_menu noredo
+ # MAC address handling is not part of
+ # https://bugzilla.redhat.com/show_bug.cgi?id=233376
+ # Instead the additions come from
+ # https://bugzilla.redhat.com/show_bug.cgi?id=248049
+ # The new parms VSWITCH and MACADDR are described in
+ # the RHEL 5.1 release notes.
+ if isLayer2; then
+ if [ -z "$VSWITCH" -o "$VSWITCH" == 0 ]; then
+ do_macaddr
+ fi
+ fi
+ elif [ "$NETTYPE" = "ctc" ]; then
+ [ -z "$reenter" -a -n "$RUNKS" -a -z "$CTCPROT" ] || do_ctcprot
+ set_device_online || workflow_item_menu noredo
+ elif [ "$NETTYPE" = "lcs" ]; then
+ [ -n "$RUNKS" -a -z "$PORTNAME" ] && PORTNAME=0
+ do_lcs_portno
+ set_device_online || workflow_item_menu noredo
+ fi
+ else # iucv
+ do_peerid
fi
-else # ctc0, iucv0
- if [ -z "$NETMASK" ]; then
- # If the user did not supply netmask, we add the right one.
- NETMASK="255.255.255.255"
- fi
- while [ -z "$GATEWAY" ]; do
- echo $"Enter the IP of your CTC / ESCON / IUCV point-to-point partner:"
- read GATEWAY
- done
-
- if [ "$NETTYPE" = "ctc" ]; then
- if [ -z "$MTU" ]; then
- MTU="1500"
- fi
- if [ -z "$RUNKS" ]; then
- if [ -n "$CTCPROT" ]; then
- validprot=1
- else
- validprot=0
- fi
- while [ "$validprot" = "0" ]; do
- echo $"Select which protocol should be used for the CTC interface"
- echo $"0 for compatibility with p.e. VM TCP service machine (default)"
- echo $"1 for enhanced package checking for Linux peers"
- echo $"3 for compatibility with OS/390 or z/OS peers"
- read CTCPROT
- case "x$CTCPROT" in
- x|x0)
- validprot=1
- unset CTCPROT
- ;;
- x1|x3)
- validprot=1
- ;;
- x2)
- echo $"CTC tty's are not usable for this installation"
- ;;
- *)
- echo $"Invalid selection"
- ;;
- esac
- done
- fi
- fi
- if [ ":$NETTYPE" = ":iucv" ]; then
- while [ -z "$PEERID" ]; do
- echo $"Enter the peer id of the VM guest you want to"
- echo $"connect to (in capital letters)."
- read PEERID
- done
- fi
-fi
-# don't ask for MTU, but use it if it has been set in the .parm file
-# don't overwrite MMTU if it has been set for CTC
-if [ -n "$MTU" -a -z "$MMTU" ]; then
- MMTU="mtu $MTU"
-fi
-# configure network-interface
-if [ ":$NETTYPE" = ":ctc" ]; then
- insmod ccwgroup$LO
- insmod cu3088$LO
- insmod fsm$LO
- insmod ctc$LO
- setupdevice
- DEVICE=${NETTYPE}0
- ifconfig $DEVICE $IPADDR $MMTU pointopoint $GATEWAY
- echo "alias $DEVICE ctc" >> /tmp/modprobe.conf
-elif [ ":$NETTYPE" = ":iucv" ]; then
- insmod fsm$LO
- insmod iucv$LO
- insmod netiucv$LO
- sysecho /sys/bus/iucv/drivers/netiucv/connection $PEERID
- DEVICE=${NETTYPE}0
- ifconfig $DEVICE $IPADDR $MMTU pointopoint $GATEWAY
- echo "alias $DEVICE netiucv" >> /tmp/modprobe.conf
-elif [ "$NETTYPE" = "lcs" ]; then
- insmod ccwgroup$LO
- insmod cu3088$LO
- insmod lcs$LO
- setupdevice
-# KH FIXME: Workaround for missing sysfs interface
-# DEVICE=`cat /sys/devices/lcs/${SUBCHANNELS//,*/}/if_name`
- DEVICE=eth0
- ifconfig $DEVICE $IPADDR $MMTU netmask $NETMASK broadcast $BROADCAST
- route add -net $NETWORK netmask $NETMASK dev $DEVICE 2>/dev/null
- echo "alias $DEVICE lcs" >> /tmp/modprobe.conf
-elif [ "$NETTYPE" = "qeth" ]; then
- insmod ccwgroup$LO
- insmod crypto_api$LO
- insmod xfrm_nalgo$LO
- insmod qdio$LO
- insmod ipv6$LO
- insmod qeth$LO
- setupdevice
- DEVICE=`cat /sys/devices/qeth/${SUBCHANNELS//,*/}/if_name`
- if [ -n "$LAYER2" -a -n "$MACADDR" ]; then
- ifconfig $DEVICE hw ether $MACADDR
- fi
- ifconfig $DEVICE $IPADDR $MMTU netmask $NETMASK broadcast $BROADCAST
- route add -net $NETWORK netmask $NETMASK dev $DEVICE 2>/dev/null
- echo "alias $DEVICE qeth" >> /tmp/modprobe.conf
-else
- echo $"Unknown network device, aborting installation"
- exit 1
-fi
+ # device needs to be up before configuring with ifconfig/ip in
+ # configure_ipv6_address/configure_ipv4_address/configure_ipv4_address
+ set_device_up || workflow_item_menu noredo
-route add default gw $GATEWAY dev $DEVICE 2>/dev/null
-# BH FIXME: Workaround for manual MACADDR, need ping to update arp table
-ping -c 1 $GATEWAY > /dev/null
+ [ "$HOSTNAME" = "(none)" ] && unset HOSTNAME
+ do_hostname
-if [ -z "$DNS" ]; then
- echo $"Enter your DNS server(s), separated by colons (:):"
- read DNS
-fi
-if [ -z "$DNS" ]; then
- echo $"You might encounter problems without a nameserver, especially"
- echo $"with FTP installs"
-fi
+ # Note: The workflow_item_menu does a rollback_config on restart
+ # dialog, i.e. hardware config has been reset and it is impossible to
+ # only restart halfway at IPADDR.
+ do_ipaddr
+ if [ "$ipv6" ]; then
+ # this branch is all IPv6 and at the same time also NETTYPE==qeth
+ do_netmask_v6
+ handle_mtu
+ configure_ipv6_address || workflow_item_menu noredo
+ do_gateway_v6
+ else
+ # Consider IPv4 as default, even for unknown IP versions
+ # due to invalid input for IPADDR ignored by the user previously
+ # (neither ipv6 nor ipv4 is set).
+ # Otherwise we would skip things like NETMASK or GATEWAY
+ # and jump forward to DNS which is probably not what we want.
+ if [ "$NETTYPE" = "qeth" ] || [ "$NETTYPE" = "lcs" ]; then
+ do_netmask
+ handle_mtu
+ configure_ipv4_address || workflow_item_menu noredo
+ do_gateway
+ else # ctc0, iucv0
+ if [ -z "$NETMASK" ]; then
+ # If the user did not supply netmask, we add the right one.
+ # Netmask MUST be present,
+ # or pumpSetupInterface() blows routes.
+ NETMASK="255.255.255.255"
+ fi
+ # don't ask for MTU, but use it if set in the parm file
+ # don't overwrite MMTU if it has been set for CTC
+ [ "$NETTYPE" = "ctc" -a -z "$MTU" -a -z "$MMTU" ] && \
+ MMTU="mtu 1500"
+ do_ptp_gateway
+ configure_ipv4_ptp || workflow_item_menu noredo
+ fi
+ fi
-if [ -n "$DNS" -a -z "$SEARCHDNS" ]; then
- echo $"Enter your DNS search domain(s) (if any), separated by colons (:):"
- read SEARCHDNS
-fi
+ modprobe_alias
+ do_dns
+ [ -n "$DNS" ] && do_searchdns
-[ -n "$HOSTNAME" ] && hostname $HOSTNAME
+ do_dasd
-# show interfaces and routing table
-ifconfig -a
-route -n
+ echo $"Initial configuration completed."
+ final_check && break
+ rollback_config
+ reenter="yes"
-# convert to space-separated lists
-if [ -n "$SEARCHDNS" ]; then
- SEARCHDNS=`echo $SEARCHDNS |sed -e 's/:/ /g'`
- for i in "$SEARCHDNS"; do echo "search $i"; done >> /etc/resolv.conf
-fi
-if [ -n "$DNS" ]; then
- RESOLVDNS=`echo $DNS |sed -e 's/:/ /g'`
- for i in $RESOLVDNS; do echo "nameserver $i"; done >> /etc/resolv.conf
-fi
+done # outer dialog loop
-# make sure we have an /etc/hosts file (required for telnetd)
-if [ ! -z "$HOSTNAME" -a ! -z "$IPADDR" ]; then
- echo -e "$IPADDR\t$HOSTNAME `echo $HOSTNAME | cut -d '.' -f 1`" >> /etc/hosts
-fi
+#echo $"Starting portmap."
+#portmap
+
+if [ -z "$testing" ]; then
+
+ # convert to space-separated lists
+ if [ -n "$SEARCHDNS" ]; then
+ SEARCHDNS=$(echo $SEARCHDNS |sed -e 's/:/ /g')
+ for i in "$SEARCHDNS"; do echo "search $i"; done >> /etc/resolv.conf
+ fi
+ if [ -n "$DNS" ]; then
+ if [ "$ipv6" ]; then
+ RESOLVDNS=$(echo $DNS |sed -e 's/,/ /g')
+ else
+ RESOLVDNS=$(echo $DNS |sed -e 's/:/ /g')
+ fi
+ for i in $RESOLVDNS; do echo "nameserver $i"; done >> /etc/resolv.conf
+ fi
+
+ # make sure we have an /etc/hosts file (required for telnetd)
+ if [ ! -z "$HOSTNAME" -a ! -z "$IPADDR" ]; then
+ echo -e "$IPADDR\t$HOSTNAME `echo $HOSTNAME | cut -d '.' -f 1`" >> /etc/hosts
+ fi
+
+fi # testing
+
+if [ -z "$testing" ]; then
+ # undo startup of udevd, only needed it for possible calls of udevsettle
+ killall udevd
+fi # testing
-if [ -z "$DASD" ]; then
- echo
- echo $"Enter DASD range (e.g. 200-203 or 200,201,202,203)"
- echo $"Press <Enter> for autoprobing (not recommended):"
- echo
- read DASD
-fi
if [ -n "$DASD" ]; then
- echo "DASD=$DASD" > /tmp/dasd_ports
+ echo "DASD=$DASD" > /tmp/dasd_ports
fi
+# syntax check to give user early feedback on parameters provided in parm file
+# (he probably won't notice the logs written by anaconda later on)
+syntax_check_fcp
+# currently we ignore failed syntax checks since FCP parms are non-interactive
for i in ${!FCP_*}; do
- echo "${!i}" >> /tmp/fcpconfig
+ echo "${!i}" >> /tmp/fcpconfig
done
+# cio_ignore handling for FCP should happen when the content of /tmp/fcpconfig
+# will actually be processed which is in anaconda's zfcp.py ZFCP::readConfig()
-grep -q ext3 /proc/filesystems
-if [ "$?" != "0" ]; then
- insmod jbd$LO
- insmod ext3$LO
-fi
+if [ -z "$testing" ]; then
+
+ grep -q ext3 /proc/filesystems
+ if [ "$?" != "0" ]; then
+ insmod jbd$LO
+ insmod ext3$LO
+ fi
+
+fi # testing
+
+# TODO/FIXME: also need to pass IPv6 decision to loader/anaconda
+# [ "$ipv6" ] && echo "IPV6=yes"
# transfer options into install environment
cat > /tmp/install.cfg << EOF
@@ -571,12 +3067,18 @@ MTU="$MTU"
NETWORK="$NETWORK"
NETMASK="$NETMASK"
BROADCAST="$BROADCAST"
-DNS="`echo $DNS | cut -d ':' -f 1`"
SEARCHDNS="$SEARCHDNS"
PEERID="$PEERID"
SUBCHANNELS="$SUBCHANNELS"
ONBOOT="yes"
CTCPROT="$CTCPROT"
+EOF
+if [ "$ipv6" ]; then
+ echo DNS=\"`echo $DNS | cut -d ',' -f 1`\" >> /tmp/install.cfg
+else
+ echo DNS=\"`echo $DNS | cut -d ':' -f 1`\" >> /tmp/install.cfg
+fi
+cat >> /tmp/install.cfg << EOF
export LANG PORTNAME S390ARCH TEXTDOMAIN TEXTDOMAINDIR
export HOSTNAME DEVICE NETTYPE IPADDR GATEWAY MTU
export NETWORK NETMASK BROADCAST DNS SEARCHDNS
@@ -584,44 +3086,61 @@ export PEERID ONBOOT SUBCHANNELS CTCPROT
EOF
# immediately read it in again to export these into the shell below
. /tmp/install.cfg
-cat /tmp/install.cfg >> /etc/profile
-
-NETSCRIPTS="/etc/sysconfig/network-scripts"
-IFCFGFILE="$NETSCRIPTS/ifcfg-$DEVICE"
-if [ ! -d "$NETSCRIPTS" ]; then
- mkdir -p $NETSCRIPTS
-fi
-
-cat > $IFCFGFILE << EOF
+if [ -z "$testing" ]; then
+ cat /tmp/install.cfg >> /etc/profile
+fi # testing
+cat > /tmp/netinfo << EOF
DEVICE=$DEVICE
ONBOOT=yes
BOOTPROTO=static
-IPADDR=$IPADDR
-NETMASK=$NETMASK
GATEWAY=$GATEWAY
BROADCAST=$BROADCAST
HOSTNAME=$HOSTNAME
MTU=$MTU
SUBCHANNELS=$SUBCHANNELS
EOF
-[ "$DNS" != "" ] && echo "DNS=`echo $DNS | cut -d ':' -f 1`" >> $IFCFGFILE
-[ "$NETTYPE" != "" ] && echo "NETTYPE=$NETTYPE" >> $IFCFGFILE
-[ "$PEERID" != "" ] && echo "PEERID=$PEERID" >> $IFCFGFILE
-[ "$PORTNAME" != "" ] && echo "PORTNAME=$PORTNAME" >> $IFCFGFILE
-[ "$CTCPROT" != "" ] && echo "CTCPROT=$CTCPROT" >> $IFCFGFILE
-[ "$LAYER2" != "" ] && echo "LAYER2=$LAYER2" >> $IFCFGFILE
-[ "$MACADDR" != "" ] && echo "MACADDR=$MACADDR" >> $IFCFGFILE
-
-# so that the vars get propagated into the sshd shells
-mkdir /.ssh
-cat >> /.ssh/environment <<EOF
+if [ "$ipv6" ]; then
+ [ "$DNS" != "" ] && echo "DNS=`echo $DNS | cut -d ',' -f 1`" >> /tmp/netinfo
+else
+ [ "$DNS" != "" ] && echo "DNS=`echo $DNS | cut -d ':' -f 1`" >> /tmp/netinfo
+fi
+[ "$NETTYPE" != "" ] && echo "NETTYPE=$NETTYPE" >> /tmp/netinfo
+[ "$PEERID" != "" ] && echo "PEERID=$PEERID" >> /tmp/netinfo
+[ "$PORTNAME" != "" ] && echo "PORTNAME=$PORTNAME" >> /tmp/netinfo
+[ "$CTCPROT" != "" ] && echo "CTCPROT=$CTCPROT" >> /tmp/netinfo
+[ "$LAYER2" != "" ] && echo "LAYER2=$LAYER2" >> /tmp/netinfo
+[ "$MACADDR" != "" ] && echo "MACADDR=$MACADDR" >> /tmp/netinfo
+[ "$PORTNO" != "" ] && echo "PORTNO=$PORTNO" >> /tmp/netinfo
+# also needs support in stage2 to make PORTNO persistent,
+# i.e. OPTION="portno=1" in /etc/sysconfig/network-scripts/ifcfg-<netdevname>
+# this is done by the loader starting with RHEL 5.3
+if [ "$ipv6" ]; then
+ cat >> /tmp/netinfo << EOF
+IPV6INIT=yes
+IPV6_AUTOCONF=no
+IPV6ADDR=$IPADDR/$NETMASK
+EOF
+ # FIXME: /etc/sysconfig/network:IPV6_DEFAULTGW=$GATEWAY
+ # /etc/sysconfig/network:NETWORKING_IPV6=yes
+else
+ cat >> /tmp/netinfo << EOF
+IPADDR=$IPADDR
+NETMASK=$NETMASK
+EOF
+fi
+
+if [ -z "$testing" ]; then
+
+ # so that the vars get propagated into the sshd shells
+ mkdir /.ssh
+ cat >> /.ssh/environment <<EOF
LD_LIBRARY_PATH=$LD_LIBRARY_PATH
PATH=$PATH
HOME=$HOME
PYTHONPATH=$PYTHONPATH
EOF
-cat >> /etc/profile <<EOF
+ cat >> /etc/profile <<EOF
LD_LIBRARY_PATH=$LD_LIBRARY_PATH
PATH=$PATH
HOME=$HOME
@@ -629,31 +3148,30 @@ PYTHONPATH=$PYTHONPATH
export LD_LIBRARY_PATH PATH HOME PYTHONPATH
EOF
-if [ -n "$DISPLAY" ]; then
- echo "export DISPLAY=$DISPLAY" >> /etc/profile
-fi
+ if [ -n "$DISPLAY" ]; then
+ echo "export DISPLAY=$DISPLAY" >> /etc/profile
+ fi
-# I'm tired of typing this out...
-echo "loader" >> /.bash_history
+ # I'm tired of typing this out...
+ echo "loader" >> /.bash_history
-echo -n $$ > /var/run/init.pid
-# shutdown (halt) on SIGUSR1
-trap doshutdown SIGUSR1
-# reboot on SIGUSR2
-trap doreboot SIGUSR2
+ echo -n $$ > /var/run/init.pid
-startinetd
+ # shutdown (halt) on SIGUSR1
+ trap doshutdown SIGUSR1
+ # reboot on SIGUSR2
+ trap doreboot SIGUSR2
-if [ -n "$RUNKS" ]; then
- /sbin/loader
-fi
+ startinetd
+
+ if [ -n "$RUNKS" ]; then
+ /sbin/loader
+ fi
+
+ doreboot
-# A shutdown needs to be performed here to avoid a loop booting back into the installer
-echo $"Finishing up with doshutdown"
-doshutdown
+fi # testing
# ;;; Local Variables: ***
# ;;; mode: sh ***
-# ;;; tab-width:3 ***
# ;;; end: ***
-# vim:ts=3:sw=3
diff --git a/loader/lsznet.raw b/loader/lsznet.raw
new file mode 100644
index 000000000..5b3df91e2
--- /dev/null
+++ b/loader/lsznet.raw
@@ -0,0 +1,368 @@
+#! /bin/bash
+
+# lsznet.raw: list sensible network device hardware setups for Linux on s390(x)
+# Copyright (C) IBM Corp. 2008,2009
+# Author: Steffen Maier <maier@de.ibm.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License only.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+readonly SYSFS=/sys
+# DEBUG=0 turns off debugging. >=1 means increasing debugging.
+readonly DEBUG=0
+
+# nothing to be changed below here
+
+export TEXTDOMAIN=lsznet.raw
+
+readonly CMD=${0##*/}
+
+function error() {
+ echo $"$CMD: ERROR: $*" 1>&2
+ exit 1;
+}
+
+# currently requires bash version 3.0 or later
+# (this seems reasonable since bash-3.0 has been shipped with
+# RHEL 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7;
+# bash-3.1 with RHEL 5.0, 5.1; and bash-3.2 with RHEL 5.2)
+if [ ${BASH_VERSINFO[0]} -lt 3 -o \
+ ${BASH_VERSINFO[1]} -lt 0 ]; then
+ error $"only works with BASH version 3.0 or later (current version used is ${BASH_VERSION})"
+fi
+
+# the script was designed for Linux kernel 2.6 and might work with newer ones
+kernel_version=$(uname -r)
+IFS=.
+read krn_ver krn_patch krn_foo <<< "$kernel_version"
+unset IFS
+if [ $krn_ver -lt 2 -o $krn_patch -lt 6 ]; then
+ error $"only works for kernel versions 2.6 or probably later"
+fi
+
+# The following combinations of control unit type and model were taken from the
+# Linux network device drivers for s390 on 2008-06-09 from Linux 2.6.25.4.
+# The list (among other things) should be adapted, if any of those device
+# drivers start supporting different CU types/models.
+# (Alternatively, the list could be generated by reading the modaliases
+# directly out of the device driver modules:
+# modinfo qeth/cu3088 | fgrep 'alias:'
+# However, this would still require a list of device driver modules.)
+readonly -a CU=(
+ 1731/01
+ 1731/05
+ 3088/08
+ 3088/1f
+ 3088/1e
+ 3088/01
+ 3088/60
+ 3088/61
+)
+
+# $CU_CARDTYPE array is the only one which may contain entries with spaces
+readonly -a CU_CARDTYPE=(
+ "OSA (QDIO)"
+ "HiperSocket"
+ "CTC adapter"
+ "escon channel"
+ "ficon channel"
+ "LCS p390"
+ "LCS OSA"
+ "LCS CLAW"
+)
+
+readonly -a CU_DEVDRV=(
+ qeth
+ qeth
+ ctc
+ ctc
+ ctc
+ lcs
+ lcs
+ lcs
+)
+
+readonly -a CU_DEVNAME=(
+ eth
+ hsi
+ ctc
+ ctc
+ ctc
+ eth
+ eth
+ eth
+)
+
+readonly -a CU_GROUPCHANNELS=(
+ 3
+ 3
+ 2
+ 2
+ 2
+ 2
+ 2
+ 2
+)
+readonly -a CHPIDTYPES=(
+ [10]=OSE
+ [11]=OSD
+ [24]=IQD
+)
+
+readonly PREFIXFORMAT=[[:xdigit:]]*
+readonly SSIDFORMAT=[0-3]
+readonly BUSIDFORMAT=[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]
+readonly IDFORMAT=$PREFIXFORMAT.$SSIDFORMAT.$BUSIDFORMAT
+readonly SUBCHANNEL_TYPE_IO=0
+
+function debug() {
+ level=$1
+ shift
+ [ $DEBUG -ge $level ] && echo "$*" 1>&2
+}
+
+# Searches for a match of argument 1 on the array $CU and sets $cu_idx
+# to the matched array index on success.
+# Returns 0 on success, 1 on failure.
+function search_cu() {
+ local scu=$1
+ local i
+ for ((i=0; i < ${#CU[@]}; i++)); do
+ if [ $scu == ${CU[i]} ]; then
+ cu_idx=$i
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Returns symbolic name of CHPID type in $chpidtype_symbolic,
+# if an entry in the array $CHPIDTYPES has been found at index of argument 1.
+# Returns "?" otherwise.
+# Always succeeds and returns 0.
+function search_chpt() {
+ local chpidtype_number=$1
+ chpidtype_symbolic=${CHPIDTYPES[$chpidtype_number]}
+ if [ "$chpidtype_symbolic" == "" ]; then
+ chpidtype_symbolic="?"
+ fi
+ return 0
+}
+
+# build_list:
+#
+# Prints list on standard output consisting of all subchannels and
+# ccwdevices whose control unit type/model match supported network
+# device types on s390. Each matching entry is accompanied with
+# (almost all) corresponding attributes.
+#
+function build_list() {
+ # use /sys/devices/css*/ for startpath
+ readonly STARTPATH=$SYSFS/devices
+ # change to base directory so path globbing length with find is minimal
+ cd $STARTPATH
+ # fail out gracefully, if there is not expected sysfs environment
+ # (could even fail out near the top, if $(uname -m) != s390x)
+ csses=css$PREFIXFORMAT
+ for d in $csses; do
+ [ -d $d ] || exit
+ done
+ find $csses -name "$IDFORMAT" |
+ while read dir; do
+ debug 6 " examining sysfs directory $dir"
+ # must not use $...FORMAT (file globs) here since this is a regex:
+ [[ "$dir" =~ ^css\([[:xdigit:]]+\)/\([[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}\)/\([[:xdigit:]]+\\.[0-3]\\.[[:xdigit:]]{4}\)$ ]]
+ case $? in
+ 0)
+ # string matched the pattern
+ debug 6 " ${BASH_REMATCH[@]}"
+ prefix=${BASH_REMATCH[1]}
+ subch=${BASH_REMATCH[2]}
+ devbusid=${BASH_REMATCH[3]}
+ subch_p=css$prefix/$subch
+ dev_p=$subch_p/$devbusid
+ debug 6 " $subch_p $dev_p"
+ ;;
+ 1)
+ # string did not match the pattern
+ continue
+ ;;
+ 2)
+ error $"syntax error in regex of match operator =~, code needs to be fixed"
+ ;;
+ *)
+ error $"unexpected return code of regex match operator =~, code needs to be fixed"
+ ;;
+ esac
+ debug 5 " sysfs directory matched regex $dir"
+ # skip non-I/O-subchannels, i.e. chsc and message subchannels
+ if [ -f $subch_p/type ]; then
+ read type < $subch_p/type
+ if [ $type != $SUBCHANNEL_TYPE_IO ]; then
+ debug 3 " skip non-I/O subchannel"
+ continue
+ fi
+ fi
+ # get subchannel information...
+ # ATTENTION: hex values from sysfs are WITHOUT leading 0x prefix!
+ read chpid_list < $subch_p/chpids
+ read -a chpids <<< "$chpid_list"
+ if [ ${#chpids[@]} -ne 8 ]; then
+ error $"sysfs reported ${#chpids[@]} CHPIDs instead of expected 8"
+ fi
+ read pim pam pom foo < $subch_p/pimpampom
+ pimchpidZ=""
+ local chp
+ for ((chp=0; chp < 8; chp++)); do
+ mask=$((0x80 >> chp))
+ if (( 0x$pim & $mask )); then
+ pimchpidZ=${pimchpidZ}${chpids[chp]}
+ else
+ pimchpidZ=${pimchpidZ}"ZZ"
+ fi
+ done
+ # get device information...
+ read cutype < $dev_p/cutype
+ read active < $dev_p/online
+ # skip already active subchannels and those that are already in a
+ # ccwgroup and thus not available any more:
+ [ $active == "1" ] && continue
+ [ -h $dev_p/group_device ] && continue
+ # get chpid information...
+ pimchpids=${pimchpidZ//ZZ/}
+ [ $pimchpids == "" ] && continue
+ # Taking the first 2 hex digits as CHPID relies somewhat on the fact
+ # that network adaptors don't use multipathing and only have one CHP.
+ # Anyway it's OK since we're only interested in CHPID type and I guess
+ # this should be equal for all possible multipaths to the same device.
+ chpid=${pimchpids:0:2}
+ chpid_p=css$prefix/chp$prefix.$chpid
+ read chptype < $chpid_p/type
+ # filter and output...
+ if search_cu $cutype; then
+ if [ "${CU_DEVDRV[$cu_idx]}" == "ctc" ]; then
+ # assume CTC are mostly virtual and ignore chpid from sysfs
+ chpidtype_symbolic="-"
+ else
+ search_chpt $chptype
+ fi
+ echo $pimchpids $devbusid $STARTPATH/$dev_p $cutype $chpidtype_symbolic $chptype ${CU_DEVDRV[$cu_idx]} ${CU_DEVNAME[$cu_idx]} ${CU_GROUPCHANNELS[$cu_idx]} $cu_idx ${CU_CARDTYPE[$cu_idx]}
+ else
+ debug 5 " skip non-network device $devbusid CU $cutype"
+ fi
+ done
+}
+
+# search_groups:
+#
+# Prints enumeration list on standard output consisting of possible
+# hardware configurations (ccwgroups) for network devices on s390.
+# Each configuration suggestion includes corresponding attributes
+# that are of potential interest for the user and fit in a fixed column
+# table on an 80 column screen.
+#
+# PRECONDITION: Standard input has to be stably sorted by device bus IDs and
+# then by CHPIDs, i.e. grouped by CHPIDs.
+#
+function search_groups() {
+ local w_prefix w_ssid w_devno
+ local d_prefix d_ssid d_devno
+ local prefix ssid devno x
+ local chp devbusid dev_p cutype chpidtypename chptype devdrv devname groupchs cu_idx cardtype
+ # remembered last state variables for possible ccwgroup:
+ local r_prefix="Z"
+ local r_ssid="Z"
+ local r_devno="ZZZZ"
+ local r_chp="ZZ"
+ local r_cutype="ZZZZ/ZZ"
+ local count=0
+ local item=1
+ local skipped=0
+ # currently unused are: dev_p,chptype, cu_idx.
+ while read chp devbusid dev_p cutype chpidtypename chptype devdrv devname groupchs cu_idx cardtype; do
+ debug 1 " # $chp $devbusid $dev_p $cutype $chpidtypename $chptype $devdrv $devname $groupchs $cu_idx $cardtype"
+ IFS=.
+ read prefix ssid devno x <<< "$devbusid"
+ unset IFS
+ if [ $r_chp != $chp \
+ -o $r_prefix != $prefix \
+ -o $r_ssid != $ssid \
+ -o $r_cutype != $cutype ]; then
+ # restart with new read channel info and remember it
+ r_prefix=$prefix
+ r_ssid=$ssid
+ r_devno=$devno
+ r_chp=$chp
+ r_cutype=$cutype
+ count=1
+ debug 2 " INFO: restart on different CHPID or prefix or CUtype/model"
+ continue
+ fi
+ count=$((count + 1))
+ if [ $count -eq 2 ]; then
+ # about to check if write channel is one above read channel
+ if [ $((0x$devno)) -ne $((0x$r_devno + 1)) ]; then
+ # start with new read channel info
+ r_prefix=$prefix
+ r_ssid=$ssid
+ r_devno=$devno
+ r_chp=$chp
+ r_cutype=$cutype
+ count=1
+ skipped=$((skipped + 1))
+ # unimplemented possible packed channel usage option:
+ # remember unused channels for later use as data channel
+ debug 2 " INFO: restart on unmatching read channel"
+ continue
+ fi
+ w_prefix=$prefix
+ w_ssid=$ssid
+ w_devno=$devno
+ elif [ $count -eq 3 ]; then
+ # remember data channel info
+ d_prefix=$prefix
+ d_ssid=$ssid
+ d_devno=$devno
+ fi
+ debug 2 " INFO: groupchs=$groupchs count=$count"
+ if [ $count -ne $groupchs ]; then
+ debug 2 " INFO: skip"
+ continue
+ fi
+ # found possible ccwgroup
+ case $count in
+ 2)
+ chlist=$r_prefix.$r_ssid.$r_devno,$w_prefix.$w_ssid.$w_devno
+ ;;
+ 3)
+ chlist=$r_prefix.$r_ssid.$r_devno,$w_prefix.$w_ssid.$w_devno,$d_prefix.$d_ssid.$d_devno
+ ;;
+ *)
+ error $"unknown number of channels for group, code needs to be fixed"
+ ;;
+ esac
+ echo $item $cutype $chp $chpidtypename $devdrv $devname $chlist "$cardtype"
+ item=$((item + 1))
+ # restart after successful detection
+ r_prefix="Z"
+ count=0
+ done
+ debug 1 " STATISTIC: skipped $skipped devnos because of unmatching read channel"
+}
+
+build_list |
+# stable sort by device bus IDs and then by CHPIDs => grouped by CHPIDs
+# (sorting only works since keys are fixed no. of digits with leading zeros!)
+sort -s -k 1,1 -k 2,2 |
+#cat ; exit # move at desired line and uncomment to see intermediate output
+search_groups
diff --git a/scripts/mk-images b/scripts/mk-images
index 523800efe..d42bc4ccc 100755
--- a/scripts/mk-images
+++ b/scripts/mk-images
@@ -603,6 +603,7 @@ makeinitrd() {
else
instbin $IMGPATH ${LOADERBINDIR##IMGPATH}/shutdown $MBD_DIR /sbin/shutdown
instbin $IMGPATH /usr/lib/anaconda-runtime/loader/linuxrc.s390 $MBD_DIR /sbin/init
+ instbin $IMGPATH /usr/lib/anaconda-runtime/loader/lsznet.raw $MBD_DIR /sbin/lsznet
instbin $IMGPATH /usr/sbin/dasdfmt $MBD_DIR /sbin/dasdfmt
fi
@@ -631,6 +632,7 @@ makeinitrd() {
instbin $IMGPATH /usr/sbin/udevd $MBD_DIR /sbin/udevd
instbin $IMGPATH /usr/sbin/udevadm $MBD_DIR /sbin/udevadm
instbin $IMGPATH /usr/bin/udevinfo $MBD_DIR /sbin/udevinfo
+ instbin $IMGPATH /usr/sbin/udevsettle $MBD_DIR /sbin/udevsettle
instbin $IMGPATH /usr/bin/bash $MBD_DIR /sbin/bash
( cd $MBD_DIR/sbin ; ln -sf bash sh )