diff options
author | David Cantrell <dcantrell@redhat.com> | 2009-05-06 08:41:05 -1000 |
---|---|---|
committer | David Cantrell <dcantrell@redhat.com> | 2009-05-06 08:41:38 -1000 |
commit | 9249e40f42ffbbdcf42cd1caad72e3d622c7a75b (patch) | |
tree | 09fcf626fdd38885f686aba3a1e1d21118271dfd | |
parent | 5ebb7235d36390fa72faa730c1f5a452e3432eb1 (diff) | |
download | anaconda-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/Makefile | 5 | ||||
-rw-r--r-- | loader/linuxrc.s390 | 3488 | ||||
-rw-r--r-- | loader/lsznet.raw | 368 | ||||
-rwxr-xr-x | scripts/mk-images | 2 |
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 OSA2 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 ) |