New build path variable
[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 #
47 #  Figure out what arguments to pass tail
48 #
49 tail="tail -n "
50 echo foo | ${tail}1 > /dev/null 2>&1
51 if test "$?" != "0"
52 then
53     tail="tail -"
54 fi
55
56 RADIUSD=$sbindir/${name}
57 RADDBDIR=${sysconfdir}/raddb
58
59 #
60 #  If you want to send email, define this field to be an email address.
61 #  This part of the functionality hasn't been well tested, so please
62 #  test it before putting it into production.
63 #
64 #  It also presumes that you have a functioning mail system on
65 #  the maching running RADIUS.  You will need to check that the
66 #  "mail" command exists, and sends mail to the address below, e.g.:
67 #
68 #     echo test | mail -s "Testing" $MAILTO
69 #
70 #  If you receive the message, then enable MAILTO.  Otherwise, fix
71 #  your mail system so that it delivers mail.
72 #
73 MAILTO=
74
75 #
76 #  Allow "radiusd_safe -X" for testing the radiusd_safe functionality.
77 #
78 ARGS="$@"
79
80 test -f $RADIUSD || exit 0
81 test -f $RADDBDIR/radiusd.conf || exit 0
82
83 ulimit -c unlimited
84
85 #
86 #  See if the PID file exists.  It might have been left over after
87 #  a crash, or it might be because the RADIUS server is still running.
88 #
89 if test -f $pid_file
90 then
91     PID=`cat $pid_file`
92     #
93     #  Check if the process exists, AND if it has the right name
94     #
95     if ps -p $PID | grep $name > /dev/null
96     then
97         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
98         echo "A $name process already exists"
99         exit 1
100     fi
101     
102     #
103     #  A RADIUS server doesn't exist.  Delete the stale PID file.
104     #
105     rm -f $pid_file
106     if test -f $pid_file
107     then
108         echo "`date +'%a %b %e %H:%M:%S %Y'` : Fatal: Cannot remove the pid file: $pid_file" >> $log_file
109         echo "Fatal error: Cannot remove the pid file: $pid_file"
110         echo "Please remove it manually and start $0 again"
111         echo "$name daemon not started"
112         exit 1
113     fi
114 fi
115
116 started=0
117 restarts=0
118 last_email=0
119 now=0
120
121 #
122 #  Save our PID.
123 #
124 echo $$ > ${rundir}/${name}_safe.pid
125
126 #
127 #  Loop forever, or until we're told to exit via a signal.
128 #
129 while :
130 do
131     #
132     #  The first time around, just start the server.
133     #  After that, see if we are re-starting in the same second
134     #  as the last time.  If so, sleep for a second.  Otherwise,
135     #  if we're not starting in the same second, then just restart
136     #  the server.
137     #
138     #  This helps prevent CPU spikes when something goes catastrophically
139     #  wrong, and the server re-starts continuously.  (e.g. disk full, etc.)
140     #
141     now_s=`date +'%a %b %e %H:%M:%S %Y'`
142     if test "$started" != "0"
143     then
144         #  Send mail when the server starts
145         if test "$MAILTO" != ""
146         then
147             # don't print minutes and seconds: cheap way
148             # of sending email only once an hour.
149             now=`date +'%a %b %e %H %Y'`
150             restarts=`expr $restarts + 1`
151
152             # send email the first time it restarts
153             if test "$last_email" = "0"
154             then
155                     cat |  mail -s "ERROR - $name died, restarting.." $MAILTO <<EOF
156 $name has restarted unexpectedly at $now
157
158 See $log_file for details.  Last 20 lines are:
159
160 ----------------------------------------------------------------------
161 `${tail}20 $log_file`
162 EOF
163                 last_email="$now"
164                 restarts=0
165             else
166                 #  Send email only once every hour (or so)
167                 if test "$now" != "$last_email"
168                 then
169                     cat |  mail -s "ERROR - $name died, restarting.." $MAILTO <<EOF
170 $name has restarted $restarts times since last email at $last_email
171
172 See $log_file for details.  Last 100 lines are:
173
174 ----------------------------------------------------------------------
175 `${tail}100 $log_file`
176 EOF
177                     last_email="$now"
178                     restarts=0
179                 fi
180             fi
181         fi
182
183         if test "$started" = "$now_s"
184         then
185             #  Allow us to be killed
186             trap - HUP INT QUIT TERM TSTP
187             sleep 1
188         fi
189     fi
190     started="$now_s"
191
192     mysig=
193     trap 'mysig=1' HUP
194     trap 'mysig=2' INT
195     trap 'mysig=3' QUIT
196     trap 'mysig=15' TERM
197     trap 'mysig=18' TSTP
198
199     eval "$RADIUSD -f $ARGS < /dev/null >> $log_file 2>&1 &"
200     PID=$!
201     
202     if test "$?" != "0"
203     then
204         echo "Failed to start $name.  See $log_file for details"
205         echo "$name daemon not started"
206         exit 1
207     fi
208
209     echo $PID > $pid_file
210
211     #
212     #  Wait for the process to exit.
213     #
214     wait $PID
215     code=$?
216
217     #
218     #  On *BSD and Linux, sending *us* a signal results in "wait" returning
219     #  with 128+sig.  On Solaris, it results in "wait" returning with "0".
220     #
221     #  If this happens, we reset our expectations here so that the code
222     #  below will work correctly.
223     #
224     if test "$code" = "0"
225     then
226         if test "$mysig" != ""
227         then
228             code=`expr $mysig + 128`
229         fi
230     fi
231
232     case "$code" in
233         0)
234             echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited normally.  Exiting" | tee -a $log_file
235             break
236             ;;
237
238         127)
239             echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited unexpectedly.  Restarting it." | tee -a $log_file
240             ;;
241
242         *)
243             #
244             #  The server exited of its own accord.
245             #
246             if test "$code" -lt 128
247             then
248                 echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited unexpectedly on exit code $code.  Restarting it." | tee -a $log_file
249             else
250                 sig=`expr $code - 128`
251
252                 #
253                 #  Was the signal sent to us, or to the child process?
254                 #
255                 if test "$mysig" != ""
256                 then
257                     echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: Caught signal $sig: Signalling $name to exit." | tee -a $log_file
258                     kill -$sig $PID
259                     break
260                 else
261                     echo "`date +'%a %b %e %H:%M:%S %Y'` : Info: $name exited unexpectedly on signal $sig.  Restarting it." | tee -a $log_file
262                 fi
263             fi
264             ;;
265     esac
266 done
267
268 rm -f $pid_file ${rundir}/${name}_safe.pid
269 exit 0