Make fancontrol more rebust against kernel driver changes (bnc#529483). --- lm_sensors-3.1.1.orig/prog/pwm/fancontrol (révision 5743) +++ lm_sensors-3.1.1/prog/pwm/fancontrol (copie de travail) @@ -3,12 +3,12 @@ # Simple script implementing a temperature dependent fan speed control # Supported Linux kernel versions: 2.6.5 and later # -# Version 0.68 +# Version 0.70 # # Usage: fancontrol [CONFIGFILE] # # Dependencies: -# bash, egrep, sed, cut, sleep, lm_sensors :) +# bash, egrep, sed, cut, sleep, readlink, lm_sensors :) # # Please send any questions, comments or success stories to # marius.reiner@hdev.de @@ -55,6 +55,8 @@ # grep configuration from file INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'` + DEVPATH=`egrep '^DEVPATH=.*$' $1 | sed -e 's/DEVPATH= *//g'` + DEVNAME=`egrep '^DEVNAME=.*$' $1 | sed -e 's/DEVNAME= *//g'` FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'` MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'` MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'` @@ -152,6 +154,108 @@ echo } +function DevicePath() +{ + if [ -h "$1/device" ] + then + readlink -f "$1/device" | sed -e 's/^\/sys\///' + fi +} + +function DeviceName() +{ + if [ -r "$1/name" ] + then + cat "$1/name" | sed -e 's/[[:space:]=]/_/g' + elif [ -r "$1/device/name" ] + then + cat "$1/device/name" | sed -e 's/[[:space:]=]/_/g' + fi +} + +function ValidateDevices() +{ + local OLD_DEVPATH="$1" OLD_DEVNAME="$2" outdated=0 + local entry device name path + + for entry in $OLD_DEVPATH + do + device=`echo "$entry" | sed -e 's/=[^=]*$//'` + path=`echo "$entry" | sed -e 's/^[^=]*=//'` + + if [ "`DevicePath "$device"`" != "$path" ] + then + echo "Device path of $device has changed" + outdated=1 + fi + done + + for entry in $OLD_DEVNAME + do + device=`echo "$entry" | sed -e 's/=[^=]*$//'` + name=`echo "$entry" | sed -e 's/^[^=]*=//'` + + if [ "`DeviceName "$device"`" != "$name" ] + then + echo "Device name of $device has changed" + outdated=1 + fi + done + + return $outdated +} + +# Check that all referenced sysfs files exist +function CheckFiles { + local outdated=0 + + let fcvcount=0 + while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs + do + pwmo=${AFCPWM[$fcvcount]} + if [ ! -w $pwmo ] + then + echo "Error: file $pwmo doesn't exist" + outdated=1 + fi + let fcvcount=$fcvcount+1 + done + + let fcvcount=0 + while (( $fcvcount < ${#AFCTEMP[@]} )) # go through all temp inputs + do + tsen=${AFCTEMP[$fcvcount]} + if [ ! -r $tsen ] + then + echo "Error: file $tsen doesn't exist" + outdated=1 + fi + let fcvcount=$fcvcount+1 + done + + let fcvcount=0 + while (( $fcvcount < ${#AFCFAN[@]} )) # go through all fan inputs + do + fan=${AFCFAN[$fcvcount]} + if [ ! -r $fan ] + then + echo "Error: file $fan doesn't exist" + outdated=1 + fi + let fcvcount=$fcvcount+1 + done + + if [ $outdated -eq 1 ] + then + echo + echo "At least one referenced file is missing. Either some required kernel" + echo "modules haven't been loaded, or your configuration file is outdated." + echo "In the latter case, you should run pwmconfig again." + fi + + return $outdated +} + if [ -f "$1" ] then LoadConfig $1 @@ -166,8 +270,12 @@ elif echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]' then DIR=/sys/class/hwmon +elif echo "${AFCPWM[0]}" | egrep -q '^[1-9]*[0-9]-[0-9abcdef]{4}' +then + DIR=/sys/bus/i2c/devices else - DIR=/sys/bus/i2c/devices + echo "$0: Invalid path to sensors" + exit 1 fi if [ ! -d $DIR ] @@ -177,6 +285,19 @@ fi cd $DIR +# Check for configuration change +if [ -z "$DEVPATH" -o -z "$DEVNAME" ] +then + echo "Configuration is too old, please run pwmconfig again" + exit 1 +fi +if ! ValidateDevices "$DEVPATH" "$DEVNAME" +then + echo "Configuration appears to be outdated, please run pwmconfig again" + exit 1 +fi +CheckFiles || exit 1 + if [ -f "$PIDFILE" ] then echo "File $PIDFILE exists, is fancontrol already running?" --- lm_sensors-3.1.1.orig/prog/pwm/pwmconfig (révision 5743) +++ lm_sensors-3.1.1/prog/pwm/pwmconfig (copie de travail) @@ -42,6 +42,12 @@ exit 1 fi +if [ "`id -u`" != "0" ] +then + echo "You need to be root to run this script." + exit 1 +fi + echo "# pwmconfig revision $REVISION ($REVDATE)" echo 'This program will search your sensors for pulse width modulation (pwm)' echo 'controls, and test each one to see if it controls a fan on' @@ -258,7 +264,7 @@ GOODPWM="$GOODPWM $i" fi else - NOTROOT=1 + echo "Can't write to $i, skipping." fi done @@ -302,13 +308,6 @@ exit 1 fi -if [ "$NOTROOT" = "1" ] -then - echo 'As you are not root, we cannot write the PWM settings.' - echo 'Please run as root to continue.' - exit 1 -fi - echo 'Warning!!! This program will stop your fans, one at a time,' echo "for approximately $DELAY seconds each!!!" echo 'This may cause your processor temperature to rise!!!' @@ -540,6 +539,57 @@ exit 1 fi +function DevicePath() +{ + if [ -h "$1/device" ] + then + readlink -f "$1/device" | sed -e 's/^\/sys\///' + fi +} + +function DeviceName() +{ + if [ -r "$1/name" ] + then + cat "$1/name" | sed -e 's/[[:space:]=]/_/g' + elif [ -r "$1/device/name" ] + then + cat "$1/device/name" | sed -e 's/[[:space:]=]/_/g' + fi +} + +function ValidateDevices() +{ + local OLD_DEVPATH="$1" OLD_DEVNAME="$2" outdated=0 + local entry device name path + + for entry in $OLD_DEVPATH + do + device=`echo "$entry" | sed -e 's/=[^=]*$//'` + path=`echo "$entry" | sed -e 's/^[^=]*=//'` + + if [ "`DevicePath "$device"`" != "$path" ] + then + echo "Device path of $device has changed" + outdated=1 + fi + done + + for entry in $OLD_DEVNAME + do + device=`echo "$entry" | sed -e 's/=[^=]*$//'` + name=`echo "$entry" | sed -e 's/^[^=]*=//'` + + if [ "`DeviceName "$device"`" != "$name" ] + then + echo "Device name of $device has changed" + outdated=1 + fi + done + + return $outdated +} + function AskPath() { echo -n 'What should be the path to your fancontrol config file (/etc/fancontrol)? ' @@ -567,6 +617,8 @@ function LoadConfig() { + local OLD_DEVPATH OLD_DEVNAME + # Nothing to do if [ ! -f "$1" ] then @@ -576,6 +628,8 @@ echo "Loading configuration from $1 ..." INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL= *//g'` + OLD_DEVPATH=`egrep '^DEVPATH=.*$' $1 | sed -e 's/DEVPATH= *//g'` + OLD_DEVNAME=`egrep '^DEVNAME=.*$' $1 | sed -e 's/DEVNAME= *//g'` FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS= *//g'` FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS= *//g'` MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP= *//g'` @@ -586,16 +640,12 @@ MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM= *//g'` # Check for configuration change - local item - for item in $FCFANS - do - if [ ! -f "`echo $item | sed -e 's/=.*$//'`" ] - then - echo "Configuration appears to be outdated, discarded" - ClearConfig - return 0 - fi - done + if ! ValidateDevices "$OLD_DEVPATH" "$OLD_DEVNAME" + then + echo "Configuration appears to be outdated, discarded" + ClearConfig + return 0 + fi } LoadConfig $FCCONFIG @@ -676,14 +726,74 @@ echo "OK, using $fanval" } +# Remember the path and name of each device with at least one +# reference (pwm, temp or fan) in the configuration file. +# This function sets globals DEVPATH and DEVNAME as a side effect. +function RememberDevices() +{ + local used entry device name path tempfandev pwmdev + DEVPATH="" + DEVNAME="" + + for device in $DEVICES + do + device=`echo "$device" | sed -e 's/\/.*$//'` + + used=0 + for entry in $1 $2 + do + pwmdev=`echo "$entry" | sed -e 's/\/.*$//'` + tempfandev=`echo "$entry" | sed -e 's/^[^=]*=//' -e 's/\/.*$//'` + + if [ "$device" = "$pwmdev" -o "$device" = "$tempfandev" ] + then + used=1 + fi + done + if [ "$used" -eq 0 ] + then + continue + fi + + # Record the device path and name. This lets the fancontrol + # script check that they didn't change. If they did, then the + # configuration file can no longer be trusted. + path=`DevicePath "$device"` + if [ -z "$DEVPATH" ] + then + DEVPATH="$device=$path" + else + DEVPATH="$DEVPATH $device=$path" + fi + + name=`DeviceName "$device"` + if [ -z "$DEVNAME" ] + then + DEVNAME="$device=$name" + else + DEVNAME="$DEVNAME $device=$name" + fi + done +} + function SaveConfig() { + RememberDevices "$FCTEMPS" "$FCFANS" + echo echo "Saving configuration to $FCCONFIG..." tmpfile=`mktemp -t pwmcfg.XXXXXXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1; } trap " [ -f \"$tmpfile\" ] && /bin/rm -f -- \"$tmpfile\"" 0 1 2 3 13 15 echo "# Configuration file generated by pwmconfig, changes will be lost" >$tmpfile - echo -e "INTERVAL=$INTERVAL\nFCTEMPS=$FCTEMPS\nFCFANS=$FCFANS\nMINTEMP=$MINTEMP\nMAXTEMP=$MAXTEMP\nMINSTART=$MINSTART\nMINSTOP=$MINSTOP" >>$tmpfile + echo "INTERVAL=$INTERVAL" >>$tmpfile + echo "DEVPATH=$DEVPATH" >>$tmpfile + echo "DEVNAME=$DEVNAME" >>$tmpfile + echo "FCTEMPS=$FCTEMPS" >>$tmpfile + echo "FCFANS=$FCFANS" >>$tmpfile + echo "MINTEMP=$MINTEMP" >>$tmpfile + echo "MAXTEMP=$MAXTEMP" >>$tmpfile + echo "MINSTART=$MINSTART" >>$tmpfile + echo "MINSTOP=$MINSTOP" >>$tmpfile [ -n "$MINPWM" ] && echo "MINPWM=$MINPWM" >>$tmpfile [ -n "$MAXPWM" ] && echo "MAXPWM=$MAXPWM" >>$tmpfile mv $tmpfile $FCCONFIG --- lm_sensors-3.1.1.orig/prog/pwm/fancontrol.8 (révision 5743) +++ lm_sensors-3.1.1/prog/pwm/fancontrol.8 (copie de travail) @@ -1,4 +1,4 @@ -.TH FANCONTROL 8 "January 2009" "lm-sensors 3" +.TH FANCONTROL 8 "September 2009" "lm-sensors 3" .SH NAME fancontrol \- automated software based fan speed regulation @@ -38,13 +38,21 @@ This variable defines at which interval in seconds the main loop of \fBfancontrol\fP will be executed .TP +.B DEVPATH +Maps hwmon class devices to physical devices. This lets \fBfancontrol\fP +check that the configuration file is still up-to-date. +.TP +.B DEVNAME +Records hwmon class device names. This lets \fBfancontrol\fP check that +the configuration file is still up-to-date. +.TP .B FCTEMPS Maps PWM outputs to temperature sensors so \fBfancontrol\fP knows which temperature sensors should be used for calculation of new values for the corresponding PWM outputs. .TP .B FCFANS -FCFANS records the association between a PWM and a fan. +Records the association between a PWM output and a fan input. Then \fBfancontrol\fP can check the fan speed and restart it if it stops unexpectedly. .TP @@ -92,6 +100,12 @@ setup I recommend using the \fBpwmconfig\fP script. Small changes can be made by editing the config file directly following the rules above. +Upon starting, fancontrol will make sure that all referenced devices +do exist and match what they were at configuration time, and that all +referenced sysfs files do exist. If not, it will quit immediately, upon +the assumption that the configuration file may be out-of-sync with the +loaded kernel drivers. + .SH THE ALGORITHM \fBfancontrol\fP first reads its configuration, writes it to arrays and loops its