root/lm-sensors/trunk/prog/pwm/fancontrol @ 5668

Revision 5668, 9.2 KB (checked in by khali, 4 years ago)

Create pid file only after successful initialization.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/bin/bash
2#
3# Simple script implementing a temperature dependent fan speed control
4# Supported Linux kernel versions: 2.6.5 and later
5#
6# Version 0.68
7#
8# Usage: fancontrol [CONFIGFILE]
9#
10# Dependencies:
11#   bash, egrep, sed, cut, sleep, lm_sensors :)
12#
13# Please send any questions, comments or success stories to
14# marius.reiner@hdev.de
15# Thanks!
16#
17# For configuration instructions and warnings please see fancontrol.txt, which
18# can be found in the doc/ directory or at the website mentioned above.
19#
20#
21#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
22#    Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
23#
24#    This program is free software; you can redistribute it and/or modify
25#    it under the terms of the GNU General Public License as published by
26#    the Free Software Foundation; either version 2 of the License, or
27#    (at your option) any later version.
28#
29#    This program is distributed in the hope that it will be useful,
30#    but WITHOUT ANY WARRANTY; without even the implied warranty of
31#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32#    GNU General Public License for more details.
33#
34#    You should have received a copy of the GNU General Public License
35#    along with this program; if not, write to the Free Software
36#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37#    MA 02110-1301 USA.
38#
39#
40
41PIDFILE="/var/run/fancontrol.pid"
42
43#DEBUG=1
44MAX=255
45
46declare -i pwmval
47
48function LoadConfig {
49        echo "Loading configuration from $1 ..."
50        if [ ! -r "$1" ]
51        then
52                echo "Error: Can't read configuration file"
53                exit 1
54        fi
55
56        # grep configuration from file
57        INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
58        FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
59        MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
60        MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
61        MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
62        MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
63        # optional settings:
64        FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
65        MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
66        MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
67
68        # Check whether all mandatory settings are set
69        if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
70        then
71                echo "Some mandatory settings missing, please check your config file!"
72                exit 1
73        fi
74        if [ "$INTERVAL" -le 0 ]
75        then
76                echo "Error in configuration file:"
77                echo "INTERVAL must be at least 1"
78                exit 1
79        fi
80
81        # write settings to arrays for easier use and print them
82        echo
83        echo "Common settings:"
84        echo "  INTERVAL=$INTERVAL"
85
86        let fcvcount=0
87        for fcv in $FCTEMPS
88        do
89                if ! echo $fcv | egrep -q '='
90                then
91                        echo "Error in configuration file:"
92                        echo "FCTEMPS value is improperly formatted"
93                        exit 1
94                fi
95
96                AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
97                AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
98                AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
99                AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
100                AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
101                AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
102                AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
103                AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
104                [ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
105                AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
106                [ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
107
108                # verify the validity of the settings
109                if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
110                then
111                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
112                        echo "MINTEMP must be less than MAXTEMP"
113                        exit 1
114                fi
115                if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
116                then
117                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
118                        echo "MAXPWM must be at most 255"
119                        exit 1
120                fi
121                if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
122                then
123                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
124                        echo "MINSTOP must be less than MAXPWM"
125                        exit 1
126                fi
127                if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
128                then
129                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
130                        echo "MINSTOP must be greater than or equal to MINPWM"
131                        exit 1
132                fi
133                if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
134                then
135                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
136                        echo "MINPWM must be at least 0"
137                        exit 1
138                fi
139
140                echo
141                echo "Settings for ${AFCPWM[$fcvcount]}:"
142                echo "  Depends on ${AFCTEMP[$fcvcount]}"
143                echo "  Controls ${AFCFAN[$fcvcount]}"
144                echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
145                echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
146                echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
147                echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
148                echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
149                echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
150                let fcvcount=fcvcount+1
151        done
152        echo
153}
154
155if [ -f "$1" ]
156then
157        LoadConfig $1
158else
159        LoadConfig /etc/fancontrol
160fi
161
162# Detect if config file uses the hwmon class or not yet
163if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
164then
165        DIR=/sys/class/hwmon
166else
167        DIR=/sys/bus/i2c/devices
168fi
169
170if [ ! -d $DIR ]
171then
172        echo $0: 'No sensors found! (did you load the necessary modules?)'
173        exit 1
174fi
175cd $DIR
176
177if [ -f "$PIDFILE" ]
178then
179        echo "File $PIDFILE exists, is fancontrol already running?"
180        exit 1
181fi
182echo $$ > "$PIDFILE"
183
184# $1 = pwm file name
185function pwmdisable()
186{
187        ENABLE=${1}_enable
188        # No enable file? Just set to max
189        if [ ! -f $ENABLE ]
190        then
191                echo $MAX > $1
192                return 0
193        fi
194
195        # Try pwmN_enable=0
196        echo 0 > $ENABLE 2> /dev/null
197        if [ `cat $ENABLE` -eq 0 ]
198        then
199                # Success
200                return 0
201        fi
202
203        # It didn't work, try pwmN_enable=1 pwmN=255
204        echo 1 > $ENABLE 2> /dev/null
205        echo $MAX > $1
206        if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
207        then
208                # Success
209                return 0
210        fi
211
212        # Nothing worked
213        echo "$ENABLE stuck to" `cat $ENABLE` >&2
214        return 1
215}
216
217# $1 = pwm file name
218function pwmenable()
219{
220        ENABLE=${1}_enable
221        if [ -f $ENABLE ]
222        then
223                echo 1 > $ENABLE 2> /dev/null
224                if [ $? -ne 0 ]
225                then
226                        return 1
227                fi
228        fi
229        echo $MAX > $1
230}
231
232function restorefans()
233{
234        local status=$1
235        echo 'Aborting, restoring fans...'
236        let fcvcount=0
237        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
238        do
239                pwmo=${AFCPWM[$fcvcount]}
240                pwmdisable $pwmo
241                let fcvcount=$fcvcount+1
242        done
243        echo 'Verify fans have returned to full speed'
244        rm -f "$PIDFILE"
245        exit $status
246}
247
248trap 'restorefans 0' SIGQUIT SIGTERM
249trap 'restorefans 1' SIGHUP SIGINT
250
251# main function
252function UpdateFanSpeeds {
253        let fcvcount=0
254        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
255        do
256                #hopefully shorter vars will improve readability:
257                pwmo=${AFCPWM[$fcvcount]}
258                tsens=${AFCTEMP[$fcvcount]}
259                fan=${AFCFAN[$fcvcount]}
260                let mint="${AFCMINTEMP[$fcvcount]}*1000"
261                let maxt="${AFCMAXTEMP[$fcvcount]}*1000"
262                minsa=${AFCMINSTART[$fcvcount]}
263                minso=${AFCMINSTOP[$fcvcount]}
264                minpwm=${AFCMINPWM[$fcvcount]}
265                maxpwm=${AFCMAXPWM[$fcvcount]}
266
267                read tval < ${tsens}
268                if [ $? -ne 0 ]
269                then
270                        echo "Error reading temperature from $DIR/$tsens"
271                        restorefans 1
272                fi
273
274                read pwmpval < ${pwmo}
275                if [ $? -ne 0 ]
276                then
277                        echo "Error reading PWM value from $DIR/$pwmo"
278                        restorefans 1
279                fi
280
281                # If fanspeed-sensor output shall be used, do it
282                if [[ -n ${fan} ]]
283                then
284                        read fanval < ${fan}
285                        if [ $? -ne 0 ]
286                        then
287                                echo "Error reading Fan value from $DIR/$fan"
288                                restorefans 1
289                        fi
290                else
291                        fanval=1  # set it to a non zero value, so the rest of the script still works
292                fi
293
294                # debug info
295                if [ "$DEBUG" != "" ]
296                then
297                        echo "pwmo=$pwmo"
298                        echo "tsens=$tsens"
299                        echo "fan=$fan"
300                        echo "mint=$mint"
301                        echo "maxt=$maxt"
302                        echo "minsa=$minsa"
303                        echo "minso=$minso"
304                        echo "minpwm=$minpwm"
305                        echo "maxpwm=$maxpwm"
306                        echo "tval=$tval"
307                        echo "pwmpval=$pwmpval"
308                        echo "fanval=$fanval"
309                fi
310
311                if (( $tval <= $mint ))
312                  then pwmval=$minpwm # below min temp, use defined min pwm
313                elif (( $tval >= $maxt ))
314                  then pwmval=$maxpwm # over max temp, use defined max pwm
315                else
316                  # calculate the new value from temperature and settings
317                  pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}"
318                  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
319                  then # if fan was stopped start it using a safe value
320                        echo $minsa > $pwmo
321                        # Sleep while still handling signals
322                        sleep 1 &
323                        wait $!
324                  fi
325                fi
326                echo $pwmval > $pwmo # write new value to pwm output
327                if [ $? -ne 0 ]
328                then
329                        echo "Error writing PWM value to $DIR/$pwmo"
330                        restorefans 1
331                fi
332                if [ "$DEBUG" != "" ]
333                then
334                        echo "new pwmval=$pwmval"
335                fi
336                let fcvcount=$fcvcount+1
337        done
338}
339
340echo 'Enabling PWM on fans...'
341let fcvcount=0
342while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
343do
344        pwmo=${AFCPWM[$fcvcount]}
345        pwmenable $pwmo
346        if [ $? -ne 0 ]
347        then
348                echo "Error enabling PWM on $DIR/$pwmo"
349                restorefans 1
350        fi
351        let fcvcount=$fcvcount+1
352done
353
354echo 'Starting automatic fan control...'
355
356# main loop calling the main function at specified intervals
357while true
358do
359        UpdateFanSpeeds
360        # Sleep while still handling signals
361        sleep $INTERVAL &
362        wait $!
363done
Note: See TracBrowser for help on using the browser.