diff options
Diffstat (limited to 'sysconfig/network-scripts/network-functions')
-rw-r--r-- | sysconfig/network-scripts/network-functions | 744 |
1 files changed, 0 insertions, 744 deletions
diff --git a/sysconfig/network-scripts/network-functions b/sysconfig/network-scripts/network-functions deleted file mode 100644 index c2756b19..00000000 --- a/sysconfig/network-scripts/network-functions +++ /dev/null @@ -1,744 +0,0 @@ -# -*-Shell-script-*- -# -# This file is not a stand-alone shell script; it provides functions -# to network scripts that source it. - -# Set up a default search path. -PATH="/sbin:/usr/sbin:/bin:/usr/bin" -export PATH - -# We need to initialize the $HOSTNAME variable by ourselves now: -# (It was previously done for RHEL-6 branch, but got lost in time.) -HOSTNAME="$(hostname)" - -[ -z "$__sed_discard_ignored_files" ] && . /etc/init.d/functions - -get_hwaddr () -{ - if [ -f /sys/class/net/${1}/address ]; then - tr '[a-z]' '[A-Z]' < /sys/class/net/${1}/address - elif [ -d "/sys/class/net/${1}" ]; then - LC_ALL= LANG= ip -o link show ${1} 2>/dev/null | \ - awk '{ print toupper(gensub(/.*link\/[^ ]* ([[:alnum:]:]*).*/, - "\\1", 1)); }' - fi -} - -get_config_by_device () -{ - LANG=C grep -l "^[[:space:]]*DEVICE=['\"]\?${1}['\"]\?\([[:space:]#]\|$\)" \ - /etc/sysconfig/network-scripts/ifcfg-* \ - | LC_ALL=C sed -e "$__sed_discard_ignored_files" -} - -get_config_by_hwaddr () -{ - LANG=C grep -il "^[[:space:]]*HWADDR=['\"]\?${1}['\"]\?\([[:space:]#]\|$\)" /etc/sysconfig/network-scripts/ifcfg-* \ - | LC_ALL=C sed -e "$__sed_discard_ignored_files" -} - -get_config_by_subchannel () -{ - LANG=C grep -E -i -l \ - "^[[:space:]]*SUBCHANNELS=['\"]?([0-9]\.[0-9]\.[a-f0-9]+,){0,2}${1}(,[0-9]\.[0-9]\.[a-f0-9]+){0,2}['\"]?([[:space:]]+#|[[:space:]]*$)" \ - /etc/sysconfig/network-scripts/ifcfg-* \ - | LC_ALL=C sed -e "$__sed_discard_ignored_files" -} - -get_config_by_name () -{ - LANG=C grep -E -i -l "^[[:space:]]*NAME=\"(Auto |System )?${1}\"" \ - /etc/sysconfig/network-scripts/ifcfg-* \ - | LC_ALL=C sed -e "$__sed_discard_ignored_files" -} - -get_device_by_hwaddr () -{ - LANG=C ip -o link | awk -F ': ' -vIGNORECASE=1 '!/link\/ieee802\.11/ && /'"$1"'/ { print $2 }' -} - -get_uuid_by_config () -{ - dbus-send --system --print-reply --dest=com.redhat.ifcfgrh1 /com/redhat/ifcfgrh1 com.redhat.ifcfgrh1.GetIfcfgDetails string:"/etc/sysconfig/network-scripts/$1" 2>/dev/null | awk -F '"' '/string / { print $2 }' -} - -generate_lease_file_name () -{ - local ver=$1 - LEASEFILE="/var/lib/dhclient/dhclient$ver-${DEVICE}.leases" - if [ -f $LEASEFILE ]; then - return - fi - LEASEFILE="/var/lib/dhclient/dhclient$ver-${UUID}-${DEVICE}.lease" -} - -generate_config_file_name () -{ - local ver=$1 - if [ -s /etc/dhcp/dhclient$ver-${DEVICE}.conf ]; then - DHCLIENTCONF="-cf /etc/dhcp/dhclient$ver-${DEVICE}.conf"; - elif [ -s /etc/dhclient$ver-${DEVICE}.conf ]; then - DHCLIENTCONF="-cf /etc/dhclient$ver-${DEVICE}.conf"; - else - DHCLIENTCONF=''; - fi -} - -need_config () -{ - local nconfig - - CONFIG="ifcfg-${1}" - [ -f "${CONFIG}" ] && return - CONFIG="${1##*/}" - [ -f "${CONFIG}" ] && return - nconfig=$(get_config_by_name "${1}") - if [ -n "$nconfig" ] && [ -f "$nconfig" ]; then - CONFIG=${nconfig##*/} - return - fi - local addr=$(get_hwaddr ${1}) - if [ -n "$addr" ]; then - nconfig=$(get_config_by_hwaddr ${addr}) - if [ -n "$nconfig" ] ; then - CONFIG=${nconfig##*/} - [ -f "${CONFIG}" ] && return - fi - fi - nconfig=$(get_config_by_device ${1}) - if [ -n "$nconfig" ] && [ -f "$nconfig" ]; then - CONFIG=${nconfig##*/} - return - fi -} - -source_config () -{ - CONFIG=${CONFIG##*/} - DEVNAME=${CONFIG##ifcfg-} - . /etc/sysconfig/network-scripts/$CONFIG - [ -r "keys-$DEVNAME" ] && . /etc/sysconfig/network-scripts/keys-$DEVNAME - case "$TYPE" in - Ethernet) - DEVICETYPE="eth" - ;; - CIPE) - DEVICETYPE="cipcb" - ;; - IPSEC) - DEVICETYPE="ipsec" - ;; - Modem) - DEVICETYPE="ppp" - ;; - xDSL) - DEVICETYPE="ppp" - ;; - ISDN) - DEVICETYPE="ippp" - ;; - Wireless) - DEVICETYPE="eth" - ;; - "Token Ring") - DEVICETYPE="eth" - ;; - CTC) - DEVICETYPE="ctc" - ;; - GRE | IPIP | IPIP6) - DEVICETYPE="tunnel" - ;; - SIT | sit) - DEVICETYPE="sit" - ;; - InfiniBand | infiniband) - DEVICETYPE="ib" - ;; - OVS*) - DEVICETYPE="ovs" - ;; - esac - if [ -n "$HWADDR" ]; then - HWADDR=$(tr '[a-z]' '[A-Z]' <<<"$HWADDR") - fi - if [ -n "$MACADDR" ]; then - MACADDR=$(tr '[a-z]' '[A-Z]' <<<"$MACADDR") - fi - [ -z "$DEVICE" -a -n "$HWADDR" ] && DEVICE=$(get_device_by_hwaddr $HWADDR) - [ -z "$DEVICETYPE" ] && DEVICETYPE=$(echo ${DEVICE} | sed "s/[0-9]*$//") - [ -z "$REALDEVICE" -a -n "$PARENTDEVICE" ] && REALDEVICE=$PARENTDEVICE - [ -z "$REALDEVICE" ] && REALDEVICE=${DEVICE%%:*} - [ -z "$SYSCTLDEVICE" ] && SYSCTLDEVICE=${REALDEVICE/.//} - if [ "${DEVICE}" != "${REALDEVICE}" ]; then - ISALIAS=yes - else - ISALIAS=no - fi - if is_nm_running && [ "$REALDEVICE" != "lo" ] ; then - nm_con_load "$CONFIG" - if ! is_false $NM_CONTROLLED; then - UUID=$(get_uuid_by_config $CONFIG) - [ -n "$UUID" ] && _use_nm=true - fi - fi -} - -nm_con_load () { - dbus-send --system --print-reply \ - --dest=org.freedesktop.NetworkManager \ - /org/freedesktop/NetworkManager/Settings \ - org.freedesktop.NetworkManager.Settings.LoadConnections \ - array:string:"/etc/sysconfig/network-scripts/${1}" >/dev/null 2>&1 -} - -ethtool_set() -{ - oldifs=$IFS; - IFS=';'; - if [ -n "${ETHTOOL_DELAY}" ]; then - # Convert microseconds to seconds: - local ETHTOOL_DELAY_SEC=$(convert2sec ${ETHTOOL_DELAY} micro) - sleep ${ETHTOOL_DELAY_SEC} - fi - for opts in $ETHTOOL_OPTS ; do - IFS=$oldifs; - if [[ "${opts}" =~ [[:space:]]*- ]]; then - /sbin/ethtool $opts - else - /sbin/ethtool -s ${REALDEVICE} $opts - fi - IFS=';'; - done - IFS=$oldifs; -} - -expand_config () -{ - local i=0 val - for idx in '' {0..255} ; do - ipaddr[$i]=$(eval echo '$'IPADDR$idx) - if [ -z "${ipaddr[$i]}" ]; then - [ "$idx" ] && [ $idx -ge 2 ] && break - continue - fi - prefix[$i]=$(eval echo '$'PREFIX$idx) - netmask[$i]=$(eval echo '$'NETMASK$idx) - broadcast[$i]=$(eval echo '$'BROADCAST$idx) - arpcheck[$i]=$(eval echo '$'ARPCHECK$idx) - arpupdate[$i]=$(eval echo '$'ARPUPDATE$idx) - - if [ "${prefix[$i]}x" != "x" ]; then - val=$(/bin/ipcalc --netmask "${ipaddr[$i]}/${prefix[$i]}") - netmask[$i]=${val##NETMASK=} - fi - - if [ "${netmask[$i]}x" = "x" ]; then - val=$(/bin/ipcalc --netmask "${ipaddr[$i]}") - netmask[$i]=${val##NETMASK=} - fi - - if [ "${prefix[$i]}x" = "x" ]; then - val=$(/bin/ipcalc --prefix ${ipaddr[$i]} ${netmask[$i]}) - prefix[$i]=${val##PREFIX=} - fi - - if [ "${broadcast[$i]}x" = "x" ]; then - val=$(/bin/ipcalc --broadcast ${ipaddr[$i]} ${netmask[$i]}) - broadcast[$i]=${val##BROADCAST=} - fi - - if [ "${arpcheck[$i]}x" != "x" ]; then - arpcheck[$i]=${arpcheck[$i]##ARPCHECK=} - arpcheck[$i]=${arpcheck[$i],,*} - fi - - if [ "${arpupdate[$i]}x" != "x" ]; then - arpupdate[$i]=${arpupdate[$i]##ARPUPDATE=} - arpupdate[$i]=${arpupdate[$i],,*} - fi - - i=$((i+1)) - done - - [ -n "$DHCP_HOSTNAME" ] && DHCP_HOSTNAME=${DHCP_HOSTNAME%%.*} - - if [ -z "${NETWORK}" ]; then - eval $(/bin/ipcalc --network ${ipaddr[0]} ${netmask[0]}) - fi -} - -toggle_value () -{ - if [ "$2" = "yes" -o "$2" = "YES" ] ; then - echo "$1 on" - elif [ "$2" = "no" -o "$2" = "NO" ] ; then - echo "$1 off" - else - echo '' - fi -} - -do_netreport () -{ - # Notify programs that have requested notification - ( - cd /run/netreport || exit - for i in * ; do - if [ -f $i ]; then - if [ "$(id -u)" = "0" ]; then - OWNER=$(stat -c %U $i) - su -s /bin/bash $OWNER -c "kill -SIGIO $i >/dev/null 2>&1 || rm -f $i >/dev/null 2>&1" > /dev/null 2>&1 - else - kill -SIGIO $i >/dev/null 2>&1 || rm -f $i >/dev/null 2>&1 - fi - fi - done - ) -} - -is_nm_running () -{ - dbus-send --system --print-reply \ - --dest=org.freedesktop.DBus \ - /org/freedesktop/DBus \ - org.freedesktop.DBus.GetNameOwner \ - string:"org.freedesktop.NetworkManager" >/dev/null 2>&1 -} - -is_nm_active () -{ - LANG=C nmcli -t --fields device,state dev status 2>/dev/null | grep -q "^${1}:connected$" -} - -is_nm_handling () -{ - LANG=C nmcli -t --fields device,state dev status 2>/dev/null | grep -q "^\(${1}:connected\)\|\(${1}:connecting.*\)$" -} - -is_nm_device_unmanaged () -{ - LANG=C nmcli -t --fields GENERAL dev show "${1}" 2>/dev/null | awk -F ':' '/GENERAL.STATE/ { if ($2 == "unmanaged") exit 0 ; else exit 1; }' -} - -# Sets $alias to the device module if $? != 0 -is_available () -{ - [ -z "$1" ] && return 1 - - [ -d "/sys/class/net/$1" ] && return 0 - - [ -n "$BONDING_OPTS" ] && install_bonding_driver $1 - - alias=$(modprobe -c | awk \ - 'BEGIN { alias = ""; } - $1 == "alias" && $2 == "'"$1"'" { alias = $3; } - $1 == "install" { install[$2] = $3; } - END { - cmd = install[alias]; - print alias; - if (alias == "" || alias == "off" || cmd == "/bin/true" || cmd == ":") - exit 1; - exit 0; - } - ') - [ $? -eq 0 ] || return 2 - - modprobe $1 > /dev/null 2>&1 || { - return 1 - } - if [ -n "$HWADDR" ]; then - local curdev=$(get_device_by_hwaddr "$HWADDR") - if [ -z "$curdev" ]; then - return 1 - fi - fi - - if [ ${alias} = "bonding" ]; then - install_bonding_driver $1 - fi - - [ -d "/sys/class/net/$1" ] && return 0 || return 1 -} - -is_available_wait () -{ - [ -z "$1" ] && return 1 - - local retry=${2##*[!0-9]*} - - is_available $1 && return 0 - ret=$? - - while [ 0"$retry" -gt 0 ]; do - sleep 1 - [ -d "/sys/class/net/$1" ] && return 0 - retry=$(($retry -1)) - done - - return $ret -} - -is_hostname_set () -{ - case "${HOSTNAME}" in - '(none)' | 'localhost' | 'localhost.localdomain') - # Hostname NOT set: - return 1 - ;; - *) - # Hostname IS set: - return 0 - ;; - esac -} - -need_hostname () -{ - # Should we avoid obtaining hostname from DHCP? (user override) - is_true "${NO_DHCP_HOSTNAME}" && return 1 - - if is_hostname_set; then - # Hostname is already set, we do not need to acquire it: - return 1 - else - # Hostname is NOT set, we need to acquire it: - return 0 - fi -} - -set_hostname_options () -{ - # User explicitly requires to *not* send DHCP_HOSTNAME, DHCP_FQDN or HOSTNAME: - is_false "${DHCP_SEND_HOSTNAME}" && return - - if [[ -n "${DHCP_HOSTNAME}" && -n "${DHCP_FQDN}" ]]; then - net_log $"Both 'DHCP_HOSTNAME=${DHCP_HOSTNAME}' and 'DHCP_FQDN=${DHCP_FQDN}' are configured... Using DHCP_FQDN." warning - fi - - local hostname_options='' - - # DHCP_FQDN takes precedence before DHCP_HOSTNAME -- as it does in NetworkManager, - # and DHCP_HOSTNAME takes precedence before HOSTNAME: - if [[ -n "${DHCP_FQDN}" ]]; then - hostname_options="-F ${DHCP_FQDN}" - elif [[ -n "${DHCP_HOSTNAME}" ]]; then - hostname_options="-H ${DHCP_HOSTNAME}" - elif is_hostname_set; then - # We need to truncate the hostname in case it is the FQDN: - hostname_options="-H ${HOSTNAME%%.*}" - else - # Nothing to send to the DHCP server: - # ['(none)', 'localhost' or 'localhost.localdomain' are not valid] - return - fi - - # Append the hostname options to the content of passed variable name: - eval "$1='${!1} ${hostname_options}'" - - return -} - -set_hostname () -{ - hostname $1 - if ! grep search /etc/resolv.conf >/dev/null 2>&1; then - domain=$(echo $1 | sed 's/^[^\.]*\.//') - if [ -n "$domain" ]; then - rsctmp=$(mktemp /tmp/XXXXXX); - cat /etc/resolv.conf > $rsctmp - echo "search $domain" >> $rsctmp - - # Backup resolv.conf only if it doesn't exist already: - ! [ -f /etc/resolv.conf.save ] && cp -af /etc/resolv.conf /etc/resolv.conf.save - - change_resolv_conf $rsctmp - /bin/rm -f $rsctmp - fi - fi -} - -check_device_down () -{ - [ ! -d /sys/class/net/$1 ] && return 0 - if LC_ALL=C ip -o link show dev $1 2>/dev/null | grep -q ",UP" ; then - return 1 - else - return 0 - fi -} - -check_link_down () -{ - if ! LC_ALL=C ip link show dev $1 2>/dev/null| grep -q ",UP" ; then - ip link set dev $1 up >/dev/null 2>&1 - fi - timeout=0 - delay=10 - [ -n "$LINKDELAY" ] && delay=$(($LINKDELAY * 2)) - while [ $timeout -le $delay ]; do - [ "$(cat /sys/class/net/$REALDEVICE/carrier 2>/dev/null)" != "0" ] && return 1 - sleep 0.5 - timeout=$((timeout+1)) - done - return 0 -} - -check_default_route () -{ - LC_ALL=C ip route list match 0.0.0.0/0 | grep -q default -} - -find_gateway_dev () -{ - . /etc/sysconfig/network - if [ -n "${GATEWAY}" -a "${GATEWAY}" != "none" ] ; then - dev=$(LC_ALL=C /sbin/ip route get to "${GATEWAY}" 2>/dev/null | \ - sed -n 's/.* dev \([[:alnum:]]*\) .*/\1/p') - if [ -n "$dev" ]; then - GATEWAYDEV="$dev" - fi - fi -} - -# After the device $1 goes away, restore the standard default route; typically -# used for ppp with DEFROUTE temporarily replacing the "standard" default -# route. -# FIXME: This function doesn't support some newer features (GATEWAY in ifcfg, -# $WINDOW, $METRIC) -add_default_route () -{ - . /etc/sysconfig/network - check_default_route && return 0 - find_gateway_dev - if [ "$GATEWAYDEV" != "" -a -n "${GATEWAY}" -a \ - "${GATEWAY}" != "none" ]; then - if ! check_device_down $1; then - if [ "$GATEWAY" = "0.0.0.0" ]; then - /sbin/ip route add default dev ${GATEWAYDEV} - else - /sbin/ip route add default via ${GATEWAY} - fi - fi - elif [ -f /etc/default-routes ]; then - while read spec; do - /sbin/ip route add $spec - done < /etc/default-routes - rm -f /etc/default-routes - fi -} - -is_wireless_device () -{ - [ -x /usr/sbin/iw ] || return 1 - LC_ALL=C /usr/sbin/iw dev $1 info > /dev/null 2>&1 && return 0 - return 1 -} - -phy_wireless_device () -{ - cat /sys/class/net/$1/phy80211/name -} - -bond_master_exists () -{ - local bond_name - [ -z "${1}" ] && return 1 - [ ! -f /sys/class/net/bonding_masters ] && return 1 - - for bond_name in $(< /sys/class/net/bonding_masters); do - [ "${bond_name}" == "${1}" ] && return 0 - done - return 1 -} - -install_bonding_driver () -{ - local fn="install_bonding_driver" - - if ! bond_master_exists ${1}; then - modprobe bonding || return 1 - echo "+$1" > /sys/class/net/bonding_masters 2>/dev/null - fi - ( - # Set config here - need_config "$1" - source_config - if [ -f /sys/class/net/${DEVICE}/bonding/slaves ] && [ $(wc -l < /sys/class/net/${DEVICE}/bonding/slaves) -eq 0 ]; then - /sbin/ip link set dev ${DEVICE} down - - # parse options and put them to arrays - for arg in $BONDING_OPTS ; do - bopts_keys[${#bopts_keys[*]}]=${arg%%=*} - bopts_vals[${#bopts_vals[*]}]=${arg##*=} - done - - # add the bits to setup driver parameters here - # first set mode, miimon - for (( idx=0; idx < ${#bopts_keys[*]}; idx++ )) ; do - key=${bopts_keys[$idx]} - value=${bopts_vals[$idx]} - - if [ "${key}" = "mode" ] ; then - echo "${value}" > /sys/class/net/${DEVICE}/bonding/$key || { - net_log $"Failed to set value '$value' [mode] to ${DEVICE} bonding device" err $fn - } - bopts_keys[$idx]="" - fi - if [ "${key}" = "miimon" ] ; then - echo "${value}" > /sys/class/net/${DEVICE}/bonding/$key || { - net_log $"Failed to set value '$value' [miimon] to ${DEVICE} bonding device" err $fn - } - bopts_keys[$idx]="" - fi - done - - # set all other remaining options - for (( idx=0; idx < ${#bopts_keys[*]}; idx++ )) ; do - key=${bopts_keys[$idx]} - value=${bopts_vals[$idx]} - - # option already set; take next - [[ -z "$key" ]] && continue - - if [ "${key}" = "arp_ip_target" -a "${value:0:1}" != "+" ]; then - OLDIFS=$IFS; - IFS=','; - for arp_ip in $value; do - if ! grep -q $arp_ip /sys/class/net/${DEVICE}/bonding/$key; then - echo +$arp_ip > /sys/class/net/${DEVICE}/bonding/$key || { - net_log $"Failed to set '$arp_ip' value [arp_ip_target] to ${DEVICE} bonding device" err $fn - } - fi - done - IFS=$OLDIFS; - elif [ "${key}" = "arp_ip_target" ]; then - if ! grep -q ${value#+} /sys/class/net/${DEVICE}/bonding/$key; then - echo "$value" > /sys/class/net/${DEVICE}/bonding/$key || { - net_log $"Failed to set '$value' value [arp_ip_target] to ${DEVICE} bonding device" err $fn - } - fi - elif [ "${key}" != "primary" ]; then - echo $value > /sys/class/net/${DEVICE}/bonding/$key || { - net_log $"Failed to set '$value' value [$key] to ${DEVICE} bonding device" err $fn - } - fi - done - fi - ) - return 0 -} - -is_bonding_device () -{ - [ -f "/sys/class/net/$1/bonding/slaves" ] -} - -# Invoke this when /etc/resolv.conf has changed: -change_resolv_conf () -{ - s=$(/bin/grep '^[\ \ ]*option' /etc/resolv.conf 2>/dev/null) - if [ $# -gt 1 ]; then - if [ "x$s" != "x" ]; then - s="$s"$'\n' - fi - n_args=$# - while [ $n_args -gt 0 ]; do - case "$s" in - *$1*) - shift - n_args=$(($n_args-1)) - continue - ;; - esac - s="$s$1" - shift - if [ $# -gt 0 ]; then - s="$s"$'\n' - fi - n_args=$(($n_args-1)) - done - elif [ $# -eq 1 ]; then - if [ "x$s" != "x" ]; then - s="$s"$'\n'$(/bin/grep -vF "$s" $1) - else - s=$(cat $1) - fi - fi - (echo "$s" > /etc/resolv.conf) >/dev/null 2>&1; - r=$? - if [ $r -eq 0 ]; then - [ -x /sbin/restorecon ] && /sbin/restorecon /etc/resolv.conf >/dev/null 2>&1 # reset the correct context - /usr/bin/logger -p local7.notice -t "NET" -i "$0 : updated /etc/resolv.conf" - [ -e /run/nscd/socket ] && /usr/sbin/nscd -i hosts # invalidate cache - fi - return $r -} - -# Logging function -# -# Usage: net_log <message> <err|warning|info> <optional file/function name> -# -# Default level is 'err'. - -net_log() -{ - local message="$1" - local level="$2" - local name="$3" - - [ -z "$message" ] && return 1 - [ -z "$level" ] && level=err - [ -z "$name" ] && name=$0 - - case $level in - 'debug') - local txt_level=$"DEBUG " - ;; - 'err') - local txt_level=$"ERROR " - ;; - 'warning') - local txt_level=$"WARN " - ;; - 'info') - local txt_level=$"INFO " - ;; - esac - - echo "$txt_level: [$name] $message" - - if [ -x /usr/bin/logger ]; then - /usr/bin/logger -p daemon.$level -t "$name" "$message" - fi - return 0 -} - -update_DNS_entries() -{ - # Remove duplicate values from DNS options if any: - if [ -n "${DNS3}" ] && [[ "${DNS3}" == "${DNS2}" || "${DNS3}" == "${DNS1}" ]]; then - unset DNS3 - fi - - if [ -n "${DNS2}" ] && [[ "${DNS2}" == "${DNS1}" ]]; then - unset DNS2 - fi - - # Shift the DNS options if necessary: - if [ -z "${DNS1}" ] && [ -n "${DNS2}" ]; then - DNS1="${DNS2}" - unset DNS2 - fi - - if [ -z "${DNS2}" ] && [ -n "${DNS3}" ]; then - DNS2="${DNS3}" - unset DNS3 - fi - - # We need to check DNS1 again in case only DNS3 was set at all: - if [ -z "${DNS1}" ] && [ -n "${DNS2}" ]; then - DNS1="${DNS2}" - unset DNS2 - fi -} |