home *** CD-ROM | disk | FTP | other *** search
- #!/bin/bash
- #
- # /sbin/hwup
- #
- # Configuring hardware (Preliminary version)
- # $Id: hwup 1518 2006-11-06 19:36:49Z zoz $
- #
-
- # /usr/bin/env
- # set -x -v
- # echo -- --------------------------------------------------------------------
-
- usage () {
- echo "Usage: hw{up,down,status} [<config>] <hwdesc> [-o <options>]"
- echo "Options are:"
- echo " auto : we were called from an automated process"
- echo " hotplug : like auto, special for hotplug (udev)"
- echo " fast : skip getcfg, works not for all subsystems"
- exit $R_USAGE
- }
-
- get_config_fast() {
- local DP
- set -- $(IFS="-"; echo $HWDESC)
- if [ "$2" = "devpath" ]; then
- HWD_BUSNAME=$1
- shift
- fi
- if [ "$1" = "devpath" ]; then
- HWD_BUSID=${2##*/}
- HWD_DEVICEPATH=${SYSFS}${2#${SYSFS}}
- DP="`cd -P $HWD_DEVICEPATH 2>/dev/null && pwd`"
- HWD_DEVICEPATH=${DP:-$HWD_DEVICEPATH}
- for cfg in hwcfg-*bus-${HWD_BUSNAME}-${HWD_BUSID}; do
- if test -f $cfg; then
- HWD_CONFIG=${cfg##hwcfg-}
- fi
- done
- return 0
- else
- return 1
- fi
- }
-
- get_config_getcfg() {
- eval `/sbin/getcfg -d . -f hwcfg- -- $HWDESC 2>/dev/null`
- # This is a workaround for getcfg that does not get a devicepath from a
- # buspath or device link.
- local devpath
- if [ -z "$HWD_DEVICEPATH" -a -n "$HWD_DEVPATH" ] ; then
- devpath=`cd -P ${SYSFS}${HWD_DEVPATH#$SYSFS}; pwd`
- if [ -d "$devpath" ] ; then
- eval `/sbin/getcfg -d . -f hwcfg- -- devpath-$devpath`
- fi
- fi
- # Normally we are interested only in the last bus. (It is not of
- # interest that below a scsi bus is a pci bus. Otherwise use
- # HWD_BUSNAME_<n>, HWD_BUSID_<n>.)
- if [ -n "$HWD_BUS_N" -a "$HWD_BUS_N" -gt 0 ] ; then
- eval export HWD_BUSNAME=\$HWD_BUSNAME_$((HWD_BUS_N-1))
- eval export HWD_BUSID=\$HWD_BUSID_$((HWD_BUS_N-1))
- fi
- HWD_CONFIG=$HWD_CONFIG_0
- }
-
- is_known_subsystem() {
- case "$1" in
- ccw) return 0 ;;
- ccwgroup) return 0 ;;
- iucv) return 0 ;;
- ide) return 0 ;;
- ieee1394) return 0 ;;
- input) return 0 ;;
- macio) return 0 ;;
- pci) return 0 ;;
- pci_express) return 0 ;;
- pcmcia) return 0 ;;
- pcmcia_socket) return 0 ;;
- platform) return 0 ;;
- pnp) return 0 ;;
- scsi) return 0 ;;
- scsi_host) return 0 ;;
- aoa-soundbus) return 0 ;;
- usb) return 0 ;;
- vio) return 0 ;;
- static) return 0 ;; # for static device configs
- *) return 1 ;;
- esac
- }
-
- get_subsystem() {
- if is_known_subsystem $SUBSYSTEM; then
- echo $SUBSYSTEM
- return 0
- fi
- set -- $(IFS="-"; echo $HWDESC)
- if is_known_subsystem $1 ; then
- echo $1
- return 0;
- fi
- test "$2" == bus && shift
- if [ "$1" == bus ] && is_known_subsystem $2; then
- echo $2
- return 0;
- fi
- local devpath
- if [ -L ${SYSFS}${DEVPATH}/bus ] ; then
- devpath=${SYSFS}${DEVPATH}
- else
- test "$2" == devpath && shift
- if [ "$1" == devpath ] ; then
- shift
- devpath="`IFS=-; echo "$*"`"
- devpath=${devpath#$SYSFS}
- fi
- fi
- if [ -L ${SYSFS}${devpath}/bus ] ; then
- local bus
- bus="`cd -P ${SYSFS}${devpath}/bus; pwd`"
- bus=${bus##*/}
- if is_known_subsystem $bus; then
- echo $bus
- return 0
- fi
- fi
- local classpath=${devpath#/class/}
- if [ "$devpath" != "$classpath" ] ; then
- classpath=${classpath%%/*}
- if is_known_subsystem $classpath; then
- echo $classpath
- return 0
- fi
- fi
- if [ -n "$CONFIG" ] ; then
- if is_known_subsystem ${CONFIG%%-*}; then
- echo ${CONFIG%%-*}
- return 0
- fi
- fi
- return 1
- }
-
- # This checks for information that should be available for all kind of
- # subsystems. If will not fail if some information is missing since the needs
- # of each subsystem differ to much. That may change in future.
- # The current implementation of this function is evil and ugly. Lets get rid of
- # getcfg soon and write a proper function. But for SL10.0 its to late. (zoz)
- get_basic_information() {
- if [ "$FAST" = yes ] ; then
- get_config_fast
- else
- get_config_getcfg
- fi
- # We need a nonempty HWD_DEVICEPATH.
- if [ -z "$HWD_DEVICEPATH" -a -n "$DEVPATH" ] ; then
- HWD_DEVICEPATH=$SYSFS$DEVPATH
- fi
- # HWD_DEVTYPE is currently only used to call special scripts. So we
- # might eliminate it and use $SUBSYSTEM instead.
- if [ -z "$HWD_DEVTYPE" ] ; then
- HWD_DEVTYPE=$SUBSYSTEM
- fi
- # We might check the following variables:
- # HWD_BUSNAME
- # HWD_BUSID
- # HWD_ID # in hwup-iucv
- }
-
- modprobe_modalias() {
- local retval
- if [ -L "$HWD_DEVICEPATH/driver" ] ; then
- info_mesg "Device already bound to a driver"
- return 0
- fi
- if [ -z "$MODALIAS" ]; then
- MODALIAS="`cat $HWD_DEVICEPATH/modalias 2>/dev/null`"
- fi
- if [ -z "$MODALIAS" ]; then
- err_mesg "No module alias available"
- return 1
- fi
- info_mesg "executing modprobe $MODALIAS"
- if [ "$LOAD_UNSUPPORTED_MODULES_AUTOMATICALLY" != yes ] ; then
- local MODPROBE_OPTS=--skip-unsupported
- fi
- if [ "$LOG_LEVEL" -lt 6 ] ; then
- modprobe -v $MODPROBE_OPTS $MODALIAS
- retval=$?
- else
- local message retval
- message="`modprobe -v $MODPROBE_OPTS $MODALIAS 2>&1`"
- retval=$?
- if [ -n "$message" ] ; then
- mesg "$message"
- elif [ "$retval" == 0 ] ; then
- info_mesg "modules already loaded:" \
- `modprobe --show-depends $MODALIAS \
- | sed 's=^.*/\(.*\).ko=\1='`
- fi
- fi
- if [ ! -L "$HWD_DEVICEPATH/driver" \
- -a -n "$HWD_BUSNAME" -a -n "$HWD_BUSID" ] ; then
- info_mesg "Device still not bound to a driver"
- if [ -e "$DRIVER_FILE" ]; then
- if [ -z "$DRIVER" ]; then
- . $DRIVER_FILE
- fi
- rm $DRIVER_FILE
- fi
- if [ -n "$DRIVER" -a "$DRIVER" != skip ] ; then
- info_mesg "Binding device to driver '$DRIVER'"
- SYSFS_DRIVER_PATH="/sys/bus/$HWD_BUSNAME/drivers/$DRIVER"
- echo -n $HWD_BUSID > $SYSFS_DRIVER_PATH/bind
- test "$DRIVER" == ipw3945 && ipw3945_start_daemon
- fi
- fi
- return $retval
- }
-
- # Driver ipw3945 needs a userspace daemon that finishes initialisation. Without
- # that daemon we don't get network interfaces.
- # ipw3945d is started via udev as soon as module ipw3945 is loaded. But if
- # someone (e.g. yast) calls hwdown and hwup the device will be unbound from the
- # driver in hwdown and then bound again in hwup. Unfortunately there are no
- # udev events if a device gets bound by a driver. So we do it ourself after
- # binding it.
- ipw3945_start_daemon() {
- info_mesg "Starting daemon ipw3945d"
- /lib/udev/ipw3945d.sh
- }
-
- R_INTERNAL=1 # internal error, e.g. no config or missing scripts
- cd /etc/sysconfig/hardware || exit $R_INTERNAL
- test -f ./config && . ./config
- test -f scripts/functions && . scripts/functions || exit $R_INTERNAL
-
- ######################################################################
- # Commandline parsing
- #
- # hw{up,down,status} [<config>] <hwdesc> [-o <options>]
- SCRIPTNAME=${0##*/}
- info_mesg $*
- HWDESC=$1
- case "$HWDESC" in ""|-h|*help*) usage; esac
- shift
- if [ -n "$1" -a "$1" != "-o" ] ; then
- CONFIG=$HWDESC
- HWDESC=$1
- fi
- shift
- test "$1" = "-o" && shift
- OPTIONS=$@
- MODE=manual
- HOTPLUG=no
- while [ $# -gt 0 ]; do
- case $1 in
- auto) MODE=auto ;;
- hotplug) MODE=auto
- HOTPLUG=yes ;;
- fast) FAST=yes;;
- *) info_mesg "unknown option $1 ignored" ;;
- esac
- shift
- done
-
-
- ######################################################################
- # Determine subsystem
- #
- SUBSYSTEM=`get_subsystem`
- if [ $? != 0 ] ; then
- err_mesg "Cannot handle subsystem '$SUBSYSTEM'"
- exit $R_USAGE
- fi
- test -r ./scripts/functions.$SUBSYSTEM && . ./scripts/functions.$SUBSYSTEM
-
-
- ######################################################################
- # Now check if basic information is available. At first that info common to all
- # subsystems. Then we can call the specific helper for the subsystem.
- get_basic_information
- if [ $? != 0 ] ; then
- err_mesg "Cannot get basic information"
- return $R_USAGE # FIXME add R_NO_INFO to functions.common
- fi
- if [ "`type -t get_${SUBSYSTEM}_information`" == function ] ; then
- get_${SUBSYSTEM}_information
- if [ $? != 0 ] ; then
- err_mesg "Cannot get specific information for '$SUBSYSTEM'"
- return $R_USAGE # FIXME add R_NO_INFO to functions.common
- fi
- fi
- DRIVER_FILE=$RUN_FILES_BASE/driver-$HWD_BUSNAME-$HWD_BUSID
-
-
- ######################################################################
- # Get the right configuration file
- if [ -z "$CONFIG" -a -n "$HWD_CONFIG" ] ; then
- CONFIG="$HWD_CONFIG"
- fi
- # This should go to get_static_information
- if [ -z "$CONFIG" ] ; then
- case ${HWDESC%%-*} in
- static|boot) CONFIG=$HWDESC;;
- esac
- fi
- info_mesg "HWDESC='$HWDESC'"
- info_mesg "CONFIG='$CONFIG'"
-
-
- ######################################################################
- # Now source the configuration file
- #
- # First remove all variables starting with MODULE because there are variables
- # starting with MODULE and unknown suffix in the config file. Otherwise
- # environment variables would irritate the code that looks for all MODULE*
- # variables.
- unset ${!MODULE*}
- if [ -n "$CONFIG" -a -r "./hwcfg-$CONFIG" ] ; then
- . "./hwcfg-$CONFIG"
- fi
- if [ "$LOG_LEVEL" -ge 6 ] ; then
- info_mesg ------------------------------------------------------------
- for var in MODE HOTPLUG SUBSYSTEM MODALIAS \
- ${!HWD_*} ${!MODULE*} ${!STARTMODE*} \
- ${!SCRIPTUP_*} ${!SCRIPTDOWN_*} ${!PRE_*} ${!POST_*}; do
- info_mesg ${var}=${!var}
- done
- if [ "`type -t show_${SUBSYSTEM}_information`" == function ] ; then
- show_${SUBSYSTEM}_information
- fi
- info_mesg ------------------------------------------------------------
- fi
-
-
- ######################################################################
- # What shell we do if there is no configuration data?
- # - fail
- # - get it automatically
- # - ask the user
- if [ "$SCRIPTNAME" = hwup -a \
- \( -z "$CONFIG" -o ! -r "hwcfg-$CONFIG" -o -n "$NODATA" \) ] ; then
- # test "$HOTPLUG" != yes && \
- # err_mesg "No configuration found for $HWDESC"
- # exit $R_NOCONFIG
- if [ "`type -t pre_init_${SUBSYSTEM}`" == function ] ; then
- info_mesg calling pre_init_${SUBSYSTEM}
- pre_init_${SUBSYSTEM}
- fi
- modprobe_modalias
- if [ "`type -t post_init_${SUBSYSTEM}`" == function ] ; then
- info_mesg calling post_init_${SUBSYSTEM}
- post_init_${SUBSYSTEM}
- fi
- exit 0
- fi
-
-
- ######################################################################
- # Check if we are supposed to initialize the device
- #
- # empty $STARTMODE means 'auto'
- case "$STARTMODE" in
- off)
- mesg "$SCRIPTNAME: used configuration has STARTMODE=$STARTMODE."
- exit 0;
- ;;
- manual)
- if [ "$MODE" != manual ] ; then
- mesg "$SCRIPTNAME: used configuration has" \
- "STARTMODE=$STARTMODE, but we are called '$MODE'."
- exit 0;
- fi
- ;;
- esac
-
- ######################################################################
- # execute individual prestart or predown scripts if available
- #
- if [ "$SCRIPTNAME" = hwup ] ; then
- # NOTE: 'eval echo' in the next line is necessary to expand settings
- # like PRE_UP_SCRIPT="~root/bin/foo"
- for PUS in `eval echo $PRE_UP_SCRIPT scripts/$PRE_UP_SCRIPT`; do
- if [ -x "$PUS" -a ! -d "$PUS" ] ; then
- info_mesg "executing additional start script $PUS" \
- "'$CONFIG' $HWDESC ${OPTIONS:+-o $OPTIONS}"
- $PUS "$CONFIG" $HWDESC ${OPTIONS:+-o $OPTIONS}
- fi
- done
- fi
- if [ "$SCRIPTNAME" = hwdown ] ; then
- # NOTE: 'eval echo' in the next line is necessary to expand settings
- # like PRE_DOWN_SCRIPT="~root/bin/foo"
- for PDS in `eval echo $PRE_DOWN_SCRIPT scripts/$PRE_DOWN_SCRIPT`; do
- if [ -x "$PDS" -a ! -d "$PDS" ] ; then
- info_mesg "executing additional stop script $PDS" \
- "'$CONFIG' $HWDESC ${OPTIONS:+-o $OPTIONS}"
- $PDS "$CONFIG" $HWDESC ${OPTIONS:+-o $OPTIONS}
- fi
- done
- fi
-
- ######################################################################
- # Call a specialized down script, depending on the event
- #
- # have a look at 'Call a specialized down script' above
- if [ "$SCRIPTNAME" = hwdown ]; then
- # Call an event-specific script if one exists
- if [ "$HWD_DEVTYPE" ]; then
- SCRIPT_DOWN=`eval echo \\$SCRIPTDOWN_$HWD_DEVTYPE`
- fi
- # Call a generic script if no event-specific exists
- if [ -z "$SCRIPT_DOWN" ]; then
- SCRIPT_DOWN=`eval echo \\$SCRIPTDOWN`
- fi
- if test -n "$SCRIPT_DOWN" && test -x "./scripts/$SCRIPT_DOWN" ; then
- info_mesg "Calling scripts/$SCRIPT_DOWN '$CONFIG'" \
- "$HWDESC ${OPTIONS:+-o $OPTIONS}"
- ./scripts/$SCRIPT_DOWN "$CONFIG" $HWDESC ${OPTIONS:+-o $OPTIONS}
- fi
- fi
-
-
- ######################################################################
- # Call subsystem specific pre_intialisation function if there is one
- #
- if [ "`type -t pre_init_${SUBSYSTEM}`" == function ] ; then
- info_mesg calling pre_init_${SUBSYSTEM}
- pre_init_${SUBSYSTEM}
- fi
-
-
- ######################################################################
- # Load all modules
- #
- declare -i M=0 N=0
- for MODVAR in ${!MODULE*}; do
- : MODVAR=$MODVAR
- # There is a silly design bug: $MODULE_OPTIONS and $MODULE_UNLOAD
- # must not be interpreted as additional MODULE*
- case "$MODVAR" in
- MODULE_OPTIONS*|MODULE_UNLOAD*) continue ;;
- esac
- INDEX=${MODVAR#MODULE}
-
- eval ML[$M]=\$MODULE$INDEX
- eval test -z "\${ML[$M]}" && continue
- eval MO[$M]=\$MODULE_OPTIONS$INDEX
- eval MU[$M]=\${MODULE_UNLOAD$INDEX:-$MODULE_UNLOAD}
- : $((M++))
- done
-
- if [ "$SCRIPTNAME" = hwup ] ; then
- while [ $N -lt $M ] ; do
- if [ -d /sys/module/${ML[$N]} ] ; then
- mesg "hwup: module '${ML[$N]}' already present in kernel"
- : $((N++))
- continue
- fi
- if [ -d /sys/bus/$HWD_BUSNAME/drivers/${ML[$N]} ] ; then
- mesg "hwup: driver '${ML[$N]}' already present in kernel"
- : $((N++))
- continue
- fi
-
- mesg "hwup: Loading module '${ML[$N]}'" \
- "${MO[$N]:+with options '${MO[$N]}' }" \
- "for device '$HWDESC'"
- /sbin/modprobe ${ML[$N]} ${MO[$N]}
- # we exit here if we cannot modprobe the module
- test $? != 0 && exit 1
- : $((N++))
- done
- fi
-
- # Check if we should/can (un)bind devices
- # ccw devices are often grouped. We had to (un)bind all or not at all.
- case "$HWD_BUSNAME" in
- ccw|"") NOBIND=yes ;;
- esac
- test -z "$HWD_BUSID" && NOBIND=yes
- if [ "$DRIVER" == skip ] ; then
- info_mesg "Binding/Releasing device '$HWD_BUSID' skipped (DRIVER==skip)"
- NOBIND=yes
- fi
-
- if [ "$SCRIPTNAME" = hwup -a "$NOBIND" != yes ] ; then
- # we need to get the driver's name here, so we do the following:
- # 1) if DRIVER exists in config file, we use it
- # 2) else we iterate the module list, and use the first usable drivername
- # 3) else we check if we saved the driver during hwdown and use it
-
- if [ -z "$DRIVER" ]; then
- N=0
- # 2)
- while [ $N -lt $M -a -z "$DRIVER" ] ; do
- ls -d /sys/bus/$HWD_BUSNAME/drivers/${ML[$N]} &>/dev/null
- if [ $? = 0 ]; then
- DRIVER=${ML[$N]}
- fi
- : $((N++))
- done
-
- # 3)
- if [ -e "$DRIVER_FILE" ]; then
- if [ -z "$DRIVER" ]; then
- . $DRIVER_FILE
- fi
- rm $DRIVER_FILE
- fi
- fi
-
- if [ -n "$DRIVER" ]; then
- SYSFS_DRIVER_PATH="/sys/bus/$HWD_BUSNAME/drivers/$DRIVER"
- if [ -L $SYSFS_DRIVER_PATH/$HWD_BUSID ] ; then
- info_mesg "Device '$HWD_BUSID' is already bound to driver '$DRIVER'"
- else
- mesg "hwup: binding device $HWD_BUSID to driver $DRIVER."
- echo -n $HWD_BUSID > $SYSFS_DRIVER_PATH/bind
- test "$DRIVER" == ipw3945 && ipw3945_start_daemon
- fi
- else
- info_mesg "hwup error: could not get driver name"
- fi
- fi
-
- if [ "$SCRIPTNAME" = hwdown -a "$HOTPLUG" != yes -a "$NOBIND" != yes ] ; then
-
- SYSFS_DRIVER_PATH=`ls -d /sys/bus/$HWD_BUSNAME/drivers/*/$HWD_BUSID 2>/dev/null`
- SYSFS_DRIVER_PATH=${SYSFS_DRIVER_PATH%/$HWD_BUSID}
-
- if [ -n "$SYSFS_DRIVER_PATH" ]; then
- # unbind the device from the module
- mesg "hwup: unbinding device $HWD_BUSID from driver $HWD_DRIVER."
- echo -n $HWD_BUSID > $SYSFS_DRIVER_PATH/unbind
- # save driver name
- echo "DRIVER=$HWD_DRIVER" > $DRIVER_FILE
- else
- info_mesg "hwup: unbinding device $HWD_BUSID failed."
- fi
-
- fi
-
- if [ "$SCRIPTNAME" = hwstatus ] ; then
- SYSFS_DRIVER_PATH=`ls -d /sys/bus/$HWD_BUSNAME/drivers/*/$HWD_BUSID \
- 2>/dev/null`
- SYSFS_DRIVER_PATH=${SYSFS_DRIVER_PATH%/$HWD_BUSID}
- SYSFS_MODULE_PATH=$(cd $SYSFS_DRIVER_PATH 2>/dev/null &&
- cd module 2>/dev/null; pwd -P)
- SYSFS_MODULE=${SYSFS_MODULE_PATH##*/}
- echo DRIVER=${SYSFS_DRIVER_PATH##*/}
- if lsmod | grep -qs "\<$SYSFS_MODULE\>"; then
- echo MODULE=${SYSFS_MODULE}
- fi
- : # to be implemented
- fi
-
-
- ######################################################################
- # Call subsystem specific post_intialisation function if there is one
- #
- if [ "`type -t post_init_${SUBSYSTEM}`" == function ] ; then
- info_mesg calling post_init_${SUBSYSTEM}
- post_init_${SUBSYSTEM}
- fi
-
-
- ######################################################################
- # Call a specialized up script, depending on the event
- #
- # have a look at 'Call a specialized down script' above
- if [ "$SCRIPTNAME" = hwup ]; then
- # Call an event-specific script if one exists
- if [ "$HWD_DEVTYPE" ]; then
- SCRIPT_UP=`eval echo \\$SCRIPTUP_$HWD_DEVTYPE`
- fi
- # Call a generic script if no event-specific exists
- if [ -z "$SCRIPT_UP" ]; then
- SCRIPT_UP=`eval echo \\$SCRIPTUP`
- fi
- if test -n "$SCRIPT_UP" && test -x "./scripts/$SCRIPT_UP" ; then
- info_mesg "Calling scripts/$SCRIPT_UP '$CONFIG'" \
- "$HWDESC ${OPTIONS:+-o $OPTIONS}"
- ./scripts/$SCRIPT_UP "$CONFIG" $HWDESC ${OPTIONS:+-o $OPTIONS}
- fi
- fi
-
- ######################################################################
- # execute individual poststart or postdown scripts if available
- #
- if [ "$SCRIPTNAME" = hwup ] ; then
- # NOTE: 'eval echo' in the next line is necessary to expand settings
- # like POST_UP_SCRIPT="~root/bin/foo"
- for PUS in `eval echo $POST_UP_SCRIPT scripts/$POST_UP_SCRIPT`; do
- if [ -x "$PUS" -a ! -d "$PUS" ] ; then
- info_mesg "executing additional start script $PUS" \
- "'$CONFIG' $HWDESC ${OPTIONS:+-o $OPTIONS}"
- $PUS "$CONFIG" $HWDESC ${OPTIONS:+-o $OPTIONS}
- fi
- done
- fi
- if [ "$SCRIPTNAME" = hwdown ] ; then
- # NOTE: 'eval echo' in the next line is necessary to expand settings
- # like POST_DOWN_SCRIPT="~root/bin/foo"
- for PDS in `eval echo $POST_DOWN_SCRIPT scripts/$POST_DOWN_SCRIPT`; do
- if [ -x "$PDS" -a ! -d "$PDS" ] ; then
- info_mesg "executing additional stop script $PDS" \
- "'$CONFIG' $HWDESC ${OPTIONS:+-o $OPTIONS}"
- $PDS "$CONFIG" $HWDESC ${OPTIONS:+-o $OPTIONS}
- fi
- done
- fi
-