]>
Commit | Line | Data |
---|---|---|
aa804986 | 1 | #!/bin/bash |
ea4d91bf DL |
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" | |
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 | |
15150265 | 86 | [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes |
ea4d91bf | 87 | if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then |
29a64c0f DL |
88 | if ! daemon_prep "$daemon" "$inst"; then |
89 | continue | |
90 | fi | |
ea4d91bf DL |
91 | debug "$daemon enabled" |
92 | enabled="$enabled $daemon" | |
93 | if [ -n "$inst" ]; then | |
94 | debug "$daemon multi-instance $inst" | |
95 | for i in $inst; do | |
96 | enabled="$enabled $daemon:$inst" | |
97 | done | |
98 | fi | |
99 | else | |
100 | debug "$daemon disabled" | |
101 | disabled="$disabled $daemon" | |
102 | fi | |
103 | done | |
104 | ||
105 | enabled="${enabled# }" | |
106 | disabled="${disabled# }" | |
107 | [ -z "$evar" ] && echo "$enabled" | |
108 | [ -n "$evar" ] && eval $evar="\"$enabled\"" | |
109 | [ -n "$dvar" ] && eval $dvar="\"$disabled\"" | |
110 | } | |
111 | ||
112 | # | |
113 | # individual daemon management | |
114 | # | |
115 | ||
116 | daemon_prep() { | |
117 | local daemon inst cfg | |
118 | daemon="$1" | |
119 | inst="$2" | |
120 | [ "$daemon" = "watchfrr" ] && return 0 | |
121 | [ -x "$D_PATH/$daemon" ] || { | |
122 | log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n" | |
123 | return 1 | |
124 | } | |
125 | [ -r "$C_PATH/frr.conf" ] && return 0 | |
126 | ||
127 | cfg="$C_PATH/$daemon${inst:+-$inst}.conf" | |
128 | if [ ! -r "$cfg" ]; then | |
129 | touch "$cfg" | |
130 | chownfrr "$cfg" | |
131 | fi | |
132 | return 0 | |
133 | } | |
134 | ||
135 | daemon_start() { | |
136 | local dmninst daemon inst args instopt wrap bin | |
137 | daemon_inst "$1" | |
138 | ||
139 | ulimit -n $MAX_FDS > /dev/null 2> /dev/null | |
140 | daemon_prep "$daemon" "$inst" || return 1 | |
b7d492f2 DL |
141 | if test ! -d "$V_PATH"; then |
142 | mkdir -p "$V_PATH" | |
143 | chown frr "$V_PATH" | |
144 | fi | |
ea4d91bf DL |
145 | |
146 | eval wrap="\$${daemon}_wrap" | |
147 | bin="$D_PATH/$daemon" | |
148 | instopt="${inst:+-n $inst}" | |
149 | eval args="\$${daemon}_options" | |
150 | ||
151 | if eval "$all_wrap $wrap $bin -d $instopt $args"; then | |
152 | log_success_msg "Started $dmninst" | |
153 | vtysh_b "$daemon" | |
154 | else | |
155 | log_failure_msg "Failed to start $dmninst!" | |
156 | fi | |
157 | } | |
158 | ||
159 | daemon_stop() { | |
160 | local dmninst daemon inst pidfile vtyfile pid cnt fail | |
161 | daemon_inst "$1" | |
162 | ||
163 | pidfile="$V_PATH/$daemon${inst:+-$inst}.pid" | |
164 | vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty" | |
165 | ||
166 | [ -r "$pidfile" ] || fail="pid file not found" | |
167 | [ -z "$fail" ] && pid="`cat \"$pidfile\"`" | |
168 | [ -z "$fail" -a -z "$pid" ] && fail="pid file is empty" | |
169 | [ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running" | |
170 | ||
171 | if [ -n "$fail" ]; then | |
172 | log_failure_msg "Cannot stop $dmninst: $fail" | |
173 | return 1 | |
174 | fi | |
175 | ||
176 | debug "kill -2 $pid" | |
177 | kill -2 "$pid" | |
178 | cnt=1200 | |
179 | while kill -0 "$pid" 2>/dev/null; do | |
180 | sleep .1 | |
181 | [ $(( cnt -= 1 )) -gt 0 ] || break | |
182 | done | |
183 | if kill -0 "$pid" 2>/dev/null; then | |
184 | log_failure_msg "Failed to stop $dmninst, pid $pid still running" | |
185 | still_running=1 | |
186 | return 1 | |
187 | else | |
188 | log_success_msg "Stopped $dmninst" | |
189 | rm -f "$pidfile" | |
190 | return 0 | |
191 | fi | |
192 | } | |
193 | ||
194 | daemon_status() { | |
195 | local dmninst daemon inst pidfile pid fail | |
196 | daemon_inst "$1" | |
197 | ||
198 | pidfile="$V_PATH/$daemon${inst:+-$inst}.pid" | |
199 | ||
200 | [ -r "$pidfile" ] || return 3 | |
201 | pid="`cat \"$pidfile\"`" | |
202 | [ -z "$pid" ] && return 1 | |
203 | kill -0 "$pid" 2>/dev/null || return 1 | |
204 | return 0 | |
205 | } | |
206 | ||
207 | print_status() { | |
208 | daemon_status "$1" | |
209 | rv=$? | |
210 | if [ "$rv" -eq 0 ]; then | |
211 | log_success_msg "Status of $1: running" | |
212 | else | |
213 | log_failure_msg "Status of $1: FAILED" | |
214 | fi | |
215 | return $rv | |
216 | } | |
217 | ||
218 | # | |
219 | # all-daemon commands | |
220 | # | |
221 | ||
222 | all_start() { | |
223 | daemon_list daemons | |
224 | for dmninst in $daemons; do | |
225 | daemon_start "$dmninst" | |
226 | done | |
227 | } | |
228 | ||
229 | all_stop() { | |
230 | local pids reversed | |
231 | ||
232 | daemon_list daemons disabled | |
233 | [ "$1" = "--reallyall" ] && daemons="$daemons $disabled" | |
234 | ||
235 | reversed="" | |
236 | for dmninst in $daemons; do | |
237 | reversed="$dmninst $reversed" | |
238 | done | |
239 | ||
240 | for dmninst in $reversed; do | |
241 | daemon_stop "$dmninst" & | |
242 | pids="$pids $!" | |
243 | done | |
244 | for pid in $pids; do | |
245 | wait $pid | |
246 | done | |
247 | } | |
248 | ||
249 | all_status() { | |
250 | local fail | |
251 | ||
252 | daemon_list daemons | |
253 | fail=0 | |
254 | for dmninst in $daemons; do | |
255 | print_status "$dmninst" || fail=1 | |
256 | done | |
257 | return $fail | |
258 | } | |
259 | ||
260 | # | |
261 | # config sourcing | |
262 | # | |
263 | ||
264 | load_old_config() { | |
265 | oldcfg="$1" | |
266 | [ -r "$oldcfg" ] || return 0 | |
267 | [ -s "$oldcfg" ] || return 0 | |
268 | grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0 | |
269 | ||
270 | log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it." | |
271 | ||
272 | # save off settings from daemons for the OR below | |
273 | for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done | |
274 | ||
275 | . "$oldcfg" | |
276 | ||
277 | # OR together the daemon enabling options between config files | |
278 | for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done | |
279 | } | |
280 | ||
281 | [ -r "$C_PATH/daemons" ] || { | |
282 | log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n" | |
283 | exit 1 | |
284 | } | |
285 | . "$C_PATH/daemons" | |
286 | ||
287 | load_old_config "$C_PATH/daemons.conf" | |
288 | load_old_config "/etc/default/frr" | |
289 | load_old_config "/etc/sysconfig/frr" | |
290 | ||
aa804986 DL |
291 | if declare -p watchfrr_options | grep -q '^declare \-a'; then |
292 | log_warning_msg "watchfrr_options contains a bash array value." \ | |
293 | "The configured value is intentionally ignored since it is likely wrong." \ | |
294 | "Please remove or fix the setting." | |
295 | unset watchfrr_options | |
296 | fi | |
297 | ||
ea4d91bf DL |
298 | # |
299 | # other defaults and dispatch | |
300 | # | |
301 | ||
302 | frrcommon_main() { | |
303 | local cmd | |
304 | ||
305 | debug "frrcommon_main" "$@" | |
306 | ||
307 | cmd="$1" | |
308 | shift | |
309 | ||
310 | if [ "$1" = "all" -o -z "$1" ]; then | |
311 | case "$cmd" in | |
312 | start) all_start;; | |
313 | stop) all_stop;; | |
314 | restart) | |
315 | all_stop | |
316 | all_start | |
317 | ;; | |
318 | *) $cmd "$@";; | |
319 | esac | |
320 | else | |
321 | case "$cmd" in | |
322 | start) daemon_start "$@";; | |
323 | stop) daemon_stop "$@";; | |
324 | restart) | |
325 | daemon_stop "$@" | |
326 | daemon_start "$@" | |
327 | ;; | |
328 | *) $cmd "$@";; | |
329 | esac | |
330 | fi | |
331 | } |