1: #!/bin/bash
2:
3: # canardien 0.0.6
4: # (c) 2005-2021 under GPL by Adrian Zaugg
5:
6:
7: # canardien [<host> [<host> ...]]
8:
9: # canardiens pings a machine, originally ente.limmat.ch thus its name,
10: # to determine wether she is gone diving.
11:
12:
13: ## Settings
14: #
15:
16: # Hosts to ping. use a space separated list for multiple targets. All
17: # hosts of the list are checked and their results reported individually.
18: # Hosts given on the command line overwrite this setting.
19: HOSTS=""
20:
21: # eMail Alerts
22: # Send alert email messages to the following address(es). Leave empty
23: # for no alert. For multiple destinations use a comma separated list.
24: ALERT_TO="root"
25:
26: # Subject of alert email
27: ALERT_SUBJECT='"Attention: no answer from $HOST anymore!"'
28:
29: # Text of Message (Put variables in 'single quotes' to protect them. They
30: # should get expanded at the time the message is sent!)
31: ALERT_TEXT='"\n[$TIME_STAMP]\n\nALERT!!\n\n\t$HOST is down!\n\nYou should probably do something, please.\n\nKind regards, $PINGHOST."'
32:
33: # Path to fping
34: PING=""
35:
36: # Answer of fping to reachable hosts
37: ALIVE_ANSWER="is alive"
38:
39: # Max number of pakets to send before giving up. Time increases exponentially,
40: # use a number < 7.
41: RETRIES=5
42:
43: # Temporary file path
44: TMPDIR="/tmp"
45:
46: # This hosts name
47: PINGHOST="$(uname -n)"
48:
49: # Set to an empty string to avoid debug output,
50: # to "low" for a few, output and to anything else
51: # for verbose output
52: DEBUG=verbose
53:
54: # For silent (non-error) operation set to anything,
55: # comment out to enable text output
56: #SILENT=shshsh
57:
58:
59: # -----------functions-----------
60:
61: # Initialize.
62: function init() {
63:
64: # check fping existence
65: if [ -z "$PING" ]; then
66: PING="$(which fping)"
67: fi
68: if [ ${#PING} -eq 0 ]; then
69: echo "Error: fping external program not found or not set. Exitting." >&2
70: exit 1
71: fi
72: if [ ! -x "$PING" ]; then
73: echo "Error: Can't execute the program set to use as fping. Please enter the correct path to \"fping\"." >&2
74: exit 1
75: fi
76:
77: # get hostset
78: if [ -n "$*" ]; then
79: HOSTS="$*"
80: fi
81:
82: # remove multiple spaces and trim
83: HOSTS="$(echo "$HOSTS" | sed -e "s/ \{1,\}/ /g" -e "s/^ //" -e "s/ $//")"
84:
85: if [ -z "$HOSTS" ]; then
86: echo "Error: No host to ping." >&2
87: exit 1
88: fi
89: }
90:
91:
92: # If a host responds to pings, it is considered up.
93: function checkconnection() {
94:
95: unset UP
96:
97: # ping host
98: PING_ANSWER="$($PING -R -B 2 -r $RETRIES -p 50 "$HOST" 2>&1)"
99: PING_ERRNUM=$?
100: if [ $PING_ERRNUM -gt 2 ]; then
101: echo "Error: Got error $PING_ERRNUM from fping $(head -1 "$PING_ANSWER"). Disregarding $HOST." >&2
102: continue;
103: fi
104:
105: # parse answer
106: if [ $(echo "$PING_ANSWER" | grep -c "$ALIVE_ANSWER") -gt 0 ]; then
107: UP=true
108: fi
109: TIME_STAMP="$(date +"%a %e.%m.%y %H:%M:%S")"
110: if [ -n "$UP" ]; then
111: if [ ! "$DEBUG" = "low" ] && [ -n "$DEBUG" ]; then
112: shout "The connection to $HOST is up."
113: fi
114: else
115: if [ -n "$DEBUG" ]; then
116: shout "The connection to $HOST is down."
117: fi
118: fi
119:
120: # remember a hosts state
121: rememberstate
122: }
123:
124:
125: # Rember recent state of host, trigger alert
126: function rememberstate() {
127: # Put a simple time stamp in a tmp file, when host is detected as down for the first time
128: if [ -z "$UP" ]; then
129: if [ ! -e "$TMPDIR/.canardien-$PINGHOST-$HOST" ]; then
130: # set time stamp
131: echo -ne "$TIME_STAMP" > "$TMPDIR/.canardien-$PINGHOST-$HOST"
132: # send alert
133: sendalert
134: elif [ -n "$DEBUG" ]; then
135: shout "Down since `cat $TMPDIR/.canardien-$PINGHOST-$HOST`."
136: fi
137: else
138: # Host is up
139: if [ -e "$TMPDIR/.canardien-$PINGHOST-$HOST" ]; then
140: if [ -n "$DEBUG" ]; then
141: shout "$HOST is up again."
142: fi
143: # send alert
144: ALERT_SUBJECT='"The host $HOST answers again!"'
145: ALERT_TEXT='"[$(date +"%a %e.%m.%y %H:%M:%S")]\n\n\n$HOST is up again.\n--------------------------------------\n(downtime began $(cat "$TMPDIR/.canardien-$PINGHOST-$HOST"))\n\n\n Kind regards, $PINGHOST."'
146: sendalert
147: # delete tmp file
148: rm "$TMPDIR/.canardien-$PINGHOST-$HOST"
149: else
150: # still running
151: if [ ! "$DEBUG" = "low" ] && [ -n "$DEBUG" ]; then
152: shout "$HOST is up."
153: fi
154: fi
155: fi
156: }
157:
158:
159: # Send an email alert
160: function sendalert() {
161: # send mail
162: if [ ! -z "$ALERT_TO" ]; then
163: eval alert_subject=\$$ALERT_SUBJECT
164: eval MSG=\$$ALERT_TEXT
165: echo -e -n "$MSG" | mail -s "$alert_subject" "$ALERT_TO"
166: if [ -n "$DEBUG" ]; then
167: shout "Alert sent to $ALERT_TO."
168: fi
169: fi
170: }
171:
172:
173: # To avoid any output in case of a silent operation,
174: # shout instead of echo.
175: function shout() {
176: if [ -z "$SILENT" ]; then
177: echo -e "$1"
178: fi
179: }
180:
181:
182: # -----------main-----------
183:
184: init "$*"
185:
186: # call an instance for each host, when multiple hosts are given
187: if [[ "$HOSTS" =~ " " ]]; then
188: while read -r HOST; do
189: "$0" "$HOST" &
190: done <<< "$(echo "$HOSTS" | tr ' ' '\n')"
191: exit 0
192: else
193: # process a single host
194: HOST="$HOSTS"
195: checkconnection
196: fi
197:
198: exit 0
199:
200: # todo: Switches ( -q, --debug, ...)
201: # grace period: do not send a mail if down time shorter than X minutes
202: # repeat down info after x hours
203: # test port instead of ping or in addition
204:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>