home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / rescue / etc / sysconfig / network / scripts / functions < prev    next >
Text File  |  2006-11-29  |  16KB  |  568 lines

  1. #!/bin/bash
  2.  
  3. # Network interface configuration
  4. #
  5. # Copyright (c) 2002-2006 SuSE Linux AG Nuernberg, Germany.
  6. # All rights reserved.
  7. #
  8. # This program is free software; you can redistribute it and/or modify it under
  9. # the terms of the GNU General Public License as published by the Free Software
  10. # Foundation; either version 2 of the License, or (at your option) any later
  11. # version.
  12. #
  13. # This program is distributed in the hope that it will be useful, but WITHOUT
  14. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  16. # details.
  17. #
  18. # You should have received a copy of the GNU General Public License along with
  19. # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. # Place, Suite 330, Boston, MA 02111-1307 USA
  21. #
  22. # Authors: Michal Svec <msvec@suse.cz>
  23. #          Mads Martin Joergensen <mmj@suse.de>
  24. #
  25. # $Id: functions 1525 2006-11-20 11:39:48Z zoz $
  26. #
  27.  
  28. . /etc/sysconfig/network/scripts/functions.common
  29.  
  30. NETWORK_RUNFILE="$RUN_FILES_BASE/network"
  31. STAMPFILE_STUB="$RUN_FILES_BASE/new-stamp-"
  32. NETWORKMANAGER_BIN=/usr/sbin/NetworkManager
  33. NM_ONLINE_BIN=/usr/bin/nm-online
  34. NM_DISPATCHER_BIN=/usr/sbin/NetworkManagerDispatcher
  35. DHCDBD_BIN=/usr/sbin/dhcdbd
  36.  
  37. #
  38. # to test the next two functions:
  39. #
  40. # for i in $(seq 0 32); do
  41. #     echo $i: $(pfxlen2mask $i) " ---> " $(mask2pfxlen $(pfxlen2mask $i))
  42. # done
  43.  
  44. mask2pfxlen() {
  45.     local i octet mask width=0
  46.  
  47.     IFS_SAVE=$IFS; IFS="."
  48.     mask=($*)
  49.     IFS=$IFS_SAVE
  50.     test -n "$mask" || return
  51.     
  52.     for octet in 0 1 2 3; do
  53.         test "${mask[octet]}" -ge 0 -a "${mask[octet]}" -le 255 2>/dev/null \
  54.             || return
  55.         for i in 128 192 224 240 248 252 254 255; do
  56.             test ${mask[octet]} -ge $i && ((width++))
  57.         done
  58.     done
  59.     
  60.     test $width -ge 0 && echo $width
  61. }
  62.  
  63. pfxlen2mask() {
  64.     local i bit n=1 width=$1
  65.  
  66.     test -n "$width" || return 0
  67.  
  68.     for ((i=1; $i<=$width; i++)); do
  69.         bit[$i]=1
  70.     done; echo
  71.  
  72.     for o in 1 2 3 4; do
  73.         octet[$o]=0
  74.         for i in 128 64 32 16 8 4 2 1; do
  75.             test ${bit[$n]:-0} -eq 1 && ((octet[$o] = ${octet[$o]} + $i))
  76.             ((n++))
  77.         done
  78.     done
  79.  
  80.     echo ${octet[1]}.${octet[2]}.${octet[3]}.${octet[4]}
  81. }
  82.  
  83. is_iface_available () {
  84.     test -z "$1" && return 1
  85.     case $1 in
  86.         ippp*|isdn*) return 0 ;;
  87.         modem*|dsl*|ppp*) return 0 ;;
  88.         vlan*) return 0 ;;
  89.         sit*|gre*|ipip*) return 0 ;;
  90.     esac
  91.     test "${SCRIPTNAME%%-*}" = ifdown -a "$MODE" = hotplug && return 0
  92.     test "${SCRIPTNAME%%-*}" = ifup -a "$BONDING_MASTER" = yes && return 0
  93.     test "${SCRIPTNAME%%-*}" = ifup -a "$BRIDGE" = yes && return 0
  94.     ip link list $1 &>/dev/null
  95. }
  96.  
  97. is_iface_up () {
  98.     test -z "$1" && return 1
  99.     case "`LC_ALL=POSIX ip link show $1 2>/dev/null`" in
  100.         *$1*UP*) ;;
  101.         *) return 1 ;;
  102.     esac
  103. }
  104.  
  105. get_hwaddress () {
  106.     test -z "$1" && return 1
  107.     local a b=""
  108.     for a in $(LC_ALL=POSIX ip link show $1 2>/dev/null ); do
  109.         if [ "$b" = "link/ether" ] ; then
  110.             echo $a
  111.             break
  112.         fi
  113.         b=$a
  114.     done
  115. }
  116.  
  117. # This will echo the first address listed for the given interface.
  118. get_ipv4address () {
  119.     test -z "$1" && return 1
  120.     local a b c
  121.     while read a b c; do
  122.         if [ "$a" = inet ] ; then
  123.             break
  124.         fi
  125.     done < <(LC_ALL=POSIX ip -4 address list "$1" 2>/dev/null)
  126.     test -z "$b" && return 1
  127.     echo ${b%%/*}
  128. }
  129.  
  130. convert_ipv4address_to_6to4 () {
  131.     printf "2002:%02x%02x:%02x%02x::1\n" $(IFS=.; echo $1)
  132. }
  133.  
  134. convert_6to4_to_ipv4address () {
  135.     ADDR=$1
  136.     PART_1=`expr $ADDR : '2002:\([^:]*\):[^:]*:'`
  137.     PART_2=`expr $ADDR : '2002:[^:]*:\([^:]*\):'`
  138.     if [ "$PART_1" = "" -o "$PART_2" = "" ]; then 
  139.         echo $ADDR
  140.     fi
  141.     NORM_1=`printf "%04x" 0x$PART_1`
  142.     NORM_2=`printf "%04x" 0x$PART_2`
  143.  
  144.     printf "::%u.%u.%u.%u" \
  145.         0x${NORM_1:0:2} 0x${NORM_1:2:2} \
  146.         0x${NORM_2:0:2} 0x${NORM_2:2:2}
  147. }
  148.  
  149. # Loads module 'bonding' if not already loaded.
  150. # Creates a new bonding master interface and sets its options.
  151. # Usage: load_bond $INTERFACE $BONDING_MODULE_OPTIONS
  152. # Module option 'max_bonds' will be ignored. Use one configuration file per
  153. # bonding interface instead.
  154. # If first argument is '_no_fail_' then failures in setting interface options
  155. # will not return an error.
  156. load_bond() {
  157.     local NIF OPT OPT_NAME OPT_VALUE OLD_OPT_VALUE OLD_OPT_VALUE_2 IF NOFAIL
  158.     if [ "$1" == _no_fail_ ] ; then
  159.         NOFAIL=1
  160.         shift
  161.     fi
  162.     IF=$1
  163.     test -z "$IF" && return 0
  164.     shift
  165.     if [ -d /sys/class/net/$IF -a ! -d /sys/class/net/$IF/bonding ] ; then
  166.         return 1 # Iface exists but of another type
  167.     fi
  168.     if [ ! -r /sys/class/net/bonding_masters ] ; then
  169.        /sbin/modprobe bonding
  170.         # If we add module option max_bonds=0 in the modprobe command above then
  171.         # we may skip the following lines in this if-fi block.
  172.         for a in `seq 33`; do
  173.             test -r /sys/class/net/bonding_masters && break
  174.             usleep 300000
  175.         done
  176.         NIF=`cat /sys/class/net/bonding_masters`
  177.         if [ -n "$NIF" -a "$NIF" != "$IF" ] ; then
  178.             nameif -r $IF $NIF
  179.         fi
  180.     fi
  181.     if [ ! -d /sys/class/net/$IF/bonding ] ; then
  182.         echo "+$IF" > /sys/class/net/bonding_masters
  183.     fi
  184.     for a in `seq 33`; do
  185.         test -d /sys/class/net/$IF/bonding && break
  186.         usleep 300000
  187.     done
  188.     if [ ! -d /sys/class/net/$IF/bonding ] ; then
  189.         return 1
  190.     fi
  191.     # Set options
  192.     sleep 1
  193.     for OPT in $*; do
  194.         read OPT_NAME OPT_VALUE < <(IFS==; echo $OPT)
  195.         if [ "$OPT_NAME" == max_bonds ] ; then
  196.             err_mesg "Don't use option max_bonds."
  197.             continue
  198.         fi
  199.         if [ ! -w /sys/class/net/$IF/bonding/$OPT_NAME ] ; then
  200.             err_mesg "There is no option '$OPT_NAME' for interface '$IF'."
  201.             echo "-$IF" > /sys/class/net/bonding_masters
  202.             return 1 # or continue? I guess its better to fail completely
  203.         fi
  204.         # Some options may only be changed if the interface is up and slaves are
  205.         # already assigned. Others may only be changed if it is down. To avoid
  206.         # unneccessary error messages or warnings we check first if the option
  207.         # already has the specified value.
  208.         # Special case for option 'mode': this sysfs attribute contains two
  209.         # words. A string describing the mode and the corresponding number. We
  210.         # have to compare both.
  211.         read OLD_OPT_VALUE OLD_OPT_VALUE_2 < /sys/class/net/$IF/bonding/$OPT_NAME
  212.         if [    "$OLD_OPT_VALUE" == "$OPT_VALUE" \
  213.              -o \( "$OPT_NAME" == mode -a "$OLD_OPT_VALUE_2" == "$OPT_VALUE" \) \
  214.            ] ; then
  215.             info_mesg "Bonding interface '$IF':" \
  216.                       "option '$OPT_NAME' is already set to '$OPT_VALUE'"
  217.             continue
  218.         fi
  219.         info_mesg "Bonding interface '$IF':" \
  220.                   "Setting option '$OPT_NAME' to '$OPT_VALUE'"
  221.         if ! echo "$OPT_VALUE" > /sys/class/net/$IF/bonding/$OPT_NAME \
  222.                   2>/dev/null ; then
  223.             err_mesg "Option '$OPT_NAME' of interface '$IF' cannot be set to" \
  224.                      "'$OPT_VALUE'."
  225.             # Should we continue? Its better to fail if not requested differently
  226.             test "$NOFAIL" == 1 && continue
  227.             echo "-$IF" > /sys/class/net/bonding_masters
  228.             return 1
  229.         fi
  230.     done
  231.     return 0
  232. }
  233.  
  234. # Removes a bonding master interface
  235. # Usage: remove_bond $INTERFACE
  236. remove_bond () {
  237.     local IF=$1
  238.     if [ ! -d /sys/class/net/$IF ] ; then
  239.         return 0 # Interface does not exist; nothing to do
  240.     fi
  241.     if [ ! -d /sys/class/net/$IF/bonding ] ; then
  242.         return 1 # Interface is not a bonding master
  243.     fi
  244.     ip link set down dev $1
  245.     echo "-$IF" > /sys/class/net/bonding_masters
  246. }
  247.  
  248. get_variable () {
  249.     local line
  250.     while read line; do
  251.         eval $line
  252.     done < <(grep "^[[:space:]]*$1" ifcfg-$2 2>/dev/null)
  253. }
  254.  
  255. get_startmode () {
  256.     local STARTMODE
  257.     get_variable STARTMODE $1
  258.     echo  "$STARTMODE"
  259. }
  260.  
  261. get_slaves () {
  262.     local ret=1
  263.     for v in BONDING_SLAVE ETHERDEVICE TUNNEL_DEVICE \
  264.              TUNNEL_LOCAL_INTERFACE BRIDGE_PORTS; do
  265.         get_variable $v $1
  266.         for vv in `eval echo \$\{\!$v\*\}`; do
  267.             if [ -n "${!vv}" ] ; then
  268.                 echo -n "${!vv} "
  269.                 ret=0
  270.             fi
  271.             unset $vv
  272.         done
  273.         test $ret = 0 && return 0
  274.     done
  275.     return 1
  276. }
  277.  
  278. get_ifplugd_priority () {
  279.     unset HWD_CONFIG_0
  280.     eval `getcfg -d . -f ifcfg- "$1"`
  281.     if [ -z "$HWD_CONFIG_0" -a -r $RUN_FILES_BASE/config-$1 ] ; then
  282.         # If the interface has gone we cannot always get configuration
  283.         # name via getcfg. Therefore we use the stored one as fallback.
  284.         read HWD_CONFIG_0 x < $RUN_FILES_BASE/config-$1
  285.     fi
  286.     local IFPLUGD_PRIORITY=0
  287.     declare -i IFPLUGD_PRIORITY
  288.     get_variable IFPLUGD_PRIORITY $HWD_CONFIG_0
  289.     echo "$IFPLUGD_PRIORITY"
  290. }
  291.  
  292. # We have to write status files per interface or per configuration for at least
  293. # these reasons:
  294. # 1) remember the used configuration if getcfg cannot get it after the device
  295. #    has been unplugged
  296. # 2) store ifup options while restarting the network (e.g. the choosen provider)
  297. # 3) pass status information to smpppd to allow kinternet to show them to the
  298. #    user.
  299. # 4) control running ifup/down processes (ifdown has to stop a running ifup)
  300. # To handle this cached information, there are the *_cached_config_data
  301. # functions.
  302.  
  303. # write_cached_config_data <type> <data> <name> [PFX=<prefix>]
  304. # needs at least 3 arguments
  305. # - the type of data to write: config, options, state, ...
  306. # - the data itself
  307. # - the configuration or interface name
  308. # - the file prefix is optional and must be given in the form PFX=<prefix>
  309. #   (default prefix is 'if-'
  310. # prints nothing
  311. # You have to commit changes after writing with commit_cached_config_data()
  312. write_cached_config_data () {
  313.     touch $RUN_FILES_BASE/tmp/test 2>/dev/null || return 1
  314.     local PFX FILE TMPFILE MODFILE
  315.     test -n "$4" && eval $4
  316.     : ${PFX:=if-}
  317.     FILE=$RUN_FILES_BASE/$PFX$3
  318.     MODFILE=$RUN_FILES_BASE/tmp/$PFX$3.$$                  # MODFILE
  319.     TMPFILE=$RUN_FILES_BASE/tmp/$PFX$3.$$.tmp              # MODFILE
  320.     test -f $MODFILE || cp $FILE $MODFILE 2>/dev/null
  321.     FILE=$MODFILE                                       # MODFILE
  322.     touch $FILE
  323.     while IFS== read a b; do
  324.         case $a in
  325.             $1) ;;
  326.              *) echo "$a=$b" ;;
  327.         esac
  328.     done < <(cat $FILE) > $TMPFILE
  329.     if [ -n "$2" ] ; then
  330.         echo "$1=$2" >> $TMPFILE
  331.     fi
  332.     if [ -f $TMPFILE ] ; then
  333.         mv $TMPFILE $FILE
  334.     fi
  335. }
  336.  
  337. # INTERFACE=`read_cached_config_data <type> <name> [PFX=<prefix>]`
  338. # needs at least 2 arguments
  339. # - the type of data to read: config, options, state, ...
  340. # - the configuration or interface name
  341. # - the file prefix is optional and must be given in the form PFX=<prefix>
  342. #   (default prefix is 'if-'
  343. # prints the wanted data
  344. read_cached_config_data () {
  345.     touch $RUN_FILES_BASE/tmp/test 2>/dev/null || return 1
  346.     local PFX
  347.     test -n "$3" && eval $3
  348.     : ${PFX:=if-}
  349.     if [ -r "$RUN_FILES_BASE/$PFX$2" ] ; then
  350.         while IFS== read a b; do
  351.             case $a in
  352.                 $1) echo "$b" ;;
  353.                  *) ;;
  354.             esac
  355.         done < $RUN_FILES_BASE/$PFX$2
  356.     fi
  357. }
  358.  
  359. # delete_from_cached_config_data <type> [<data> [<name>]] [PFX=<prefix>]
  360. # Deletes an entry "$1=$2" from all config data cache files.
  361. # If there is a third argument, we delete it only from this configuration. All
  362. # handled files that are empty after modification will be deleted.
  363. # If $2 is empty then remove line $1=* from this ($3) or all configuration.
  364. # If $1 is '*' it will remove all entries.
  365. #
  366. # !!! WIP !!!
  367. # It currently works only on one file and 2nd and 3rd argument are mandatory
  368. # !!! WIP !!!
  369. #
  370. # needs at least 1 argument
  371. # - the type of data to delete: config, options, state, ...
  372. # - optional the data itself
  373. # - optional the configuration or interface name
  374. # - the file prefix is also optional and must be given in the form PFX=<prefix>
  375. #   (default prefix is 'if-'
  376. # prints nothing
  377. # You have to commit changes after deleting with commit_cached_config_data()
  378. delete_from_cached_config_data () {
  379.     touch $RUN_FILES_BASE/tmp/test 2>/dev/null || return 1
  380.     local TYPE DATA PFX FILE TMPFILE MODFILE NAME
  381.     TYPE=$1; shift
  382.     if [ "$1" = "${1#PFX}" ] ; then
  383.         DATA=$1; shift
  384.     fi
  385.     if [ "$1" = "${1#PFX}" ] ; then
  386.         NAME=$1; shift
  387.     fi
  388.     test -n "$1" && eval $1
  389.     : ${PFX:=if-}
  390.     FILE=$RUN_FILES_BASE/$PFX$NAME                 # MODFILE
  391.     MODFILE=$RUN_FILES_BASE/tmp/$PFX$NAME.$$          # MODFILE
  392.     TMPFILE=$RUN_FILES_BASE/tmp/$PFX$NAME.$$.tmp      # MODFILE
  393.     test -f $MODFILE || cp $FILE $MODFILE 2>/dev/null
  394.    FILE=$MODFILE                                       # MODFILE
  395.     touch $FILE
  396.         if [ -s "$FILE" ] ; then
  397.             while IFS== read a b; do
  398.                 case $a in
  399.                     $TYPE)
  400.                         if [ "$b" != "$DATA" -a -n "$DATA" ] ; then
  401.                             echo "$a=$b" 
  402.                         fi
  403.                         ;;
  404.                      *) echo "$a=$b" ;;
  405.                 esac
  406.             done < <(cat $FILE) > $TMPFILE
  407.         fi
  408.         if [ -f $TMPFILE ] ; then
  409.             mv $TMPFILE $FILE
  410.         fi
  411.         if [ ! -s $FILE ] ; then
  412.             rm -Rf $FILE
  413.         fi
  414. #    done   MODFILE
  415. }
  416.  
  417. # HWDESC NIX < <(grep_cached_config_data <type> <data> [PFX=<prefix>])
  418. # needs 2 arguments:
  419. # - the type of data to grep for: config, options, state, ...
  420. # - the data itself
  421. # - the file prefix is optional and must be given in the form PFX=<prefix>
  422. #   (default prefix is 'if-'
  423. # prints all matching configuration names in a single line
  424. grep_cached_config_data () {
  425.     touch $RUN_FILES_BASE/tmp/test 2>/dev/null || return 1
  426.     local PFX
  427.     test -n "$3" && eval $3
  428.     : ${PFX:=if-}
  429.     local restore_nullglob="$(shopt -p nullglob)"
  430.     shopt -s nullglob
  431.     for f in $RUN_FILES_BASE/$PFX*; do
  432.         while IFS== read a b; do
  433.             case $a in
  434.                 $1)
  435.                     if [ "$b" = "$2" ] ; then
  436.                         echo -n "${f#$RUN_FILES_BASE/$PFX} " 
  437.                     fi
  438.                     ;;
  439.             esac
  440.         done < $f
  441.     done
  442.     eval $restore_nullglob
  443.     echo
  444. }
  445.  
  446. # Writing and deleting cached config data is always done in temporary files. To
  447. # make this changes visible in the right file you must commit the changes. This
  448. # helps to make file changes atomic.
  449. commit_cached_config_data () {
  450.     touch $RUN_FILES_BASE/tmp/test 2>/dev/null || return 1
  451.     local PFX FILE MODFILE
  452.     test -n "$2" && eval $2
  453.     : ${PFX:=if-}
  454.     FILE=$RUN_FILES_BASE/$PFX$1
  455.     MODFILE=$RUN_FILES_BASE/tmp/$PFX$1.$$
  456.     if [ -f $MODFILE ] ; then
  457.         mv $MODFILE $FILE
  458.     else
  459.         rm -f $FILE
  460.     fi
  461. }
  462.  
  463. is_connected () {
  464.     case `read_cached_config_data status $1` in
  465.         connected) return 0 ;;
  466.         connecting) return 0 ;; # might be wrong, test for link to
  467.     esac
  468.     return 1
  469. }
  470.  
  471. has_link () {
  472.     case `read_cached_config_data link $1` in
  473.         yes) return 0 ;;
  474.     esac
  475.     return 1
  476. }
  477.  
  478. # This function looks for interfaces which depend on the given interface. It
  479. # prints a list with all depending interfaces. It returns 0 if there are
  480. # depending interfaces and !=0 if not.
  481. # Currently it checks only for vlan and bonding interfaces.
  482. # FIXME: Add other types of interfaces that depend on others.
  483. get_depending_ifaces() {
  484.     local VLAN_PATH BOND_PATH DEP_IFACES DEP_VLANS DEP_BONDS BASE_IFACE
  485.     VLAN_PATH="/proc/net/vlan"
  486.     BOND_PATH="/proc/net/bonding"
  487.     BASE_IFACE="$1"
  488.     DEP_IFACES=""
  489.  
  490.     if [ -z "$BASE_IFACE" ]; then
  491.         return 1
  492.     fi
  493.  
  494.     if [ -d "$VLAN_PATH" ]; then
  495.         DEP_VLANS=`cd "$VLAN_PATH"
  496.             grep -lws "Device: *$BASE_IFACE" *`
  497.         DEP_IFACES="$DEP_VLANS"
  498.     fi
  499.  
  500.     if [ -d "$BOND_PATH" ]; then
  501.         DEP_BONDS=`cd "$BOND_PATH"
  502.             grep -lws "Slave Interface: *$BASE_IFACE" *`
  503.         DEP_IFACES="$DEP_IFACES${DEP_BONDS:+ $DEP_BONDS}"
  504.     fi
  505.  
  506.     if [ -z "$DEP_IFACES" ]; then
  507.         return 1
  508.     else
  509.         echo "$DEP_IFACES"
  510.         return 0
  511.     fi
  512. }
  513.  
  514. nm_running () {
  515.     local MSG RET
  516.     test -x "$NETWORKMANAGER_BIN" || return
  517.     MSG=`checkproc $NETWORKMANAGER_BIN 2>&1`
  518.     RET=$?
  519.     info_mesg "$MSG"
  520.     return $RET
  521. }
  522.  
  523. netcontrol_running() {
  524.     test -f $NETWORK_RUNFILE
  525. }
  526.  
  527. # Since 'readlink' is located in /usr there is a quick and dirty replacement. It
  528. # is used in my_pidof.
  529. my_readlink() {
  530.    test -L $1 || return
  531.     local skip=yes
  532.     for a in `ls -l $1`; do
  533.         if [ "$skip" == yes ] ; then
  534.             test "$a" == "->" && skip=no
  535.             continue
  536.         fi
  537.         break
  538.     done
  539.     test -n "$a" || return
  540.     echo $a
  541. }
  542.  
  543. # replacement for /sbin/pidof which works with lost NFS mounts
  544. # See Bug 55370
  545. my_pidof() {
  546.     local line psout pid pids rc
  547.  
  548.     # ps itself doesn't take the full path
  549.     psout=$(ps --no-headers -C ${1##*/})
  550.     rc=$?
  551.     test "$rc" != 0 && return $rc
  552.  
  553.     echo "$psout" | while read pid line; do
  554.         # 'exe' is a link to the full path of the executable
  555.         case "$(my_readlink /proc/$pid/exe)" in 
  556.           *$1*)    echo -n "$pid "
  557.             ;; 
  558.         esac
  559.     done
  560.     echo
  561.  
  562.     # we return 0 if only matches with differing path were found
  563.     # but then the output is empty, so it is sufficient in most cases
  564.     # if the 'while read' wouldn't be in a subshell, we could set an exit code...
  565.     return $rc
  566. }
  567.  
  568.