home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
boot
/
i386
/
rescue
/
sbin
/
hwup
< prev
next >
Wrap
Text File
|
2006-11-29
|
18KB
|
613 lines
#!/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