mirror_frr/tools/frrcommon.sh.in
David Lamparter ea4d91bfba debian/tools: new init script
This separates the init script used for the system (and called in the
systemd unit file) from the script that watchfrr uses to control
daemons.  Mixing these two caused the entire thing to become a rather
huge spaghetti mess.

Note that there is a behaviour change in that the new script always
starts zebra regardless of zebra_enable.

Side changes:
- Ubuntu 12.04 removed from backports since it doesn't work anyway
- zebra is always started regardless of zebra_enable.  To disable FRR,
  the entire init script should be disabled through policy.
- no-watchfrr operation is no longer supported by the scripts in the
  Debian packages.  (This is intentional.)

Signed-off-by: David Lamparter <equinox@diac24.net>
2018-12-06 23:05:48 +01:00

318 lines
6.6 KiB
Bash

#!/bin/sh
#
# This is a "library" of sorts for use by the other FRR shell scripts. It
# has most of the daemon start/stop logic, but expects the following shell
# functions/commands to be provided by the "calling" script:
#
# log_success_msg
# log_warning_msg
# log_failure_msg
#
# (coincidentally, these are LSB standard functions.)
#
# Sourcing this file in a shell script will load FRR config variables but
# not perform any action. Note there is an "exit 1" if the main config
# file does not exist.
#
# This script should be installed in @CFG_SBIN@/frrcommon.sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin
D_PATH="@CFG_SBIN@" # /usr/lib/frr
C_PATH="@CFG_SYSCONF@" # /etc/frr
V_PATH="@CFG_STATE@" # /var/run/frr
VTYSH="@vtysh_bin@" # /usr/bin/vtysh
FRR_USER="@enable_user@" # frr
FRR_GROUP="@enable_group@" # frr
FRR_VTY_GROUP="@enable_vty_group@" # frrvty
# ORDER MATTERS FOR $DAEMONS!
# - keep zebra first
# - watchfrr does NOT belong in this list
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd"
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
#
# general helpers
#
debug() {
[ -n "$watchfrr_debug" ] || return 0
printf '%s %s(%s):' "`date +%Y-%m-%dT%H:%M:%S.%N`" "$0" $$ >&2
# this is to show how arguments are split regarding whitespace & co.
# (e.g. for use with `debug "message" "$@"`)
while [ $# -gt 0 ]; do
printf ' "%s"' "$1" >&2
shift
done
printf '\n' >&2
}
chownfrr() {
[ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
[ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
}
vtysh_b () {
[ "$1" = "watchfrr" ] && return 0
[ -r "$C_PATH/frr.conf" ] || return 0
if [ -n "$1" ]; then
"$VTYSH" -b -n -d "$1"
else
"$VTYSH" -b -n
fi
}
daemon_inst() {
# note this sets global variables ($dmninst, $daemon, $inst)
dmninst="$1"
daemon="${dmninst%:*}"
inst=""
[ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}"
}
daemon_list() {
# note $1 and $2 specify names for global variables to be set
local enabled disabled evar dvar
enabled=""
disabled=""
evar="$1"
dvar="$2"
for daemon in $DAEMONS; do
eval cfg=\$$daemon
eval inst=\$${daemon}_instances
[ "$daemon" = zebra ] && cfg=yes
if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
debug "$daemon enabled"
enabled="$enabled $daemon"
if [ -n "$inst" ]; then
debug "$daemon multi-instance $inst"
for i in $inst; do
enabled="$enabled $daemon:$inst"
done
fi
else
debug "$daemon disabled"
disabled="$disabled $daemon"
fi
done
enabled="${enabled# }"
disabled="${disabled# }"
[ -z "$evar" ] && echo "$enabled"
[ -n "$evar" ] && eval $evar="\"$enabled\""
[ -n "$dvar" ] && eval $dvar="\"$disabled\""
}
#
# individual daemon management
#
daemon_prep() {
local daemon inst cfg
daemon="$1"
inst="$2"
[ "$daemon" = "watchfrr" ] && return 0
[ -x "$D_PATH/$daemon" ] || {
log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n"
return 1
}
[ -r "$C_PATH/frr.conf" ] && return 0
cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
if [ ! -r "$cfg" ]; then
touch "$cfg"
chownfrr "$cfg"
fi
return 0
}
daemon_start() {
local dmninst daemon inst args instopt wrap bin
daemon_inst "$1"
ulimit -n $MAX_FDS > /dev/null 2> /dev/null
daemon_prep "$daemon" "$inst" || return 1
eval wrap="\$${daemon}_wrap"
bin="$D_PATH/$daemon"
instopt="${inst:+-n $inst}"
eval args="\$${daemon}_options"
if eval "$all_wrap $wrap $bin -d $instopt $args"; then
log_success_msg "Started $dmninst"
vtysh_b "$daemon"
else
log_failure_msg "Failed to start $dmninst!"
fi
}
daemon_stop() {
local dmninst daemon inst pidfile vtyfile pid cnt fail
daemon_inst "$1"
pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty"
[ -r "$pidfile" ] || fail="pid file not found"
[ -z "$fail" ] && pid="`cat \"$pidfile\"`"
[ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
[ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
if [ -n "$fail" ]; then
log_failure_msg "Cannot stop $dmninst: $fail"
return 1
fi
debug "kill -2 $pid"
kill -2 "$pid"
cnt=1200
while kill -0 "$pid" 2>/dev/null; do
sleep .1
[ $(( cnt -= 1 )) -gt 0 ] || break
done
if kill -0 "$pid" 2>/dev/null; then
log_failure_msg "Failed to stop $dmninst, pid $pid still running"
still_running=1
return 1
else
log_success_msg "Stopped $dmninst"
rm -f "$pidfile"
return 0
fi
}
daemon_status() {
local dmninst daemon inst pidfile pid fail
daemon_inst "$1"
pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
[ -r "$pidfile" ] || return 3
pid="`cat \"$pidfile\"`"
[ -z "$pid" ] && return 1
kill -0 "$pid" 2>/dev/null || return 1
return 0
}
print_status() {
daemon_status "$1"
rv=$?
if [ "$rv" -eq 0 ]; then
log_success_msg "Status of $1: running"
else
log_failure_msg "Status of $1: FAILED"
fi
return $rv
}
#
# all-daemon commands
#
all_start() {
daemon_list daemons
for dmninst in $daemons; do
daemon_start "$dmninst"
done
}
all_stop() {
local pids reversed
daemon_list daemons disabled
[ "$1" = "--reallyall" ] && daemons="$daemons $disabled"
reversed=""
for dmninst in $daemons; do
reversed="$dmninst $reversed"
done
for dmninst in $reversed; do
daemon_stop "$dmninst" &
pids="$pids $!"
done
for pid in $pids; do
wait $pid
done
}
all_status() {
local fail
daemon_list daemons
fail=0
for dmninst in $daemons; do
print_status "$dmninst" || fail=1
done
return $fail
}
#
# config sourcing
#
load_old_config() {
oldcfg="$1"
[ -r "$oldcfg" ] || return 0
[ -s "$oldcfg" ] || return 0
grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0
log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
# save off settings from daemons for the OR below
for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
. "$oldcfg"
# OR together the daemon enabling options between config files
for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
}
[ -r "$C_PATH/daemons" ] || {
log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n"
exit 1
}
. "$C_PATH/daemons"
load_old_config "$C_PATH/daemons.conf"
load_old_config "/etc/default/frr"
load_old_config "/etc/sysconfig/frr"
#
# other defaults and dispatch
#
frrcommon_main() {
local cmd
debug "frrcommon_main" "$@"
cmd="$1"
shift
if [ "$1" = "all" -o -z "$1" ]; then
case "$cmd" in
start) all_start;;
stop) all_stop;;
restart)
all_stop
all_start
;;
*) $cmd "$@";;
esac
else
case "$cmd" in
start) daemon_start "$@";;
stop) daemon_stop "$@";;
restart)
daemon_stop "$@"
daemon_start "$@"
;;
*) $cmd "$@";;
esac
fi
}