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