[tpwd] Fix segfault when exactly one argument given
[tinyapps.git] / check.sh
blobfa1855caccd95e23f333bb14f1ced4225514c269
1 #!/bin/sh
2 ##
3 ## Pings specified host and runs specified program if no responding
4 ## Copyright (c) 2005-2008 by Michal Nazarewicz (mina86/AT/mina86.com)
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 3 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
19 ## This is part of Tiny Applications Collection
20 ## -> http://tinyapps.sourceforge.net/
24 ## I use it to shut down my PC when my brother shuts down his PC which
25 ## is a router. It may be also used to run a reconnect script when
26 ## connection is loast. It can be also used to monitor another PC and
27 ## send (let say) SMS when it goes down.
31 ## Version
33 version () {
34 echo 'Check v0.2 (c) 2005,2006 by MichaƂ Nazarewicz'
35 echo
40 ## Usage
42 usage () {
43 cat <<EOF
44 usage: check.sh [ <options> ] [ [--] <action> [ <arg> ... ] ]
45 <options> are:
46 -h --help Displays help screen and exits
47 -H --long-help Displays long help screen and exits
48 -V --version Displays vesion and exits
49 -q --quiet Displays less messages
50 -r --retry=<count> Runs <action> after <count> failed checkings [10]
51 -i --interval=<int> Waits <int> seconds betwenn each checking [10]
52 -c --check=<check> Runs <check> to check [check_ping www.google.com]
53 -k --keep-going Restarts after running action [no]
54 -t --trap=<trpap> Executes <trap> when signal is trapped [exit 0]
55 -T --ignore-sig Ignores signals [no]
57 Single letter options may not be given as one argument (eg. -kTq).
59 <action> Program to be run when check faileds [exit]
60 <arg> ... Arguments to the <action> [1]
62 EOF
63 if [ "X$1" != "Xlong" ]; then return 0; fi
64 cat <<EOF
66 <check> must exit with 0 exit code if check succeeded or non-zero otherwise.
67 Script contains the fallowing built-in check functions:
68 check_ping <host> -- checks if <host> answers to ping
69 check_proc_load <proc> <load> -- checks if <proc>'s CPU load is below <load>
70 (<load> must be an integer betwen 1 and 100)
71 check_proc <proc> -- checks if <proc> is running
72 Each built-in function has also an alias with the first c letter removed.
74 The script exports variables CHECK_QUIET (empty if false, y if true),
75 CHECK_INGORESIG (empty if false, y if true), (in case of <action>)
76 CHECK_EXIT_CODE (exit code of <check>) and CHECK_TMP (path to a temporary
77 file) which both <check> and <action> should take into account.
79 Examples:
81 ./check.sh '-check_proc_load X 95' -k -- killall X -q &
82 Kills X each time it uses more then 95% of CPU for 5 minutes. Usefull
83 when executed from system start scripts since it keeps running silently in
84 the background.
86 ./check.sh || /sbin/halt
87 Halts computer if www.google.com stops responding to pings (most likely
88 connection was lsot). May be canceled with Ctrl+C.
90 ./check.sh '-check_proc foo' -k -q -r100 -i1 -- /path/to/foo' &
91 Checks whether foo is runing and if not executes it. Useful when executed
92 from system start scripts since it keeps running silently in the
93 background.
95 EOF
100 ## Init variables
102 umask 077
103 SLEEP=10
104 RETRY=10
106 KEEPGOING=
107 CHECK_QUIET=
108 CHECK_IGNORESIG=
109 export CHECK_QUIET CHECK_IGNORESIG
110 TRAPCMD="exit 0"
111 CMD="check_ping www.google.com"
115 ## Parse arguments
117 while [ $# -ne 0 ]; do
118 case "$1" in
119 -h|--help) version; usage ; exit 0; ;;
120 -H|--long-help) version; usage long; exit 0; ;;
121 -V|--version) version; exit 0; ;;
123 -q|--quiet) CHECK_QUIET=yes ; ;;
124 -k|--keep-going) KEEPGOING=yes ; ;;
125 -T|--ignore-sig) CHECK_IGNORESIG=y; ;;
127 -r|--retry) RETRY=$2 ; shift; ;;
128 -i|--interval) SLEEP=$2 ; shift; ;;
129 -c|--count) CMD=$2 ; shift; ;;
130 -t|--trap) TRAPCMD=$2; shift; ;;
132 -r*) RETRY=${1#-?} ; ;; (--retry=*) RETRY=${1#-*=} ; ;;
133 -i*) SLEEP=${1#-?} ; ;; (--interval=*) SLEEP=${1#-*=} ; ;;
134 -c*) CMD=${1#-?} ; ;; (--check=*) CMD=${1#-*=} ; ;;
135 -t*) TRAPCMD=${1#-?}; ;; (--trap=*) TRAPCMD=${1#-*=}; ;;
137 --) shift; break; ;;
138 -*) echo Unknown option: "$1"; exit 1; ;;
139 *) break; ;;
140 esac
141 shift
142 done
143 [ $# -eq 0 ] && set -- exit 1
146 [ -n "$CHECK_QUIET" ] || version
150 ## Check arguments
152 if [ "$RETRY" -lt 1 ]; then
153 echo '<count> must be integer >= 1'
154 exit 2;
156 if [ "$SLEEP" -lt 1 ]; then
157 echo '<interval> must be integer >= 1'
158 exit 2;
163 ## Checking function
165 check_ping () {
166 ping -c 1 "$1" 2>/dev/null >"$CHECK_TMP" || return 1
167 [ -n "$CHECK_QUIET" ] || head -n 2 "$CHECK_TMP" |tail -n 1
168 return 0
170 heck_ping () { check_ping "$@"; }
172 check_proc_load () {
173 LOAD="$(ps -o %cpu -C "$1" |tail -n+2)"
174 if [ ! "$LOAD" ]; then
175 [ -n "$CHECK_QUIET" ] || printf '%s: not running\n' "$1"
176 return 0
178 [ -n "$CHECK_QUIET" ] || printf '%s: CPU Load %5s%%\n' "$1" "$LOAD"
180 [ "${LOAD%%.*}" -lt "$2" ]
182 heck_proc_load () { check_proc_load "$@"; }
184 check_proc () {
185 if [ -z "$__CHECK_PROC_PKILL_PRESENT" ]; then
186 which pkill >/dev/null 2>&1
187 __CHECK_PROC_PKILL_PRESENT=$?
190 if [ $__CHECK_PROC_PKILL_PRESENT -eq 0 ]; then
191 if ! pkill -0 "^$1\$"; then return 1; fi
192 elif ! ps -C "$1" >/dev/null 2>/dev/null; then
193 return 1
196 if [ -n "$CHECK_QUIET" ]; then return 0; fi
197 case "$__CHECK_PROC_GLOBAL_VAR" in
198 (1) printf '%s: running (/)\r' "$1"; __CHECK_PROC_GLOBAL_VAR=2; ;;
199 (2) printf '%s: running (-)\r' "$1"; __CHECK_PROC_GLOBAL_VAR=3; ;;
200 (3) printf '%s: running (\\)\r' "$1"; __CHECK_PROC_GLOBAL_VAR=0; ;;
201 (*) printf '%s: running (|)\r' "$1"; __CHECK_PROC_GLOBAL_VAR=1; ;;
202 esac
203 return 0
205 heck_proc () { check_proc "$@"; }
209 ## Temporary file
212 # Find temp dir
213 CHECK_TMP=.
214 for N in "$TMPDIR" "$TMP" "$TEMP" ~/tmp /tmp; do
215 if [ -n "$N" ] && [ -d "$N" ] && [ -w "$N" ]; then
216 CHECK_TMP="$N"
217 break
219 done
221 # tempfile exists
222 if which mktemp >/dev/null 2>&1; then
223 export CHECK_TMP=$(mktemp "$CHECK_TMP/check-XXXXXXXX")
224 elif which tempfile >/dev/null 2>&1; then
225 export CHECK_TMP=$(tempfile -d "$CHECK_TMP" -p "check-")
226 else
227 echo unable to create temporary file, mktemp or tempfile required >&2
228 exit 0
231 trap '[ -f "$CHECK_TMP" ] && rm -f -- "$CHECK_TMP"' 0
235 ## Signals
237 catch_sig () {
238 if [ -n "$CHECK_IGNORESIG" ] || [ "X$1" = XUSR1 ] ||
239 [ "X$1" = XUSR2 ] || [ "X$1" = XALRM ]; then
240 [ -n "$CHECK_QUIET" ] || echo "Got SIG$1; ignoring..."
241 return 0
244 [ -n "$CHECK_QUIET" ] || echo "Got SIG$1"
245 $TRAPCMD
248 for e in HUP INT QUIT ABRT SEGV PIPE ALRM TERM USR1 USR2; do
249 # shellcheck disable=SC2064
250 trap "catch_sig $e" "$e"
251 done
256 ## Loop
258 count=0
259 while :; do
260 ## OK
261 if $CMD; then
262 count=0
263 sleep "$SLEEP"
264 continue
267 ## Not OK
268 export CHECK_EXIT_CODE=$?
269 count=$(( count + 1 ))
270 [ -n "$CHECK_QUIET" ] || printf " !!! %3d / %3d\r" "$count" "$RETRY"
272 ## Limit reached
273 if [ "$count" -ge "$RETRY" ]; then
274 [ -n "$CHECK_QUIET" ] || echo ' !!! Checking failed.'
275 [ -f "$CHECK_TMP" ] && rm -f -- "$CHECK_TMP"
276 "$@"
277 [ -n "$KEEPGOING" ] || exit 0;
278 count=0
281 sleep "$SLEEP"
282 done