3107 lines
104 KiB
Plaintext
3107 lines
104 KiB
Plaintext
|
#! /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>
|
||
|
# Karsten Hopp <karsten@redhat.de>
|
||
|
# Florian La Roche <laroche@redhat.com>
|
||
|
# 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
|
||
|
# the Free Software Foundation; either version 2 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program; if not, write to the Free Software
|
||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
#
|
||
|
|
||
|
# prerequisites of this script to run inside the installer initrd:
|
||
|
# - udevadm and udevd need to be there
|
||
|
# - have /etc/udev/udev.conf with at least one comment line as content
|
||
|
# - if necessary, have udev rules
|
||
|
# - lsznet.raw and znetcontrolunits from s390utils-base in /lib/s390-tools
|
||
|
# - pack kernel modules and module-init-tools (no longer use busybox for that)
|
||
|
# - "multi on" in /etc/host.conf [RH bugs 486457,486461,483244]
|
||
|
|
||
|
# TODOs:
|
||
|
# - make sure driver modules get loaded automatically
|
||
|
# - udev rule for lcs/ctcm vs. cu3088
|
||
|
|
||
|
# debug: set -x
|
||
|
|
||
|
VERSION=1.2
|
||
|
|
||
|
export TEXTDOMAIN=s390installer
|
||
|
export TEXTDOMAINDIR=/usr/lib/locale
|
||
|
|
||
|
# helper function to execute command in arguments and print command on stdout
|
||
|
function debug() {
|
||
|
# uncomment the following echo "$*" to enable debug output
|
||
|
#echo "$*"
|
||
|
$*
|
||
|
}
|
||
|
|
||
|
# 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"
|
||
|
|
||
|
if [ "$RUNKS" = "0" ]; then
|
||
|
RUNKS=""
|
||
|
fi
|
||
|
|
||
|
# helper function to disable commands while running outside the initrd
|
||
|
function tv() {
|
||
|
if [ -z "$testing" ]; then
|
||
|
$*
|
||
|
else
|
||
|
return 0
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
function checkipv6()
|
||
|
{
|
||
|
local ip=$1
|
||
|
[ -z "$ip" ] && return 1
|
||
|
/sbin/ipcalc -c -6 "$ip" >/dev/null 2>&1
|
||
|
return $?
|
||
|
}
|
||
|
|
||
|
function checkipv4()
|
||
|
{
|
||
|
local ip=$1
|
||
|
[ -z "$ip" ] && return 1
|
||
|
/sbin/ipcalc -c -4 "$ip" >/dev/null 2>&1
|
||
|
return $?
|
||
|
}
|
||
|
|
||
|
function doshutdown()
|
||
|
{
|
||
|
echo $"about to exec shutdown"
|
||
|
exec /sbin/shutdown
|
||
|
exit 0
|
||
|
}
|
||
|
|
||
|
function doreboot()
|
||
|
{
|
||
|
if [ -e "/sys/firmware/reipl" ]; then
|
||
|
read REIPL_TYPE < /sys/firmware/reipl/reipl_type
|
||
|
echo "reipl_type=$REIPL_TYPE"
|
||
|
pushd /sys/firmware/reipl/$REIPL_TYPE >/dev/null 2>&1
|
||
|
for i in *; do
|
||
|
echo "$i=`cat $i`"
|
||
|
done
|
||
|
popd >/dev/null 2>&1
|
||
|
fi
|
||
|
|
||
|
echo $"about to exec shutdown -r"
|
||
|
exec /sbin/shutdown -r
|
||
|
exit 0
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
function dasd_settle() {
|
||
|
local dasd_status=/sys/bus/ccw/devices/$1/status
|
||
|
if [ ! -f $dasd_status ]; then
|
||
|
return 1
|
||
|
fi
|
||
|
local i=1
|
||
|
while [ $i -le 30 ] ; do
|
||
|
local status
|
||
|
read status < $dasd_status
|
||
|
case $status in
|
||
|
online|unformatted)
|
||
|
return 0 ;;
|
||
|
*)
|
||
|
sleep 0.1
|
||
|
i=$((i+1)) ;;
|
||
|
esac
|
||
|
done
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
function dasd_settle_all() {
|
||
|
for dasdccw in $(cut -d '(' -f 1 /proc/dasd/devices) ; do
|
||
|
if ! dasd_settle $dasdccw ; then
|
||
|
echo $"Could not access DASD $dasdccw in time"
|
||
|
return 1
|
||
|
fi
|
||
|
done
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
function startinetd()
|
||
|
{
|
||
|
echo
|
||
|
echo $"Starting 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/sshd -f /etc/ssh/sshd_config.anaconda
|
||
|
if [ -z "$RUNKS" ]; then
|
||
|
echo
|
||
|
echo $"Connect now to $IPADDR and log in as user install to start the installation."
|
||
|
echo $"E.g. using: ssh -x install@$IPADDR"
|
||
|
echo $"You may log in as the root user to start an interactive shell."
|
||
|
read
|
||
|
while : ; do
|
||
|
/bin/sh --login
|
||
|
[ $? = 0 ] || break
|
||
|
done
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# prints a canonocalized device bus ID for a given devno of any format
|
||
|
function canonicalize_devno()
|
||
|
{
|
||
|
case ${#1} in
|
||
|
3) echo "0.0.0${1}" ;;
|
||
|
4) echo "0.0.${1}" ;;
|
||
|
*) echo "${1}" ;;
|
||
|
esac
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
# read file from CMS and write it to /tmp
|
||
|
function readcmsfile() # $1=dasdport $2=filename
|
||
|
{
|
||
|
local dev
|
||
|
if [ $# -ne 2 ]; then return; fi
|
||
|
# precondition: udevd created dasda block device node
|
||
|
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 udevadm settle we could wait 2 seconds unconditionally)
|
||
|
#debug ls -laF /dev/.udev
|
||
|
udevadm settle
|
||
|
# even though the device might now be online, some of its
|
||
|
# sysfs attributes might not yet be available
|
||
|
sleep 1
|
||
|
# precondition: dasd_eckd_mod driver incl. dependencies loaded,
|
||
|
# dasd_mod must be loaded without setting any DASD online
|
||
|
dev=$(canonicalize_devno $1)
|
||
|
if ! sysecho /sys/bus/ccw/devices/$dev/online 1; then
|
||
|
echo $"DASD $dev could not be set online"
|
||
|
return 1
|
||
|
fi
|
||
|
udevadm settle
|
||
|
if ! dasd_settle $dev ; then
|
||
|
echo $"Could not access DASD $dev in time"
|
||
|
return 1
|
||
|
fi
|
||
|
udevadm settle
|
||
|
if ! cmsfscat -d /dev/dasda -a $2 > /tmp/$2; then
|
||
|
echo $"Could not read conf file $2 on CMS DASD $1."
|
||
|
fi
|
||
|
if ! sysecho /sys/bus/ccw/devices/$dev/online 0; then
|
||
|
echo $"DASD $dev could not be set offline again"
|
||
|
return 1
|
||
|
fi
|
||
|
udevadm settle
|
||
|
# consequences of no more module unload: loader can no longer
|
||
|
# use DASD module option to online DASDs and set other DASD parameters!
|
||
|
}
|
||
|
|
||
|
# adaption of the same function in init.c (udevd gets started later)
|
||
|
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
|
||
|
EOF
|
||
|
# tty handling is different from init.c since s390 does not have all
|
||
|
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
|
||
|
}
|
||
|
|
||
|
# approximately the main() function of init.c
|
||
|
function init_main() {
|
||
|
S390ARCH=$(uname -m)
|
||
|
if [ "$S390ARCH" = "s390" ]; then
|
||
|
export S390ARCH="S/390"
|
||
|
else
|
||
|
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
|
||
|
else
|
||
|
LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
|
||
|
fi
|
||
|
export LD_LIBRARY_PATH
|
||
|
|
||
|
PATH="$PATH:/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sysimage/bin:/mnt/sysimage/usr/bin:/mnt/sysimage/usr/sbin:/mnt/sysimage/sbin:/mnt/sysimage/usr/X11R6/bin"
|
||
|
export PATH
|
||
|
HOME=/
|
||
|
export HOME
|
||
|
PYTHONPATH=/tmp/updates
|
||
|
export PYTHONPATH
|
||
|
|
||
|
if [ -z "$testing" ]; then
|
||
|
|
||
|
mount -t proc none /proc
|
||
|
|
||
|
mount -t tmpfs none /dev
|
||
|
createDevices
|
||
|
# udevd req'd by udevadm settle (/dev/.udev/queue)
|
||
|
# in readcmsfile, dialog_network_table, semantic_check_subchannels.
|
||
|
# (important: start udevd at the right time, e.g. after setup of /dev)
|
||
|
echo $"Starting udev..."
|
||
|
udevd --daemon
|
||
|
# debug: udevadm control --log-priority=debug
|
||
|
|
||
|
udevadm control --env=ANACONDA=1
|
||
|
|
||
|
mount -t devpts /dev/pts /dev/pts
|
||
|
mount -t sysfs none /sys
|
||
|
|
||
|
# remount root fs rw
|
||
|
mount /dev/root / -o remount,rw
|
||
|
|
||
|
# limit output on 3270 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
|
||
|
|
||
|
# make /tmp/ramfs
|
||
|
mount -t ramfs none /tmp
|
||
|
|
||
|
ifconfig lo 127.0.0.1 netmask 255.0.0.0
|
||
|
route add -host 127.0.0.1 dev lo
|
||
|
|
||
|
echo -e "127.0.0.1\tlocalhost.localdomain localhost localhost4 localhost4.localdomain4" > /etc/hosts
|
||
|
echo -e "::1\t\tlocalhost.localdomain localhost localhost6 localhost6.localdomain6" >> /etc/hosts
|
||
|
|
||
|
/sbin/dbus-uuidgen --ensure &
|
||
|
[ $? != 0 ] && echo "error on calling /sbin/dbus-uuidgen --ensure"
|
||
|
/sbin/dbus-daemon --system &
|
||
|
[ $? != 0 ] && echo "error on calling /sbin/dbus-daemon --system"
|
||
|
|
||
|
fi # testing
|
||
|
}
|
||
|
|
||
|
# trigger udev to automatically load device drivers
|
||
|
function udev_setup() {
|
||
|
if [ -z "$testing" ]; then
|
||
|
# debug: udevadm monitor &
|
||
|
udevadm trigger
|
||
|
udevadm settle
|
||
|
fi # testing
|
||
|
}
|
||
|
|
||
|
# from here on accesses to sysfs try to follow
|
||
|
# linux/Documentation/sysfs-rules.txt
|
||
|
|
||
|
### lsznet.raw integration
|
||
|
|
||
|
declare -a nettable
|
||
|
|
||
|
function read_lsznet_output() {
|
||
|
count=0
|
||
|
local line
|
||
|
while read line; do
|
||
|
nettable[$count]="$line"
|
||
|
count=$((count + 1))
|
||
|
# using the more sophisticated process substitution instead of temp file
|
||
|
# requires the symlink /dev/fd -> /proc/self/fd => createDevices
|
||
|
done < <(/lib/s390-tools/lsznet.raw)
|
||
|
}
|
||
|
|
||
|
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
|
||
|
udevadm settle
|
||
|
# (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
|
||
|
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
|
||
|
if [ "$devdrv" = "ctcm" ]; then
|
||
|
NETTYPE="ctc"
|
||
|
else
|
||
|
NETTYPE=$devdrv
|
||
|
fi
|
||
|
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
|
||
|
|
||
|
. /lib/s390-tools/znetcontrolunits
|
||
|
|
||
|
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 "HiperSockets with CHPID type IQD" ;;
|
||
|
"GuestLAN QDIO") echo "GuestLAN based on OSA (QDIO)" ;;
|
||
|
"GuestLAN Hiper") echo "GuestLAN based on HiperSockets" ;;
|
||
|
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
|
||
|
}
|
||
|
|
||
|
# 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
|
||
|
# 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|HiperSockets|"GuestLAN QDIO")
|
||
|
return 0 ;;
|
||
|
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
|
||
|
}
|
||
|
|
||
|
# sets device online _and_ retrieves DEVICE at the same time
|
||
|
function set_device_online() {
|
||
|
echo $"Activating network device..."
|
||
|
local sysnettype
|
||
|
case "${NETTYPE}" in
|
||
|
qeth|lcs) sysnettype=${NETTYPE} ;;
|
||
|
ctc) sysnettype=ctm ;;
|
||
|
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
|
||
|
udevadm settle
|
||
|
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. HiperSockets won't => 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" = ":ctc" ]; then
|
||
|
echo "alias $DEVICE ctcm" >> /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
|
||
|
if [ -n "$NETTYPE" ]; then
|
||
|
if [ -n "$SCH_R_DEVBUSID" ]; then
|
||
|
local sysnettype
|
||
|
case "${NETTYPE}" in
|
||
|
qeth|lcs) sysnettype=${NETTYPE} ;;
|
||
|
ctcm) sysnettype=ctcm ;;
|
||
|
esac
|
||
|
[ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online ] && \
|
||
|
sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online "0"
|
||
|
udevadm settle
|
||
|
[ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/ungroup ] && \
|
||
|
sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/ungroup "1"
|
||
|
udevadm settle
|
||
|
fi
|
||
|
fi
|
||
|
[ -z "$mtu_was_set" ] && unset MTU
|
||
|
[ -z "$mmtu_was_set" ] && unset MMTU
|
||
|
[ -z "$vswitch_was_set" ] && unset VSWITCH
|
||
|
# prevent possible reuse of an old DEVICE on restarting dialog
|
||
|
unset DEVICE
|
||
|
# set activated DASDs offline again
|
||
|
local dasd
|
||
|
while read dasd < /proc/dasd/devices; do
|
||
|
dasd=${dasd%%(*}
|
||
|
sysecho /sys/bus/ccw/devices/$dasd/online 0
|
||
|
done
|
||
|
udevadm settle
|
||
|
}
|
||
|
|
||
|
### 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}
|
||
|
[[ "$NETTYPE" =~ (^qeth$)|(^lcs$)|(^ctc$) ]]
|
||
|
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 or value for network type (NETTYPE): $NETTYPE"
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
function question_prefix_nettype() {
|
||
|
echo -n $"Network type"
|
||
|
}
|
||
|
|
||
|
function question_choices_nettype() {
|
||
|
echo $" (qeth, lcs, ctc, ? for help). Default is qeth:"
|
||
|
}
|
||
|
|
||
|
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, Hipersockets, 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."
|
||
|
}
|
||
|
|
||
|
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 udevadm settle we
|
||
|
# could wait 2 seconds unconditionally)
|
||
|
#debug ls -laF /dev/.udev
|
||
|
udevadm settle
|
||
|
# 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
|
||
|
local driver
|
||
|
if [ "$NETTYPE" = "ctc" ]; then
|
||
|
driver="ctcm"
|
||
|
else
|
||
|
driver=$NETTYPE
|
||
|
fi
|
||
|
if [ "${CU_DEVDRV[$cu_idx]}" != "$driver" ]; 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
|
||
|
# TODO: not true for CTCM => relax
|
||
|
# - 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
|
||
|
local driver
|
||
|
if [ "$NETTYPE" = "ctc" ]; then
|
||
|
driver="ctcm"
|
||
|
else
|
||
|
driver=$NETTYPE
|
||
|
fi
|
||
|
if sysecho /sys/bus/ccwgroup/drivers/${driver}/group "$SUBCHANNELS"; then
|
||
|
udevadm settle
|
||
|
case "$NETTYPE" in
|
||
|
qeth)
|
||
|
# Just preliminary card_type info until device goes online!
|
||
|
# In fact it seems enough to separate OSA from HiperSockets.
|
||
|
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/$driver/$SCH_R_DEVBUSID/type ]; then
|
||
|
local type
|
||
|
read type < /sys/devices/$driver/$SCH_R_DEVBUSID/type
|
||
|
[ "$type" = "CTC/A" ] && \
|
||
|
type="channel-to-channel adapter (CTC/A)"
|
||
|
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. hipersockets 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() {
|
||
|
if [ -z "$LAYER2" ]; then
|
||
|
isLayer2Default && LAYER2=1 || LAYER2=0
|
||
|
# do not break, always apply, default may differ from online layer mode
|
||
|
#break
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
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() {
|
||
|
macaddr_default=$(ifconfig $DEVICE | grep 'HWaddr' | sed 's/.*HWaddr \([[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]\).*/\1/')
|
||
|
echo $" (e.g. 02:00:00:00:00:00, ? for help). Default is $macaddr_default:"
|
||
|
}
|
||
|
|
||
|
function helptext_macaddr() {
|
||
|
echo $" Help text for MAC address:"
|
||
|
if [ -z "${cardtype//OSD_*/}" ]; then
|
||
|
echo $" For real OSA in layer 2 mode, a random MAC address is automatically assigned."
|
||
|
else
|
||
|
echo $" If connecting to a layer 2 VSWITCH, a MAC address is automatically assigned."
|
||
|
fi
|
||
|
echo $" You may accept the automatic MAC address with an empty input. [default]"
|
||
|
echo $" If the automatic address is not unique, please provide a MAC address."
|
||
|
[ -z "${cardtype//OSD_*/}" ] && \
|
||
|
echo $" For real OSA, the provided address must be different from that of the OSA."
|
||
|
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() {
|
||
|
if [ -z "$MACADDR" ]; then
|
||
|
if [ -z "${cardtype//OSD_*/}" ]; then
|
||
|
# keep random default MAC address of real OSA,
|
||
|
# so the OSA comes up with the same MAC each time in the future
|
||
|
MACADDR=$macaddr_default
|
||
|
else
|
||
|
# virtual OSA in layer2 is GuestLAN or VSWITCH
|
||
|
VSWITCH=1
|
||
|
fi
|
||
|
break
|
||
|
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/ctcm/${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/lcs/$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
|
||
|
}
|
||
|
|
||
|
### 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 interfaces"
|
||
|
echo $" - z/VM guest LAN interfaces running in QDIO mode."
|
||
|
echo $" IPv6 is not supported on HiperSockets 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
|
||
|
if [ "$ipv6" ]; then
|
||
|
# qeth_l3 would load ipv6 automatically but not qeth_l2
|
||
|
modprobe ipv6
|
||
|
tv disable_ipv6_autoconf
|
||
|
fi
|
||
|
|
||
|
# 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
|
||
|
}
|
||
|
|
||
|
### NETWORK
|
||
|
|
||
|
function do_network() {
|
||
|
echo
|
||
|
echo $"The NETWORK parameter isn't used anymore and will be ignored."
|
||
|
echo $" It is sufficient to specify IPADDR and NETMASK."
|
||
|
echo
|
||
|
}
|
||
|
|
||
|
### BROADCAST
|
||
|
|
||
|
function do_broadcast() {
|
||
|
echo
|
||
|
echo $"The BROADCAST parameter isn't used anymore and will be ignored."
|
||
|
echo $" It is sufficient to specify IPADDR and NETMASK."
|
||
|
echo
|
||
|
}
|
||
|
|
||
|
### 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 -w 5 $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 -w 5 $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 or ESCON 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 -w 5 $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
|
||
|
unset range features range lo hi rangegood \
|
||
|
attrs devno lodevno hidevno devbusid sys
|
||
|
case $dasditem in
|
||
|
autodetect)
|
||
|
[ -z "$handle" ] && continue
|
||
|
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! Only activating visible DASDs."
|
||
|
fi
|
||
|
local sys
|
||
|
while read sys; do
|
||
|
if ! sysecho $sys/online 1; then
|
||
|
echo $"Could not set DASD ${sys##*/} online"
|
||
|
fi
|
||
|
done < <(find /sys/bus/ccw/drivers/dasd-eckd/ -name "*.?.????" 2>/dev/null;\
|
||
|
find /sys/bus/ccw/drivers/dasd-fba/ -name "*.?.????" 2>/dev/null)
|
||
|
;;
|
||
|
probeonly|nopav|nofcx)
|
||
|
if [ -z "$handle" ]; then
|
||
|
echo $"DASD option $dasditem not supported by installer"
|
||
|
fi
|
||
|
;;
|
||
|
"") continue ;; # empty range
|
||
|
*) local range features rangegood="yes"
|
||
|
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
|
||
|
lo=$(canonicalize_devno $lo) ;;
|
||
|
1) # string did not match the pattern
|
||
|
rangegood="no"
|
||
|
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
|
||
|
hi=$(canonicalize_devno $hi)
|
||
|
if [ "${lo%.*}" != "${hi%.*}" ]; then
|
||
|
echo $"Prefixes of DASD range $range do not match: ${lo%.*} != ${hi%.*}"
|
||
|
rangegood="no"
|
||
|
allgood="no"
|
||
|
fi
|
||
|
;;
|
||
|
1) # string did not match the pattern
|
||
|
rangegood="no"
|
||
|
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 [ "$rangegood" = "yes" -a "$handle" = "yes" ]; then
|
||
|
if ! sysecho /proc/cio_ignore "free $range"; then
|
||
|
echo $"Could not free DASD device $range from device blacklist"
|
||
|
allgood="no"
|
||
|
else
|
||
|
udevadm settle
|
||
|
fi
|
||
|
fi
|
||
|
if [ "${features//*)/}" != "" ]; then
|
||
|
if [ -z "$handle" ]; then
|
||
|
echo $"Missing closing parenthesis at features of DASD range $range: ($features"
|
||
|
allgood="no"
|
||
|
fi
|
||
|
fi
|
||
|
local attrs=""
|
||
|
if [ -n "$features" ]; then
|
||
|
features="${features%)}"
|
||
|
while read feature; do
|
||
|
case $feature in
|
||
|
ro) attrs=$attrs" readonly" ;;
|
||
|
diag) attrs=$attrs" use_diag" ;;
|
||
|
erplog|failfast) attrs=$attrs" "$feature ;;
|
||
|
*) if [ -z "$handle" ]; then
|
||
|
echo $"Unknown DASD feature for device range $range: $feature"
|
||
|
allgood="no"
|
||
|
fi
|
||
|
;;
|
||
|
esac
|
||
|
done < <(echo $features | sed 's/:/\n/g')
|
||
|
fi
|
||
|
[ "$rangegood" = "yes" ] || continue
|
||
|
[ "$handle" = "yes" ] || continue
|
||
|
# now apply $attrs and set DASDs $lo to $hi online
|
||
|
[ -z "$hi" ] && hi=$lo
|
||
|
local devno lodevno=$((0x${lo##*.})) hidevno=$((0x${hi##*.}))
|
||
|
for ((devno=$lodevno; $devno <= $hidevno; ++devno)); do
|
||
|
local devbusid=$(printf "%s.%04x" ${lo%.*} $devno)
|
||
|
local sys="/sys/bus/ccw/devices/"$devbusid
|
||
|
for attr in $attrs; do
|
||
|
if [ "$attr" = "use_diag" ]; then
|
||
|
# diag discipline cannot be auto-loaded
|
||
|
modprobe dasd_diag_mod
|
||
|
fi
|
||
|
if [ ! -f $sys/$attr ]; then
|
||
|
echo $"DASD $devbusid does not provide attribute $attr"
|
||
|
continue
|
||
|
fi
|
||
|
if ! sysecho $sys/$attr 1; then
|
||
|
echo $"Could not set attribute $attr for DASD $devbusid"
|
||
|
fi
|
||
|
done
|
||
|
if [ ! -f $sys/online ]; then
|
||
|
echo $"DASD $devbusid not found"
|
||
|
continue
|
||
|
fi
|
||
|
if ! sysecho $sys/online 1; then
|
||
|
echo $"Could not set DASD $devbusid online"
|
||
|
fi
|
||
|
done
|
||
|
;;
|
||
|
esac
|
||
|
done < <(echo $DASD | sed 's/,/\n/g')
|
||
|
if [ "$handle" = "yes" ]; then
|
||
|
udevadm settle
|
||
|
dasd_settle_all || return 1
|
||
|
echo $"Activated DASDs:"
|
||
|
cat /proc/dasd/devices | sed -e 's/ at ([^)]*) is//' -e 's/ at/,/'
|
||
|
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" ] && DASD="autodetect"
|
||
|
}
|
||
|
|
||
|
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
|
||
|
[ "$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
|
||
|
;;
|
||
|
d) # show active DASDs with some useful details
|
||
|
echo $"Activated DASDs:"
|
||
|
cat /proc/dasd/devices|sed -e 's/ at ([^)]*) is//' -e 's/ at/,/'
|
||
|
;;
|
||
|
r) break ;;
|
||
|
s) echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
|
||
|
/bin/bash
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
### MAIN ###
|
||
|
|
||
|
init_main
|
||
|
udev_setup
|
||
|
|
||
|
# Parse configuration
|
||
|
if [ -n "$CMSDASD" -a -n "$CMSCONFFILE" ]; then
|
||
|
readcmsfile $CMSDASD $CMSCONFFILE
|
||
|
source /tmp/$CMSCONFFILE #2>/dev/null
|
||
|
fi
|
||
|
|
||
|
if [ -r /sys/firmware/ipl/ipl_type ]; then
|
||
|
#local ipl_type
|
||
|
read ipl_type < /sys/firmware/ipl/ipl_type
|
||
|
if [ "$ipl_type" = "fcp" ]; then
|
||
|
while : ; do
|
||
|
echo $"Your IPL device is set to FCP."
|
||
|
echo $"Would you like to perform a CD-ROM/DVD-ROM installation? (y/n)"
|
||
|
#local do_cd_install
|
||
|
read do_cd_install
|
||
|
case $do_cd_install in
|
||
|
y|Y|[Yy][Ee][Ss])
|
||
|
# precondition: zfcp driver incl. dependencies loaded
|
||
|
#local CD_DEVICE WWPN LUN
|
||
|
read CD_DEVICE < /sys/firmware/ipl/device
|
||
|
read WWPN < /sys/firmware/ipl/wwpn
|
||
|
read LUN < /sys/firmware/ipl/lun
|
||
|
if sysecho /proc/cio_ignore "free $CD_DEVICE"; then
|
||
|
udevadm settle
|
||
|
# even though device might now be online, some of its
|
||
|
# sysfs attributes might not yet be available
|
||
|
sleep 1
|
||
|
else
|
||
|
echo $"Device $CD_DEVICE could not be cleared from device blacklist"
|
||
|
fi
|
||
|
sysecho /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/online 1 \
|
||
|
|| echo $"Could not set FCP device $CD_DEVICE online"
|
||
|
udevadm settle
|
||
|
# port (WWPN) appears automatically
|
||
|
sysecho /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/$WWPN/unit_add $LUN \
|
||
|
|| echo $"Could not add LUN $LUN at WWPN $WWPN on FCP device $CD_DEVICE"
|
||
|
udevadm settle
|
||
|
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
|
||
|
|
||
|
[ -n "$CHANDEV" ] && do_chandev
|
||
|
[ -n "$NETWORK" ] && do_network
|
||
|
[ -n "$BROADCAST" ] && do_broadcast
|
||
|
|
||
|
# [ -z "${cardtype//OSD_*/}" ] can be used to check for real OSA
|
||
|
|
||
|
# Check for missing parameters, prompt for them if necessary
|
||
|
while : ; do
|
||
|
|
||
|
# 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
|
||
|
|
||
|
# precondition: driver (qeth/lcs/ctcm) loaded incl. dependencies
|
||
|
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/HiperSockets/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
|
||
|
|
||
|
# 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
|
||
|
|
||
|
[ "$HOSTNAME" = "(none)" ] && unset HOSTNAME
|
||
|
do_hostname
|
||
|
|
||
|
# 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
|
||
|
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
|
||
|
|
||
|
modprobe_alias
|
||
|
do_dns
|
||
|
[ -n "$DNS" ] && do_searchdns
|
||
|
|
||
|
do_dasd
|
||
|
|
||
|
echo $"Initial configuration completed."
|
||
|
final_check && break
|
||
|
rollback_config
|
||
|
reenter="yes"
|
||
|
|
||
|
done # outer dialog loop
|
||
|
|
||
|
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 (originally 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 [ -n "$DASD" ]; then
|
||
|
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
|
||
|
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()
|
||
|
|
||
|
# 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
|
||
|
LANG="$LANG"
|
||
|
S390ARCH="$S390ARCH"
|
||
|
TEXTDOMAIN="$TEXTDOMAIN"
|
||
|
TEXTDOMAINDIR="$TEXTDOMAINDIR"
|
||
|
PORTNAME="$PORTNAME"
|
||
|
HOSTNAME="$HOSTNAME"
|
||
|
DEVICE="$DEVICE"
|
||
|
NETTYPE="$NETTYPE"
|
||
|
IPADDR="$IPADDR"
|
||
|
GATEWAY="$GATEWAY"
|
||
|
MTU="$MTU"
|
||
|
NETWORK="$NETWORK"
|
||
|
NETMASK="$NETMASK"
|
||
|
BROADCAST="$BROADCAST"
|
||
|
SEARCHDNS="$SEARCHDNS"
|
||
|
PEERID="$PEERID"
|
||
|
SUBCHANNELS="$SUBCHANNELS"
|
||
|
ONBOOT="yes"
|
||
|
CTCPROT="$CTCPROT"
|
||
|
EOF
|
||
|
if [ "$ipv6" ]; then
|
||
|
DNS1=$(echo $DNS | cut -d ',' -f 1)
|
||
|
echo DNS=\"$DNS1\" >> /tmp/install.cfg
|
||
|
echo DNS1=\"$DNS1\" >> /tmp/install.cfg
|
||
|
echo DNS2=\"$(echo $DNS | cut -d ',' -f 2)\" >> /tmp/install.cfg
|
||
|
else
|
||
|
DNS1=$(echo $DNS | cut -d ':' -f 1)
|
||
|
echo DNS=\"$DNS1\" >> /tmp/install.cfg
|
||
|
echo DNS1=\"$DNS1\" >> /tmp/install.cfg
|
||
|
echo DNS2=\"$(echo $DNS | cut -d ':' -f 2)\" >> /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 DNS1 DNS2 SEARCHDNS
|
||
|
export PEERID ONBOOT SUBCHANNELS CTCPROT
|
||
|
EOF
|
||
|
# immediately read it in again to export these into the shell below
|
||
|
. /tmp/install.cfg
|
||
|
if [ -z "$testing" ]; then
|
||
|
cat /tmp/install.cfg >> /etc/profile
|
||
|
fi # testing
|
||
|
|
||
|
NETSCRIPTS="/etc/sysconfig/network-scripts"
|
||
|
IFCFGFILE="$NETSCRIPTS/ifcfg-$DEVICE"
|
||
|
if [ ! -d "$NETSCRIPTS" ]; then
|
||
|
mkdir -p $NETSCRIPTS
|
||
|
fi
|
||
|
|
||
|
# to please NetworkManager on startup in loader before loader reconfigures net
|
||
|
cat > /etc/sysconfig/network << EOF
|
||
|
HOSTNAME=$HOSTNAME
|
||
|
EOF
|
||
|
|
||
|
cat > $IFCFGFILE << EOF
|
||
|
DEVICE=$DEVICE
|
||
|
ONBOOT=yes
|
||
|
BOOTPROTO=static
|
||
|
GATEWAY=$GATEWAY
|
||
|
BROADCAST=$BROADCAST
|
||
|
MTU=$MTU
|
||
|
SUBCHANNELS=$SUBCHANNELS
|
||
|
EOF
|
||
|
if [ "$ipv6" ]; then
|
||
|
cat >> $IFCFGFILE << EOF
|
||
|
IPV6INIT=yes
|
||
|
IPV6_AUTOCONF=no
|
||
|
IPV6ADDR=$IPADDR/$NETMASK
|
||
|
IPV6_DEFAULTGW=$GATEWAY
|
||
|
EOF
|
||
|
# FIXME: /etc/sysconfig/network:IPV6_DEFAULTGW=$GATEWAY
|
||
|
# /etc/sysconfig/network:NETWORKING_IPV6=yes
|
||
|
else
|
||
|
cat >> $IFCFGFILE << EOF
|
||
|
IPADDR=$IPADDR
|
||
|
NETMASK=$NETMASK
|
||
|
EOF
|
||
|
fi
|
||
|
[ "$DNS1" != "" ] && echo "DNS1=$DNS1" >> $IFCFGFILE
|
||
|
[ "$DNS2" != "" ] && echo "DNS2=$DNS2" >> $IFCFGFILE
|
||
|
# colons in SEARCHDNS already replaced with spaces above for /etc/resolv.conf
|
||
|
[ "$SEARCHDNS" != "" ] && echo "DOMAIN=\"$SEARCHDNS\"" >> $IFCFGFILE
|
||
|
[ "$NETTYPE" != "" ] && echo "NETTYPE=$NETTYPE" >> $IFCFGFILE
|
||
|
[ "$PEERID" != "" ] && echo "PEERID=$PEERID" >> $IFCFGFILE
|
||
|
[ "$PORTNAME" != "" ] && echo "PORTNAME=$PORTNAME" >> $IFCFGFILE
|
||
|
[ "$CTCPROT" != "" ] && echo "CTCPROT=$CTCPROT" >> $IFCFGFILE
|
||
|
[ "$MACADDR" != "" ] && echo "MACADDR=$MACADDR" >> $IFCFGFILE
|
||
|
optstr=""
|
||
|
for option in LAYER2 PORTNO; do
|
||
|
[ -z "${!option}" ] && continue
|
||
|
[ -n "$optstr" ] && optstr=${optstr}" "
|
||
|
optstr=${optstr}$(echo ${option} | tr [[:upper:]] [[:lower:]])"="${!option}
|
||
|
done
|
||
|
# write single quotes since network.py removes double quotes but we need quotes
|
||
|
echo "OPTIONS='$optstr'" >> $IFCFGFILE
|
||
|
unset option
|
||
|
unset optstr
|
||
|
|
||
|
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
|
||
|
LD_LIBRARY_PATH=$LD_LIBRARY_PATH
|
||
|
PATH=$PATH
|
||
|
HOME=$HOME
|
||
|
PYTHONPATH=$PYTHONPATH
|
||
|
export LD_LIBRARY_PATH PATH HOME PYTHONPATH
|
||
|
EOF
|
||
|
|
||
|
if [ -n "$DISPLAY" ]; then
|
||
|
echo "export DISPLAY=$DISPLAY" >> /etc/profile
|
||
|
fi
|
||
|
|
||
|
# 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
|
||
|
|
||
|
startinetd
|
||
|
|
||
|
if [ -n "$RUNKS" ]; then
|
||
|
/sbin/loader
|
||
|
fi
|
||
|
|
||
|
doshutdown
|
||
|
|
||
|
fi # testing
|
||
|
|
||
|
# ;;; Local Variables: ***
|
||
|
# ;;; mode: sh ***
|
||
|
# ;;; end: ***
|