%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/sbin/ |
| Current File : //proc/thread-self/root/backups/router/usr/local/sbin/keactrl |
#!/bin/sh
# Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# This is keactrl script responsible for starting up Kea processes.
# This script is used to run Kea from installation directory,
# as well as for running tests.
# shellcheck disable=SC2034
# SC2034: ... appears unused. Verify use (or export if used externally).
# shellcheck disable=SC2154
# SC2154: ... is referenced but not assigned.
# Reason: some variables are taken from keactrl.conf
# Exit with error if commands exit with non-zero and if undefined variables are
# used.
set -eu
PACKAGE_VERSION="2.6.1"
EXTENDED_VERSION="2.6.1 (tarball)"
# Set the have_netconf flag to know if netconf is available.
if test 'no' = 'yes'; then
have_netconf=true
else
have_netconf=false
fi
### Logging functions ###
# Logs message at the error level.
log_error() {
printf "ERROR/keactrl: %s\n" "${1}"
}
# Logs message at the warning level.
log_warning() {
printf "WARNING/keactrl: %s\n" "${1}"
}
# Logs message at the info level.
log_info() {
printf "INFO/keactrl: %s\n" "${1}"
}
### Convenience functions ###
# Checks if the value is in the list. An example usage of this function
# is to determine whether the keactrl command belongs to the list of
# supported commands.
is_in_list() {
local member="${1-}" # Value to be checked
local list="${2-}" # Comma separated list of items
_inlist=0 # Return value: 0 if not in list, 1 otherwise.
if [ -z "${member}" ]; then
log_error "missing ${member}"
fi
# Iterate over all items on the list and compare with the member.
# If they match, return, otherwise log error and exit.
for item in ${list}
do
if [ "${item}" = "${member}" ]; then
_inlist=1
return
fi
done
}
# Prints keactrl usage.
usage() {
printf "usage is %s command [-c keactrl-config-file] [-s server[,server,..]]\n" \
"$(basename -- "${0}")"
printf "commands: start stop reload status version\n"
}
### Functions managing Kea processes ###
# Constructs a server's PID file based on its binary name, the config file,
# and the --localstatedir and returns the contents as $_pid. If the file
# does not exist, the value of $_pid is 0. If the file exists but cannot
# be read the function exists with a error message. Note the PID file name
# is always returned in $_pid_file.
# There are some variables set in /etc/kea/keactrl.conf that's included here.
# Since we run shellcheck against keactrl.in rather than an installed file,
# we get false warnings about the variable being referenced but not assigned.
get_pid_from_file() {
local proc_name="${1}" # Process name.
local kea_config_file=
case ${proc_name} in
kea-dhcp4)
kea_config_file=${kea_dhcp4_config_file}
;;
kea-dhcp6)
kea_config_file=${kea_dhcp6_config_file}
;;
kea-dhcp-ddns)
kea_config_file=${kea_dhcp_ddns_config_file}
;;
kea-ctrl-agent)
kea_config_file=${kea_ctrl_agent_config_file}
;;
kea-netconf)
kea_config_file=${kea_netconf_config_file}
;;
esac
# Extract the name portion (from last slash to last dot) of the config file name.
local conf_name
conf_name=$(basename -- "${kea_config_file}" | rev | cut -f2- -d'.' | rev)
# Default the directory to --localstatedir / run
local pid_file_dir
pid_file_dir="/var/run/kea"
# Use directory override if set (primarily for testing only)
if test -n "${KEA_PIDFILE_DIR+x}"; then
pid_file_dir=${KEA_PIDFILE_DIR}
fi
# construct the PID file name
_pid_file="${pid_file_dir}/${conf_name}.${proc_name}.pid"
# Grab the PID if the file exists
_pid=$(cat "${_pid_file}" 2> /dev/null || true)
if test -z "${_pid}"; then
# No file, means no pid
_pid=0;
fi
}
# Checks if the specified process is running by reading its
# PID file and checking the PID it contains. If the file does
# not exist, the process is assumed to not be running.
check_running() {
local proc_name="${1}" # Process name.
# Initially mark the process as not running.
_running=0
# Get the PID from the PID file (if it exists)
get_pid_from_file "${proc_name}"
if [ ${_pid} -gt 0 ]; then
# Use ps to check if PID is alive
if ps -p ${_pid} 1>/dev/null; then
# No error, so PID IS ALIVE
_running=1
fi
fi
}
# Sends a signal to a process based on its PID file
send_signal() {
local sig="${1}" # Signal number
local proc_name="${2}" # Process name.
get_pid_from_file "${proc_name}"
if [ "${_pid}" -eq 0 ]; then
log_info "Skip sending signal ${sig} to process ${proc_name}: \
process is not running"
else
if ! kill "-${sig}" "${_pid}"; then
log_error "Failed to send signal ${sig} to process ${proc_name}, PID {$_pid}."
fi
fi
}
# Start the Kea process. Do not start the process if there is an instance
# already running.
start_server() {
binary_path=${1} # Full path to the binary.
# Extract the name of the binary from the path.
local binary_name
binary_name=$(basename -- "${binary_path}")
# Use the binary name to check if the process is already running.
check_running "${binary_name}"
# If process is running, don't start another one. Just log a message.
if [ "${_running}" -ne 0 ]; then
log_info "${binary_name} appears to be running, see: \
PID ${_pid}, PID file: ${_pid_file}."
else
log_info "Starting ${*}"
# Start the process.
"${@}" &
fi
}
# Instruct Kea process to shutdown by sending it signal 15
stop_server() {
binary_path=${1} # Full path to the binary.
local sig=15
# Extract the name of the binary from the path.
local binary_name
binary_name=$(basename -- "${binary_path}")
# Use the binary name to check if the process is already running.
check_running "${binary_name}"
# If process isn't running, don't start another one. Just log a message.
if [ "${_running}" -eq 0 ]; then
log_info "${binary_name} isn't running."
else
log_info "Stopping ${binary_name}..."
if ! kill "-${sig}" "${_pid}"; then
log_error "Stop failed, could not send signal ${sig} \
to process ${proc_name}, PID ${_pid}."
fi
fi
}
# Instruct Kea process to reload config by sending it signal 1
reload_server() {
binary_path=${1} # Full path to the binary.
local sig=1
# Extract the name of the binary from the path.
local binary_name
binary_name=$(basename -- "${binary_path}")
# Use the binary name to check if the process is already running.
check_running "${binary_name}"
# If process isn't running, don't start another one. Just log a message.
if [ "${_running}" -eq 0 ]; then
log_info "${binary_name} isn't running."
else
log_info "Reloading ${binary_name}..."
if ! kill "-${sig}" "${_pid}"; then
log_error "Reload failed, could not send signal ${sig} \
to process ${proc_name}, PID ${_pid}."
fi
fi
}
# Print Kea daemon version
print_version() {
name=${1}
binary_path=${2}
if [ -e "${binary_path}" ]; then
if ! ver=$(${binary_path} -v); then
log_error "Error checking version of binary file: ${binary_path}"
fi
else
# No file, means no pid
ver="unknown, ${binary_path} missing";
fi
echo "${name}: ${ver}"
}
### Functions testing the existence of the Kea config file
# Check if the Kea configuration file location has been specified in the
# keactrl configuration file. If not, it is a warning or a fatal error.
check_kea_conf() {
local conf_file="${1-}" # Kea config file name.
if [ -z "${conf_file}" ]; then
log_error "Configuration file for Kea not specified."
exit 1
elif [ ! -f "${conf_file}" ]; then
log_error "Configuration file for Kea does not exist: ${conf_file}."
exit 1
fi
}
# Run the specified command if the server has been enabled.
# In order for the command to run, the following conditions have to be met:
# - server must be on the list of servers (e.g. specified from command line)
# or servers must contain all
# - if check_file_cfg is non zero, the server must be enabled in the
# configuration file, so the variable named after server name should exist
# and be set to yes, e.g. ${dhcp4} should be equal to yes if server name
# is dhcp4
run_conditional() {
local server="${1}" # Server name: dhcp4, dhcp6, dhcp_ddns, ctrl_agent, netconf
local commands="${2}" # Commands to execute
local check_file_cfg="${3}" # Check if server enabled in the configuration file
local is_all=0 # is all servers or a specific one
# If keyword "all" is not on the list of servers we will have to check
# if our specific server is on the list. If, not return.
is_in_list "all" "${servers}"
if [ "${_inlist}" -eq 0 ]; then
is_in_list "${server}" "${servers}"
if [ "${_inlist}" -eq 0 ]; then
return
fi
else
is_all=1
fi
# Return for for netconf when not available.
if [ "${server}" = "netconf" ]; then
if ! ${have_netconf}; then
return
fi
# reload is not supported for netconf.
if [ "${command}" = "reload" ]; then
if [ "${is_all}" -eq 1 ]; then
return
fi
log_warning "netconf does not support reload"
return
fi
fi
# Get the configuration value of the keactrl which indicates whether
# the server should be enabled or not. Variables that hold these values
# are: ${dhcp4}, ${dhcp6}, ${dhcp_ddns}.
local file_config
file_config=$( eval printf "%s" "\${$server}" )
# Run the commands if we ignore the configuration setting or if the
# setting is "yes".
if [ "${check_file_cfg}" -eq 0 ] || [ "${file_config}" = "yes" ]; then
${commands}
fi
}
### Script starts here ###
# Configure logger to log messages into the file.
# Do not set destination if the KEA_LOGGER_DESTINATION is set,
# because a unit test could have set this to some other location.
# Note that when the configuration is applied this location may be
# altered and only the handful of initial messages will be logged
# to the default file.
if [ -z "${KEA_LOGGER_DESTINATION+x}" ]; then
prefix="/usr/local"
export KEA_LOGGER_DESTINATION="/var/log/kea.log"
fi
command=${1-}
if [ -z "${command}" ]; then
log_error "missing command"
usage
exit 1
fi
# Check if this is a simple question about version.
if test "${command}" = "-v" || test "${command}" = "--version"; then
echo "${PACKAGE_VERSION}"
exit 0
fi
if test "${command}" = "-V"; then
echo "${EXTENDED_VERSION}"
exit 0
fi
is_in_list "${command}" "start stop reload status version"
if [ "${_inlist}" -eq 0 ]; then
log_error "invalid command: ${command}"
exit 1
fi
# Get the location of the keactrl configuration file.
prefix="/usr/local"
localstatedir="/var"
keactrl_conf="${prefix}/etc/kea/keactrl.conf"
servers="all"
shift
while test ${#} -gt 0
do
option=${1}
case ${option} in
# Override keactrl configuration file.
-c|--ctrl-config)
shift
keactrl_conf=${1-}
if [ -z "${keactrl_conf}" ]; then
log_error "keactrl-config-file not specified"
usage
exit 1
fi
;;
# Get the specific servers for which the command will be
# executed.
-s|--server)
shift
servers=$(printf '%s' "${1-}" | tr ',' '\n')
if [ -z "${servers}" ]; then
log_error "servers not specified"
usage
exit 1
fi
# Validate that the specified server names are correct.
for s in ${servers}
do
server_list="all dhcp4 dhcp6 dhcp_ddns ctrl_agent"
if ${have_netconf}; then
server_list="${server_list} netconf"
fi
is_in_list "${s}" "${server_list}"
if [ "${_inlist}" -eq 0 ]; then
log_error "invalid server name: ${s}"
exit 1
fi
done
;;
*)
log_error "invalid option: ${option}"
usage
exit 1
esac
shift
done
# Check if the file exists. If it doesn't, it is a fatal error.
if [ ! -f "${keactrl_conf}" ]; then
log_error "keactrl configuration file doesn't exist in ${keactrl_conf}."
exit 1
fi
# Include the configuration file.
# shellcheck source=src/bin/keactrl/keactrl.conf.in
. "${keactrl_conf}"
# Get location of the DHCPv4 server binary.
if [ -z "${dhcp4_srv+x}" ]; then
log_error "dhcp4_srv parameter not specified"
exit 1
fi
# Get location of the DHCPv6 server binary.
if [ -z "${dhcp6_srv+x}" ]; then
log_error "dhcp6_srv parameter not specified"
exit 1
fi
# Get location of the DHCP DDNS server binary.
if [ -z "${dhcp_ddns+x}" ]; then
log_error "dhcp_ddns parameter not specified"
exit 1
fi
# Get location of the Control Agent binary.
if [ -z "${ctrl_agent_srv+x}" ]; then
log_error "ctrl_agent_srv parameter not specified"
exit 1
fi
# Get location of the Netconf binary.
if ${have_netconf}; then
if [ -z "${netconf_srv+x}" ]; then
log_error "netconf_srv parameter not specified"
exit 1
fi
fi
# dhcp4 and dhcp6 (=yes) indicate if we should start DHCPv4 and DHCPv6 server
# respectively. The same is true for ddns, ctrl-agent and netconf.
dhcp4=$( printf "%s" "${dhcp4}" | tr '[:upper:]' '[:lower:]' )
dhcp6=$( printf "%s" "${dhcp6}" | tr '[:upper:]' '[:lower:]' )
dhcp_ddns=$( printf "%s" "${dhcp_ddns}" | tr '[:upper:]' '[:lower:]' )
ctrl_agent=$( printf "%s" "${ctrl_agent}" | tr '[:upper:]' '[:lower:]' )
if ${have_netconf}; then
netconf=$( printf "%s" "${netconf}" | tr '[:upper:]' '[:lower:]' )
fi
case ${command} in
# Start the servers.
start)
args=""
# kea_verbose is set in keactrl.conf that shellcheck is unable to load.
if [ "${kea_verbose}" = "yes" ]; then
args="-d"
fi
# Run servers if they are on the list of servers from the command line
# and if they are enabled in the keactrl configuration file.
# The variables (dhcp4_srv, dhcp6_serv, dhcp_ddns_srv etc) are set in the
# keactrl.conf file that shellcheck is unable to read.
run_conditional "dhcp4" "start_server ${dhcp4_srv} -c ${kea_dhcp4_config_file} ${args}" 1
run_conditional "dhcp6" "start_server ${dhcp6_srv} -c ${kea_dhcp6_config_file} ${args}" 1
run_conditional "dhcp_ddns" "start_server ${dhcp_ddns_srv} -c ${kea_dhcp_ddns_config_file} \
${args}" 1
run_conditional "ctrl_agent" "start_server ${ctrl_agent_srv} -c ${kea_ctrl_agent_config_file} \
${args}" 1
if ${have_netconf}; then
run_conditional "netconf" "start_server ${netconf_srv} -c ${kea_netconf_config_file} \
${args}" 1
fi
exit 0 ;;
# Stop running servers.
stop)
# Stop all servers or servers specified from the command line.
run_conditional "dhcp4" "stop_server ${dhcp4_srv}" 0
run_conditional "dhcp6" "stop_server ${dhcp6_srv}" 0
run_conditional "dhcp_ddns" "stop_server ${dhcp_ddns_srv}" 0
run_conditional "ctrl_agent" "stop_server ${ctrl_agent_srv}" 0
if ${have_netconf}; then
run_conditional "netconf" "stop_server ${netconf_srv}" 0
fi
exit 0 ;;
# Reconfigure the servers.
reload)
# Reconfigure all servers or servers specified from the command line.
run_conditional "dhcp4" "reload_server ${dhcp4_srv}" 0
run_conditional "dhcp6" "reload_server ${dhcp6_srv}" 0
run_conditional "dhcp_ddns" "reload_server ${dhcp_ddns_srv}" 0
run_conditional "ctrl_agent" "reload_server ${ctrl_agent_srv}" 0
if ${have_netconf}; then
run_conditional "netconf" "reload_server ${netconf_srv}" 0
fi
exit 0 ;;
status)
if [ -t 1 ]; then
inactive="\033[91minactive\033[0m"
active="\033[92mactive\033[0m"
else
inactive="inactive"
active="active"
fi
kea4_status=$inactive
# This case of nested double quotes looks confusing, but it is actually
# correct. For details, see this fine explanation:
# https://unix.stackexchange.com/questions/443989/whats-the-right-way-to-quote-command-arg
check_running "$(basename -- "${dhcp4_srv}")"
if [ "${_running}" -eq 1 ]; then
kea4_status=$active
fi
printf "DHCPv4 server: %b\n" "${kea4_status}"
kea6_status=$inactive
check_running "$(basename -- "${dhcp6_srv}")"
if [ "${_running}" -eq 1 ]; then
kea6_status=$active
fi
printf "DHCPv6 server: %b\n" "${kea6_status}"
d2_status=$inactive
check_running "$(basename -- "${dhcp_ddns_srv}")"
if [ "${_running}" -eq 1 ]; then
d2_status=$active
fi
printf "DHCP DDNS: %b\n" "${d2_status}"
agent_status=$inactive
check_running "$(basename -- "${ctrl_agent_srv}")"
if [ "${_running}" -eq 1 ]; then
agent_status=$active
fi
printf "Control Agent: %b\n" "${agent_status}"
if ${have_netconf}; then
netconf_status=$inactive
check_running "$(basename -- "${netconf_srv}")"
if [ "${_running}" -eq 1 ]; then
netconf_status=$active
fi
printf "Netconf agent: %b\n" "${netconf_status}"
fi
printf "Kea DHCPv4 configuration file: %s\n" "${kea_dhcp4_config_file}"
printf "Kea DHCPv6 configuration file: %s\n" "${kea_dhcp6_config_file}"
printf "Kea DHCP DDNS configuration file: %s\n" "${kea_dhcp_ddns_config_file}"
printf "Kea Control Agent configuration file: %s\n" "${kea_ctrl_agent_config_file}"
if ${have_netconf}; then
printf "Kea Netconf configuration file: %s\n" "${kea_netconf_config_file}"
fi
printf "keactrl configuration file: %s\n" "${keactrl_conf}"
check_kea_conf "${kea_dhcp4_config_file}"
check_kea_conf "${kea_dhcp6_config_file}"
check_kea_conf "${kea_dhcp_ddns_config_file}"
check_kea_conf "${kea_ctrl_agent_config_file}"
if ${have_netconf}; then
check_kea_conf "${kea_netconf_config_file}"
fi
exit 0 ;;
version)
echo "keactrl: ${PACKAGE_VERSION}"
run_conditional "dhcp4" "print_version kea-dhcp4 ${dhcp4_srv}" 0
run_conditional "dhcp6" "print_version kea-dhcp6 ${dhcp6_srv}" 0
run_conditional "dhcp_ddns" "print_version kea-dhcp-ddns ${dhcp_ddns_srv}" 0
run_conditional "ctrl_agent" "print_version kea-ctrl-agent ${ctrl_agent_srv}" 0
if ${have_netconf}; then
run_conditional "netconf" "print_version kea-netconf ${netconf_srv}" 0
fi
exit 0 ;;
# No other commands are supported.
*)
log_error "Invalid command: ${command}."
exit 1 ;;
esac