4724a14aacfc88a47119bf3dfd916f19b2271406
[freeradius.git] / scripts / radwatch.in
1 #!/bin/sh
2 ######################################################################
3 #
4 #    This program is free software; you can redistribute it and/or modify
5 #    it under the terms of the GNU General Public License as published by
6 #    the Free Software Foundation; either version 2 of the License, or
7 #    (at your option) any later version.
8 #
9 #    This program is distributed in the hope that it will be useful,
10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #    GNU General Public License for more details.
13 #
14 #    You should have received a copy of the GNU General Public License
15 #    along with this program; if not, write to the Free Software
16 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 #
18 #    Copyright (C) 2009 Network RADIUS SARL <info@networkradius.com>
19 #
20 ######################################################################
21 #
22 # radwatch - Start the radius daemon and restart upon crash.
23 #
24 #  It also catches signals sent to it, and then re-sends those signals
25 #  to the radius server it is watching.
26 #
27 #  If you want to watch and re-start the server, we recommend
28 #  reading the file doc/supervise-radiusd.txt
29
30 #
31 #  This simplifies the script, and avoids most issues with (say)
32 #  Debian re-naming "radiusd" to "freeradius".
33 #
34 name=radiusd
35
36 prefix=@prefix@
37 exec_prefix=@exec_prefix@
38 sbindir=@sbindir@
39 localstatedir=@localstatedir@
40 logdir=@logdir@
41 rundir=${localstatedir}/run/${name}
42 sysconfdir=@sysconfdir@
43 pid_file=${rundir}/${name}.pid
44 log_file=${logdir}/${name}_safe.log
45
46 RADIUSD=$sbindir/${name}
47 RADDBDIR=${sysconfdir}/raddb
48
49 #
50 #  If you want to send email, define this field to be an email address.
51 #  This part of the functionality hasn't been well tested, so please
52 #  test it before putting it into production.
53 #
54 #  It also presumes that you have a functioning mail system on
55 #  the maching running RADIUS.  You will need to check that the
56 #  "mail" command exists, and sends mail to the address below, e.g.:
57 #
58 #     echo test | mail -s "Testing" $MAILTO
59 #
60 #  If you receive the message, then enable MAILTO.  Otherwise, fix
61 #  your mail system so that it delivers mail.
62 #
63 MAILTO=
64
65 #
66 #  Allow "radiusd_safe -X" for testing the radiusd_safe functionality.
67 #
68 ARGS="$@"
69
70 test -f $RADIUSD || exit 0
71 test -f $RADDBDIR/radiusd.conf || exit 0
72
73 ulimit -c unlimited
74
75 #
76 #  See if the PID file exists.  It might have been left over after
77 #  a crash, or it might be because the RADIUS server is still running.
78 #
79 if test -f $pid_file
80 then
81     PID=`cat $pid_file`
82     #
83     #  Check if the process exists, AND if it has the right name
84     #
85     if ps -p $PID | grep $name > /dev/null
86     then
87         echo "`date +'%a %b %e %H:%M:%S %Y'` : Fatal: A $name process already exists at PID $PID.  We cannot start another one." >> $log_file
88         echo "A $name process already exists"
89         exit 1
90     fi
91     
92     #
93     #  A RADIUS server doesn't exist.  Delete the stale PID file.
94     #
95     rm -f $pid_file
96     if test -f $pid_file
97     then
98         echo "`date +'%a %b %e %H:%M:%S %Y'` : Fatal: Cannot remove the pid file: $pid_file" >> $log_file
99         echo "Fatal error: Cannot remove the pid file: $pid_file"
100         echo "Please remove it manually and start $0 again"
101         echo "$name daemon not started"
102         exit 1
103     fi
104 fi
105
106 started=0
107 restarts=0
108 last_email=0
109
110 #
111 #  Loop forever, or until we're told to exit via a signal.
112 #
113 while :
114 do
115     mysig=
116     trap 'mysig=1' HUP
117     trap 'mysig=2' INT
118     trap 'mysig=3' QUIT
119     trap 'mysig=15' TERM
120     trap 'mysig=18' TSTP
121
122     #
123     #  The first time around, just start the server.
124     #  After that, see if we are re-starting in the same second
125     #  as the last time.  If so, sleep for a second.  Otherwise,
126     #  if we're not starting in the same second, then just restart
127     #  the server.
128     #
129     #  This helps prevent CPU spikes when something goes catastrophically
130     #  wrong, and the server re-starts continuously.  (e.g. disk full, etc.)
131     #
132     if test "$started" != "0"
133     then
134         #  Send mail when the server starts
135         if test "$MAILTO" != ""
136         then
137             now=`date +"%s"`
138             restarts=`expr $restarts + 1`
139
140             # send email the first time it restarts
141             if test "$last_email" = "0"
142             then
143                     cat |  mail -s "ERROR - $name died, restarting.." $MAILTO <<EOF
144 $name has restarted unexpectedly at $now
145
146 See $log_file for details.  Last 20 lines are:
147
148 ----------------------------------------------------------------------
149 `tail -n 20 $log_file`
150 EOF
151                 $last_email="$now"
152                 restarts=0
153             else
154                 #  Send email only once every hour.
155                 if test "$now" -gt `expr $last_email + 3600`
156                 then
157                     cat |  mail -s "ERROR - $name died, restarting.." $MAILTO <<EOF
158 $name has restarted $restarts times since last email at $last_email
159
160 See $log_file for details.  Last 100 lines are:
161
162 ----------------------------------------------------------------------
163 `tail -n 100 $log_file`
164 EOF
165                     $last_email="$now"
166                     restarts=0
167                 fi
168             fi
169         fi
170
171         if test "$started" = `date +"%s"`
172         then
173             sleep 1
174         fi
175     fi
176     started=`date +"%s"`
177
178     eval "$RADIUSD -f $ARGS < /dev/null >> $log_file 2>&1 &"
179     PID=$!
180     
181     if test "$?" != "0"
182     then
183         echo "Failed to start $name.  See $log_file for details"
184         echo "$name daemon not started"
185         exit 1
186     fi
187
188     echo $PID > $pid_file
189
190     #
191     #  Wait for the process to exit.
192     #
193     wait $PID
194     code=$?
195
196     #
197     #  On *BSD and Linux, sending *us* a signal results in "wait" returning
198     #  with 128+sig.  On Solaris, it results in "wait" returning with "0".
199     #
200     #  If this happens, we reset our expectations here so that the code
201     #  below will work correctly.
202     #
203     if test "$code" = "0"
204     then
205         if "$mysig" != ""
206         then
207             code=`expr $mysig + 128`
208         fi
209     fi
210
211     case "$code" in
212         0)
213             echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited normally.  Exiting" | tee -a $log_file
214             break
215             ;;
216
217         127)
218             echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited unexpectedly.  Restarting it." | tee -a $log_file
219             ;;
220
221         *)
222             #
223             #  The server exited of its own accord.
224             #
225             if test "$code" -lt 128
226             then
227                 echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited unexpectedly on exit code $code.  Restarting it." | tee -a $log_file
228             else
229                 sig=`expr $code - 128`
230
231                 #
232                 #  Was the signal sent to us, or to the child process?
233                 #
234                 if test "$mysig" = "yes"
235                 then
236                     echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: Caught signal $sig: Signalling $name to exit." | tee -a $log_file
237                     kill -`expr $code - 128` $PID
238                     break
239                 else
240                     echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited unexpectedly on signal $sig.  Restarting it." | tee -a $log_file
241                 fi
242             fi
243             ;;
244     esac
245 done
246
247 rm -f $pid_file
248 exit 0