Files
bpfire/src/initscripts/system/functions
Peter Müller 66c3619872 Early spring clean: Remove trailing whitespaces, and correct licence headers
Bumping across one of our scripts with very long trailing whitespaces, I
thought it might be a good idea to clean these up. Doing so, some
missing or inconsistent licence headers were fixed.

There is no need in shipping all these files en bloc, as their
functionality won't change.

Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
2022-02-18 23:54:57 +00:00

878 lines
20 KiB
Bash

#!/bin/sh
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
## Environmental setup
# Setup default values for environment
umask 022
export PATH="/bin:/usr/bin:/sbin:/usr/sbin"
# Signal sent to running processes to refresh their configuration
RELOADSIG="HUP"
# Number of seconds between STOPSIG and FALLBACK when stopping processes
KILLDELAY="10"
## Screen Dimensions
# Find current screen size
if [ -z "${COLUMNS}" ]; then
COLUMNS=$(stty size 2>/dev/null)
COLUMNS=${COLUMNS##* }
fi
# When using remote connections, such as a serial port, stty size returns 0
if [ "${COLUMNS}" = "0" ]; then
COLUMNS=80
fi
## Measurements for positioning result messages
COL=$((${COLUMNS} - 8))
WCOL=$((${COL} - 2))
## Set Cursor Position Commands, used via echo -e
SET_COL="\\033[${COL}G" # at the $COL char
SET_WCOL="\\033[${WCOL}G" # at the $WCOL char
CURS_UP="\\033[1A\\033[0G" # Up one line, at the 0'th char
## Set color commands, used via echo -e
# Please consult `man console_codes for more information
# under the "ECMA-48 Set Graphics Rendition" section
#
# Warning: when switching from a 8bit to a 9bit font,
# the linux console will reinterpret the bold (1;) to
# the top 256 glyphs of the 9bit font. This does
# not affect framebuffer consoles
NORMAL="\\033[0;39m" # Standard console grey
SUCCESS="\\033[1;32m" # Success is green
WARNING="\\033[1;33m" # Warnings are yellow
FAILURE="\\033[1;31m" # Failures are red
INFO="\\033[1;36m" # Information is light cyan
BRACKET="\\033[1;34m" # Brackets are blue
STRING_LENGTH="0" # the length of the current message
#*******************************************************************************
# Function - boot_mesg()
#
# Purpose: Sending information from bootup scripts to the console
#
# Inputs: $1 is the message
# $2 is the colorcode for the console
#
# Outputs: Standard Output
#
# Dependencies: - sed for parsing strings.
# - grep for counting string length.
#
# Todo:
#*******************************************************************************
boot_mesg()
{
local ECHOPARM=""
while true
do
case "${1}" in
-n)
ECHOPARM=" -n "
shift 1
;;
-*)
echo "Unknown Option: ${1}"
return 1
;;
*)
break
;;
esac
done
## Figure out the length of what is to be printed to be used
## for warning messges.
STRING_LENGTH="`echo "${1}" | sed \
-e 's,.,.,g' -e 'l 1' | grep -c \$`"
# Print the message to the screen
echo ${ECHOPARM} -e "${2}${1}"
}
boot_mesg_flush()
{
# Reset STRING_LENGTH for next message
STRING_LENGTH="0"
}
boot_log()
{
# Left in for backwards compatibility
echo -n ""
}
echo_ok()
{
echo -n -e "${CURS_UP}${SET_COL}${BRACKET}[${SUCCESS} OK ${BRACKET}]"
echo -e "${NORMAL}"
boot_mesg_flush
}
echo_failure()
{
echo -n -e "${CURS_UP}${SET_COL}${BRACKET}[${FAILURE} FAIL ${BRACKET}]"
echo -e "${NORMAL}"
boot_mesg_flush
}
echo_warning()
{
echo -n -e "${CURS_UP}${SET_COL}${BRACKET}[${WARNING} WARN ${BRACKET}]"
echo -e "${NORMAL}"
boot_mesg_flush
}
print_error_msg()
{
echo_failure
# $i is inherited by the rc script
boot_mesg -n "FAILURE:\n\nYou should not be reading this error message.\n\n" ${FAILURE}
boot_mesg -n " It means that an unforeseen error took"
boot_mesg -n " place in ${i}, which exited with a return value of"
boot_mesg " ${error_value}.\n"
boot_mesg_flush
boot_mesg -n "If you're able to track this"
boot_mesg -n " error down to a bug in one of the files provided by"
boot_mesg -n " ipfire, please be so kind to inform us at"
boot_mesg " https://bugzilla.ipfire.org.\n"
boot_mesg_flush
boot_mesg -n "Press Enter to continue or wait a minute..." ${INFO}
boot_mesg "" ${NORMAL}
read -t 60 ENTER
}
check_script_status()
{
# $i is inherited by the rc script
if [ ! -f ${i} ]; then
boot_mesg "${i} is not a valid symlink." ${WARNING}
echo_warning
continue
fi
if [ ! -x ${i} ]; then
boot_mesg "${i} is not executable, skipping." ${WARNING}
echo_warning
continue
fi
}
evaluate_retval()
{
error_value="${?}"
if [ ${error_value} = 0 ]; then
echo_ok
else
echo_failure
fi
# This prevents the 'An Unexpected Error Has Occurred' from trivial
# errors.
return 0
}
print_status()
{
if [ "${#}" = "0" ]; then
echo "Usage: ${0} {success|warning|failure}"
return 1
fi
case "${1}" in
success)
echo_ok
;;
warning)
# Leave this extra case in because old scripts
# may call it this way.
case "${2}" in
running)
echo -e -n "${CURS_UP}"
echo -e -n "\\033[${STRING_LENGTH}G "
boot_mesg "Already running." ${WARNING}
echo_warning
;;
not_running)
echo -e -n "${CURS_UP}"
echo -e -n "\\033[${STRING_LENGTH}G "
boot_mesg "Not running." ${WARNING}
echo_warning
;;
not_available)
echo -e -n "${CURS_UP}"
echo -e -n "\\033[${STRING_LENGTH}G "
boot_mesg "Not available." ${WARNING}
echo_warning
;;
*)
# This is how it is supposed to
# be called
echo_warning
;;
esac
;;
failure)
echo_failure
;;
esac
}
reloadproc()
{
if [ "${#}" = "0" ]; then
echo "Usage: reloadproc [{program}]"
exit 1
fi
getpids "${1}"
if [ -n "${pidlist}" ]; then
failure="0"
for pid in ${pidlist}
do
kill -"${RELOADSIG}" "${pid}" || failure="1"
done
(exit ${failure})
evaluate_retval
else
boot_mesg "Process ${1} not running." ${WARNING}
echo_warning
fi
}
statusproc()
{
if [ "${#}" = "0" ]
then
echo "Usage: statusproc {program}"
exit 1
fi
getpids "${1}"
if [ -n "${pidlist}" ]; then
echo -e "${INFO}${base} is running with Process"\
"ID(s) ${pidlist}.${NORMAL}"
else
if [ -n "${base}" -a -e "/var/run/${base}.pid" ]; then
echo -e "${WARNING}${1} is not running but"\
"/var/run/${base}.pid exists.${NORMAL}"
else
if [ -n "${PIDFILE}" -a -e "${PIDFILE}" ]; then
echo -e "${WARNING}${1} is not running"\
"but ${PIDFILE} exists.${NORMAL}"
else
echo -e "${INFO}${1} is not running.${NORMAL}"
fi
fi
fi
}
# The below functions are documented in the LSB-generic 2.1.0
#*******************************************************************************
# Function - pidofproc [-s] [-p pidfile] pathname
#
# Purpose: This function returns one or more pid(s) for a particular daemon
#
# Inputs: -p pidfile, use the specified pidfile instead of pidof
# pathname, path to the specified program
#
# Outputs: return 0 - Success, pid's in stdout
# return 1 - Program is dead, pidfile exists
# return 2 - Invalid or excessive number of arguments,
# warning in stdout
# return 3 - Program is not running
#
# Dependencies: pidof, echo, head
#
# Todo: Remove dependency on head
# This depreciates getpids
# Test changes to pidof
#
#*******************************************************************************
pidofproc()
{
local pidfile=""
local lpids=""
local silent=""
pidlist=""
while true
do
case "${1}" in
-p)
pidfile="${2}"
shift 2
;;
-s)
# Added for legacy opperation of getpids
# eliminates several '> /dev/null'
silent="1"
shift 1
;;
-*)
log_failure_msg "Unknown Option: ${1}"
return 2
;;
*)
break
;;
esac
done
if [ "${#}" != "1" ]; then
shift 1
log_failure_msg "Usage: pidofproc [-s] [-p pidfile] pathname"
return 2
fi
if [ -n "${pidfile}" ]; then
if [ ! -r "${pidfile}" ]; then
return 3 # Program is not running
fi
lpids=`head -n 1 ${pidfile}`
for pid in ${lpids}
do
if [ "${pid}" -ne "$$" -a "${pid}" -ne "${PPID}" ]; then
kill -0 "${pid}" > /dev/null &&
pidlist="${pidlist} ${pid}"
fi
if [ "${silent}" -ne "1" ]; then
echo "${pidlist}"
fi
test -z "${pidlist}" &&
# Program is dead, pidfile exists
return 1
# else
return 0
done
else
pidlist=`pidof -o $$ -o $PPID -x "$1"`
if [ "x${silent}" != "x1" ]; then
echo "${pidlist}"
fi
# Get provide correct running status
if [ -n "${pidlist}" ]; then
return 0
else
return 3
fi
fi
if [ "$?" != "0" ]; then
return 3 # Program is not running
fi
}
# This will ensure compatibility with previous LFS Bootscripts
getpids()
{
if [ -z "${PIDFILE}" ]; then
pidofproc -s -p "${PIDFILE}" $@
else
pidofproc -s $@
fi
base="${1##*/}"
}
#*******************************************************************************
# Function - loadproc [-f] [-n nicelevel] [-p pidfile] pathname [args]
#
# Purpose: This runs the specified program as a daemon
#
# Inputs: -f, run the program even if it is already running
# -n nicelevel, specifies a nice level. See nice(1).
# -p pidfile, uses the specified pidfile
# pathname, pathname to the specified program
# args, arguments to pass to specified program
#
# Outputs: return 0 - Success
# return 2 - Invalid of excessive number of arguments,
# warning in stdout
# return 4 - Program or service status is unknown
#
# Dependencies: nice
#
# Todo: LSB says this should be called start_daemon
# LSB does not say that it should call evaluate_retval
# It checks for PIDFILE, which is deprecated.
# Will be removed after BLFS 6.0
# loadproc returns 0 if program is already running, not LSB compliant
#
#*******************************************************************************
loadproc()
{
local background=""
local pidfile=""
local forcestart=""
local nicelevel=""
# This will ensure compatibility with previous LFS Bootscripts
if [ -n "${PIDFILE}" ]; then
pidfile="${PIDFILE}"
fi
while true
do
case "${1}" in
-b)
background="1"
shift 1
;;
-f)
forcestart="1"
shift 1
;;
-n)
nicelevel="${2}"
shift 2
;;
-p)
pidfile="${2}"
shift 2
;;
-*)
log_failure_msg "Unknown Option: ${1}"
return 2 #invalid or excess argument(s)
;;
*)
break
;;
esac
done
if [ "${#}" = "0" ]; then
log_failure_msg "Usage: loadproc [-f] [-n nicelevel] [-p pidfile] pathname [args]"
return 2 #invalid or excess argument(s)
fi
if [ -z "${forcestart}" ]; then
if [ -z "${pidfile}" ]; then
pidofproc -s "${1}"
else
pidofproc -s -p "${pidfile}" "${1}"
fi
case "${?}" in
0)
log_warning_msg "Unable to continue: ${1} is running"
return 0 # 4
;;
1)
log_warning_msg "Unable to continue: ${pidfile} exists"
return 0 # 4
;;
3)
;;
*)
log_failure_msg "Unknown error code from pidofproc: ${?}"
return 4
;;
esac
fi
local cmd="${@}"
if [ -n "${nicelevel}" ]; then
cmd="nice -n "${nicelevel}" ${cmd}"
fi
if [ -n "${background}" ]; then
(
${cmd} &>/dev/null
) &
evaluate_retval
else
${cmd}
evaluate_retval # This is "Probably" not LSB compliant, but required to be compatible with older bootscripts
fi
return 0
}
#*******************************************************************************
# Function - killproc [-p pidfile] pathname [signal]
#
# Purpose:
#
# Inputs: -p pidfile, uses the specified pidfile
# pathname, pathname to the specified program
# signal, send this signal to pathname
#
# Outputs: return 0 - Success
# return 2 - Invalid of excessive number of arguments,
# warning in stdout
# return 4 - Unknown Status
#
# Dependencies: kill
#
# Todo: LSB does not say that it should call evaluate_retval
# It checks for PIDFILE, which is deprecated.
# Will be removed after BLFS 6.0
#
#*******************************************************************************
killproc()
{
local pidfile=""
local killsig=""
pidlist=""
# This will ensure compatibility with previous LFS Bootscripts
if [ -n "${PIDFILE}" ]; then
pidfile="${PIDFILE}"
fi
while true
do
case "${1}" in
-p)
pidfile="${2}"
shift 2
;;
-*)
log_failure_msg "Unknown Option: ${1}"
return 2
;;
*)
break
;;
esac
done
if [ "${#}" = "2" ]; then
killsig="${2}"
elif [ "${#}" != "1" ]; then
shift 2
log_failure_msg "Usage: killproc [-p pidfile] pathname [signal]"
return 2
fi
if [ -z "${pidfile}" ]; then
pidofproc -s "${1}"
else
pidofproc -s -p "${pidfile}" "${1}"
fi
# Change....
if [ -n "${pidlist}" ]; then
for pid in ${pidlist}
do
kill -${killsig:-TERM} ${pid} 2>/dev/null
if [ -z "${killsig}" ]; then
# Wait up to 3 seconds, for ${pid} to terminate
local dtime=${KILLDELAY}
while [ "${dtime}" != "0" ]
do
kill -0 ${pid} 2>/dev/null || break
sleep 1
dtime=$(( ${dtime} - 1))
done
# If ${pid} is still running, kill it
kill -0 ${pid} 2>/dev/null && kill -KILL ${pid} 2>/dev/null
fi
done
if [ -z "${killsig}" ]; then
pidofproc -s "${1}"
# Program was terminated
if [ "$?" != "0" ]; then
# Pidfile Exists
if [ -f "${pidfile}" ]; then
rm -f "${pidfile}"
fi
echo_ok
return 0
else # Program is still running
echo_failure
return 4 # Unknown Status
fi
else
if [ -z "${pidfile}" ]; then
pidofproc -s "${1}"
else
pidofproc -s -p "${pidfile}" "${1}"
fi
fi
evaluate_retval # This is "Probably" not LSB compliant, but required to be compatible with older bootscripts
else
print_status warning not_running
fi
}
#*******************************************************************************
# Function - log_success_msg "message"
#
# Purpose: Print a success message
#
# Inputs: $@ - Message
#
# Outputs: Text output to screen
#
# Dependencies: echo
#
# Todo: logging
#
#*******************************************************************************
log_success_msg()
{
echo -n -e "${BOOTMESG_PREFIX}${@}"
echo -e "${SET_COL}""${BRACKET}""[""${SUCCESS}"" OK ""${BRACKET}""]""${NORMAL}"
return 0
}
#*******************************************************************************
# Function - log_failure_msg "message"
#
# Purpose: Print a failure message
#
# Inputs: $@ - Message
#
# Outputs: Text output to screen
#
# Dependencies: echo
#
# Todo: logging
#
#*******************************************************************************
log_failure_msg() {
echo -n -e "${BOOTMESG_PREFIX}${@}"
echo -e "${SET_COL}""${BRACKET}""[""${FAILURE}"" FAIL ""${BRACKET}""]""${NORMAL}"
return 0
}
#*******************************************************************************
# Function - log_warning_msg "message"
#
# Purpose: print a warning message
#
# Inputs: $@ - Message
#
# Outputs: Text output to screen
#
# Dependencies: echo
#
# Todo: logging
#
#*******************************************************************************
log_warning_msg() {
echo -n -e "${BOOTMESG_PREFIX}${@}"
echo -e "${SET_COL}""${BRACKET}""[""${WARNING}"" WARN ""${BRACKET}""]""${NORMAL}"
return 0
}
run_subdir() {
DIR=$1
for i in $(ls -v ${DIR}* 2> /dev/null); do
check_script_status
OUT=$(echo $(basename ${i}) | awk -F- '{ print $2 }')
case "$OUT" in
S) ${i} start ;;
K) ${i} stop ;;
RS) ${i} restart ;;
RL) ${i} reload ;;
U) ${i} up ;;
D) ${i} down ;;
*) ${i} ;;
esac
done
}
mem_amount() {
local pagesize="$(getconf PAGESIZE)"
local pages="$(getconf _PHYS_PAGES)"
echo "$(( ${pagesize} * ${pages} / 1024 / 1024 ))"
}
use_ramdisk() {
eval $(/usr/local/bin/readhash /etc/sysconfig/ramdisk)
case "${RAMDISK_MODE}" in
# Don't use ramdisk
0)
return 1
;;
# Always use ramdisk
1)
return 0
;;
# Automatic mode - use ramdisk if sufficient
# memory is available
2)
local mem_avail="$(mem_amount)"
if [ ${mem_avail} -ge 400 ]; then
return 0
else
return 1
fi
;;
# Fail for everything else
*)
return 2
;;
esac
}
mount_ramdisk() {
local path="${1}"
local path_tmpfs="${path}.tmpfs"
# Check if the ramdisk is already mounted
if mountpoint "${path}" &>/dev/null; then
return 0
fi
# Create ramdisk
mkdir -p "${path_tmpfs}"
mount -t tmpfs none "${path_tmpfs}"
# Restore ramdisk content
cp -pR ${path}/* "${path_tmpfs}"
# Move ramdisk to final destination
mount --move "${path_tmpfs}" "${path}"
rm -rf "${path_tmpfs}"
}
umount_ramdisk() {
local path="${1}"
local path_tmpfs="${path}.tmpfs"
# Check if a ramdisk is actually mounted
if ! mountpoint "${path}" &>/dev/null; then
return 0
fi
# Move the ramdisk
mkdir -p "${path_tmpfs}"
mount --move "${path}" "${path_tmpfs}"
# Backup ramdisk content
cp -pR ${path_tmpfs}/* "${path}"
# Destroy the ramdisk
umount "${path_tmpfs}"
rm -rf "${path_tmpfs}"
}
# Returns true when this system running in a virtual environment
running_on_hypervisor() {
grep -qE "^flags\s+:.*hypervisor" /proc/cpuinfo
}
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html
running_on_ec2() {
local uuid
# Check if the DMI product UUID starts with EC2
if [ -r "/sys/devices/virtual/dmi/id/product_uuid" ]; then
uuid=$(</sys/devices/virtual/dmi/id/product_uuid)
# Convert the UUID as uppercase
uuid="${uuid^^}"
[ "${uuid:0:3}" = "EC2" ] && return 0
fi
# We are not running on AWS EC2
return 1
}
running_on_azure() {
# Check if the vendor is Microsoft
if [ -r "/sys/devices/virtual/dmi/id/sys_vendor" ] && \
[ "$(</sys/devices/virtual/dmi/id/sys_vendor)" = "Microsoft Corporation" ]; then
# Check if this product is a "Virtual Machine"
if [ -r "/sys/devices/virtual/dmi/id/product_name" ] && \
[ "$(</sys/devices/virtual/dmi/id/product_name)" = "Virtual Machine" ]; then
# Yes, we are running on Azure
return 0
fi
fi
# We are not running on Azure
return 1
}
running_on_exoscale() {
if [ -r "/sys/devices/virtual/dmi/id/sys_vendor" ]; then
local sys_vendor="$(</sys/devices/virtual/dmi/id/sys_vendor)"
[ "${sys_vendor}" = "Exoscale" ] && return 0
fi
# We are not running on Exoscale
return 1
}
running_on_gcp() {
# Check if the BIOS vendor is "Google"
if [ -r "/sys/devices/virtual/dmi/id/bios_vendor" ]; then
local bios_vendor="$(</sys/devices/virtual/dmi/id/bios_vendor)"
[ "${bios_vendor}" = "Google" ] && return 0
fi
# We are not running on GCP
return 1
}
running_on_oci() {
if [ -r "/sys/devices/virtual/dmi/id/chassis_asset_tag" ]; then
local asset_tag="$(</sys/devices/virtual/dmi/id/chassis_asset_tag)"
[ "${asset_tag}" = "OracleCloud.com" ] && return 0
fi
# We are not running on OCI
return 1
}