]> git.proxmox.com Git - mirror_frr.git/blob - tools/frrcommon.sh.in
Merge pull request #4885 from satheeshkarra/pim_mlag
[mirror_frr.git] / tools / frrcommon.sh.in
1 #!/bin/bash
2 #
3 # This is a "library" of sorts for use by the other FRR shell scripts. It
4 # has most of the daemon start/stop logic, but expects the following shell
5 # functions/commands to be provided by the "calling" script:
6 #
7 # log_success_msg
8 # log_warning_msg
9 # log_failure_msg
10 #
11 # (coincidentally, these are LSB standard functions.)
12 #
13 # Sourcing this file in a shell script will load FRR config variables but
14 # not perform any action. Note there is an "exit 1" if the main config
15 # file does not exist.
16 #
17 # This script should be installed in @CFG_SBIN@/frrcommon.sh
18
19 PATH=/bin:/usr/bin:/sbin:/usr/sbin
20 D_PATH="@CFG_SBIN@" # /usr/lib/frr
21 C_PATH="@CFG_SYSCONF@" # /etc/frr
22 V_PATH="@CFG_STATE@" # /var/run/frr
23 VTYSH="@vtysh_bin@" # /usr/bin/vtysh
24 FRR_USER="@enable_user@" # frr
25 FRR_GROUP="@enable_group@" # frr
26 FRR_VTY_GROUP="@enable_vty_group@" # frrvty
27
28 # ORDER MATTERS FOR $DAEMONS!
29 # - keep zebra first
30 # - watchfrr does NOT belong in this list
31
32 DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd"
33 RELOAD_SCRIPT="$D_PATH/frr-reload.py"
34
35 #
36 # general helpers
37 #
38
39 debug() {
40 [ -n "$watchfrr_debug" ] || return 0
41
42 printf '%s %s(%s):' "`date +%Y-%m-%dT%H:%M:%S.%N`" "$0" $$ >&2
43 # this is to show how arguments are split regarding whitespace & co.
44 # (e.g. for use with `debug "message" "$@"`)
45 while [ $# -gt 0 ]; do
46 printf ' "%s"' "$1" >&2
47 shift
48 done
49 printf '\n' >&2
50 }
51
52 chownfrr() {
53 [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
54 [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
55 }
56
57 vtysh_b () {
58 [ "$1" = "watchfrr" ] && return 0
59 [ -r "$C_PATH/frr.conf" ] || return 0
60 if [ -n "$1" ]; then
61 "$VTYSH" -b -n -d "$1"
62 else
63 "$VTYSH" -b -n
64 fi
65 }
66
67 daemon_inst() {
68 # note this sets global variables ($dmninst, $daemon, $inst)
69 dmninst="$1"
70 daemon="${dmninst%-*}"
71 inst=""
72 [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}"
73 }
74
75 daemon_list() {
76 # note $1 and $2 specify names for global variables to be set
77 local enabled disabled evar dvar
78 enabled=""
79 disabled=""
80 evar="$1"
81 dvar="$2"
82
83 for daemon in $DAEMONS; do
84 eval cfg=\$$daemon
85 eval inst=\$${daemon}_instances
86 [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes
87 if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
88 if ! daemon_prep "$daemon" "$inst"; then
89 continue
90 fi
91 debug "$daemon enabled"
92 enabled="$enabled $daemon"
93 if [ -n "$inst" ]; then
94 debug "$daemon multi-instance $inst"
95 oldifs="${IFS}"
96 IFS="${IFS},"
97 for i in $inst; do
98 enabled="$enabled $daemon-$i"
99 done
100 IFS="${oldifs}"
101 fi
102 else
103 debug "$daemon disabled"
104 disabled="$disabled $daemon"
105 fi
106 done
107
108 enabled="${enabled# }"
109 disabled="${disabled# }"
110 [ -z "$evar" ] && echo "$enabled"
111 [ -n "$evar" ] && eval $evar="\"$enabled\""
112 [ -n "$dvar" ] && eval $dvar="\"$disabled\""
113 }
114
115 #
116 # individual daemon management
117 #
118
119 daemon_prep() {
120 local daemon inst cfg
121 daemon="$1"
122 inst="$2"
123 [ "$daemon" = "watchfrr" ] && return 0
124 [ -x "$D_PATH/$daemon" ] || {
125 log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed"
126 return 1
127 }
128 [ -r "$C_PATH/frr.conf" ] && return 0
129
130 cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
131 if [ ! -r "$cfg" ]; then
132 touch "$cfg"
133 chownfrr "$cfg"
134 fi
135 return 0
136 }
137
138 daemon_start() {
139 local dmninst daemon inst args instopt wrap bin
140 daemon_inst "$1"
141
142 ulimit -n $MAX_FDS > /dev/null 2> /dev/null
143 daemon_prep "$daemon" "$inst" || return 1
144 if test ! -d "$V_PATH"; then
145 mkdir -p "$V_PATH"
146 chown frr "$V_PATH"
147 fi
148
149 eval wrap="\$${daemon}_wrap"
150 bin="$D_PATH/$daemon"
151 instopt="${inst:+-n $inst}"
152 eval args="\$${daemon}_options"
153
154 if eval "$all_wrap $wrap $bin -d $instopt $args"; then
155 log_success_msg "Started $dmninst"
156 vtysh_b "$daemon"
157 else
158 log_failure_msg "Failed to start $dmninst!"
159 fi
160 }
161
162 daemon_stop() {
163 local dmninst daemon inst pidfile vtyfile pid cnt fail
164 daemon_inst "$1"
165
166 pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
167 vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty"
168
169 [ -r "$pidfile" ] || fail="pid file not found"
170 [ -z "$fail" ] && pid="`cat \"$pidfile\"`"
171 [ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
172 [ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
173
174 if [ -n "$fail" ]; then
175 log_failure_msg "Cannot stop $dmninst: $fail"
176 return 1
177 fi
178
179 debug "kill -2 $pid"
180 kill -2 "$pid"
181 cnt=1200
182 while kill -0 "$pid" 2>/dev/null; do
183 sleep .1
184 [ $(( cnt -= 1 )) -gt 0 ] || break
185 done
186 if kill -0 "$pid" 2>/dev/null; then
187 log_failure_msg "Failed to stop $dmninst, pid $pid still running"
188 still_running=1
189 return 1
190 else
191 log_success_msg "Stopped $dmninst"
192 rm -f "$pidfile"
193 return 0
194 fi
195 }
196
197 daemon_status() {
198 local dmninst daemon inst pidfile pid fail
199 daemon_inst "$1"
200
201 pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
202
203 [ -r "$pidfile" ] || return 3
204 pid="`cat \"$pidfile\"`"
205 [ -z "$pid" ] && return 1
206 kill -0 "$pid" 2>/dev/null || return 1
207 return 0
208 }
209
210 print_status() {
211 daemon_status "$1"
212 rv=$?
213 if [ "$rv" -eq 0 ]; then
214 log_success_msg "Status of $1: running"
215 else
216 log_failure_msg "Status of $1: FAILED"
217 fi
218 return $rv
219 }
220
221 #
222 # all-daemon commands
223 #
224
225 all_start() {
226 daemon_list daemons
227 for dmninst in $daemons; do
228 daemon_start "$dmninst"
229 done
230 }
231
232 all_stop() {
233 local pids reversed
234
235 daemon_list daemons disabled
236 [ "$1" = "--reallyall" ] && daemons="$daemons $disabled"
237
238 reversed=""
239 for dmninst in $daemons; do
240 reversed="$dmninst $reversed"
241 done
242
243 for dmninst in $reversed; do
244 daemon_stop "$dmninst" &
245 pids="$pids $!"
246 done
247 for pid in $pids; do
248 wait $pid
249 done
250 }
251
252 all_status() {
253 local fail
254
255 daemon_list daemons
256 fail=0
257 for dmninst in $daemons; do
258 print_status "$dmninst" || fail=1
259 done
260 return $fail
261 }
262
263 #
264 # config sourcing
265 #
266
267 load_old_config() {
268 oldcfg="$1"
269 [ -r "$oldcfg" ] || return 0
270 [ -s "$oldcfg" ] || return 0
271 grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0
272
273 log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
274
275 # save off settings from daemons for the OR below
276 for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
277
278 . "$oldcfg"
279
280 # OR together the daemon enabling options between config files
281 for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
282 }
283
284 [ -r "$C_PATH/daemons" ] || {
285 log_failure_msg "cannot run $@: $C_PATH/daemons does not exist"
286 exit 1
287 }
288 . "$C_PATH/daemons"
289
290 load_old_config "$C_PATH/daemons.conf"
291 load_old_config "/etc/default/frr"
292 load_old_config "/etc/sysconfig/frr"
293
294 if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
295 log_warning_msg "watchfrr_options contains a bash array value." \
296 "The configured value is intentionally ignored since it is likely wrong." \
297 "Please remove or fix the setting."
298 unset watchfrr_options
299 fi
300
301 #
302 # other defaults and dispatch
303 #
304
305 frrcommon_main() {
306 local cmd
307
308 debug "frrcommon_main" "$@"
309
310 cmd="$1"
311 shift
312
313 if [ "$1" = "all" -o -z "$1" ]; then
314 case "$cmd" in
315 start) all_start;;
316 stop) all_stop;;
317 restart)
318 all_stop
319 all_start
320 ;;
321 *) $cmd "$@";;
322 esac
323 else
324 case "$cmd" in
325 start) daemon_start "$@";;
326 stop) daemon_stop "$@";;
327 restart)
328 daemon_stop "$@"
329 daemon_start "$@"
330 ;;
331 *) $cmd "$@";;
332 esac
333 fi
334 }