Project: IPFire
Code Location: git://git.ipfire.org/network.gitmaster
Browse
/
Download File
functions.util
#!/bin/bash
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2010  Michael Tremer & Christian Schmidt                      #
#                                                                             #
# 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/>.       #
#                                                                             #
###############################################################################

# A simple print statement
function print() {
	local fmt=${1}; shift

	printf -- "${fmt}\n" "$@"
}

# The args() function takes a number of arguments like
#   var1="abc d" var2="abc" var3="abcd e"
# and splits them into several arguments, devided by newline
function args() {
	echo "$@" | xargs printf "%s\n"
}

function unquote() {
	local var="$@"

	if [ "${var:0:1}" = "\"" ]; then
		var=${var:1}
	fi

	local last=$(( ${#var} - 1 ))
	if [ ${last} -ge 0 ] && [ "${var:${last}:1}" = "\"" ]; then
		var=${var:0:${last}}
	fi

	print "${var}"
}

function quote() {
	print "\"%s\"" "$@"
}

function strip() {
	local value="$@"

	# remove leading whitespace characters
	value="${value#"${value%%[![:space:]]*}"}"

	# remove trailing whitespace characters
	value="${value%"${value##*[![:space:]]}"}"

	print "${value}"
}

# Print a pretty error message
function error() {
	echo -e " ${CLR_RED_B}ERROR${CLR_RESET}  : $@" >&2
}

function error_log() {
	log ERROR "$@"
}

# Print a pretty warn message
function warning() {
	echo -e " ${CLR_YELLOW_B}WARNING${CLR_RESET}: $@" >&2
}

function warning_log() {
	log WARNING "$@"
}

# The next three functions are kept for backwards
# compatibility. The need to be dropped at some time.
function listsort() {
	list_sort $@
}

function listmatch() {
	list_match $@
}

function listlength() {
	list_length $@
}

# Speedup function to avoid a call of the basename binary
function basename() {
	echo "${1##*/}"
}

function format() {
	local key=${1}
	assert isset key

	local format=${2}
	assert isset format

	shift 2

	printf -v "${key}" "${format}" "$@"
}

function assign() {
	local key=${1}
	assert isset key
	shift

	format "${key}" "%s" "$@"
}

function fread() {
	local file=${1}
	assert isset file

	[ -r "${file}" ] || return ${EXIT_ERROR}

	print "$(<${file})"
}

function fwrite() {
	local file=${1}
	assert isset file
	shift

	print "%s" "$@" >> ${file}
}

function enabled() {
	local param=${1}

	list_match "${!param}" yes on true 1
}

function mac_generate() {
	# Get a bunch of random hex digits
	# and remove all dashes from the input.
	local random=$(</proc/sys/kernel/random/uuid)
	random=${random//-/}
	assert isset random

	local output

	local i o
	for i in $(seq 0 5); do
		o="0x${random:0:2}"
		random="${random:2:${#random}}"

		case "${i}" in
			0)
				# Remove multicast bit
				# and set address is software assigned
				o=$(( ${o} & 0xfe ))
				o=$(( ${o} | 0x02 ))

				printf -v output "%02x" "${o}"
				;;
			*)
				printf -v output "%s:%02x" "${output}" "${o}"
				;;
		esac
	done

	# Check if output is valid
	assert mac_is_valid ${output}

	echo "${output}"
}

function mac_format() {
	local mac=${1}
	assert isset mac

	# Remove all colons and make the rest lowercase.
	mac=${mac//:/}
	mac=${mac,,}

	local output
	if [ "${#mac}" = "12" ]; then
		# Add colons (:) to mac address
		output=${mac:0:2}
		local i
		for i in 2 4 6 8 10; do
			output="${output}:${mac:${i}:2}"
		done
	else
		output=${mac}
	fi

	assert mac_is_valid ${output}

	print "${output}"
}

function mac_is_valid() {
	local mac=${1}

	[[ ${mac} =~ ^([0-9a-f]{2}\:){5}[0-9a-f]{2}$ ]]
}

function uuid() {
	echo $(</proc/sys/kernel/random/uuid)
}

function isset() {
	local var=${1}

	[ -n "${!var}" ]
}

function isoneof() {
	local var=${!1}
	shift

	list_match "${var}" "$@"
}

function isbool() {
	local var=${1}

	isoneof ${var} 0 1 no yes on off
}

function isinteger() {
	local var=${!1}

	[[ ${var} =~ ^[0-9]+$ ]]
}

function ismac() {
	local mac=${!1}

	mac_is_valid ${mac}
}

function isipaddress() {
	local addr=${!1}

	ip_is_valid ${addr}
}

function backtrace() {
	local start=1

	echo # Empty line
	error_log "Backtrace (most recent call in first line):"

	local i source
	for i in $(seq ${start} ${#BASH_SOURCE[*]}); do
		[ -z "${FUNCNAME[${i}]}" ] && continue
		[ "${FUNCNAME[${i}]}" == "main" ] && continue

		source=${BASH_SOURCE[$(( ${i} + 1 ))]}
		error_log "  $(printf "%20s" "'${FUNCNAME[${i}]}'") called from ${source:-<shell>}:${BASH_LINENO[${i}]}"
	done
}

function assert() {
	local assertion="$@"

	if ! ${assertion}; then
		error_log "Assertion '${assertion}' failed."
		backtrace
		exit ${EXIT_ERROR_ASSERT}
	fi

	return ${EXIT_OK}
}

# This function checks, if the given argument is an assert error
# exit code. If this is the case, the script will halt immediately.
function assert_check_retval() {
	local ret=${1}

	if [ ${ret} -eq ${EXIT_ERROR_ASSERT} ]; then
		exit ${EXIT_ERROR_ASSERT}
	fi

	return ${ret}
}

function exec_cmd() {
	local cmd=$@

	log DEBUG "Running command: ${cmd}"

	DEBUG=${DEBUG} \
	LOG_DISABLE_STDOUT="${LOG_DISABLE_STDOUT}" \
	LOG_FACILITY="${LOG_FACILITY}" \
		${SHELL} ${cmd}
	local ret=$?

	#log DEBUG "Returned with code '${ret}'"

	if [ ${ret} -eq ${EXIT_ERROR_ASSERT} ]; then
		error_log "Stopping parent process due to assertion error in child process: ${cmd}"
		exit ${EXIT_ERROR_ASSERT}
	fi

	return ${ret}
}

function cmd() {
	local cmd=$@

	log DEBUG "Running command: ${cmd}"

	${cmd}
	local ret=$?

	log DEBUG "Returned with code '${ret}'"

	return ${ret}
}

function cmd_quiet() {
	cmd $@ &>/dev/null
}

function cmd_exec() {
	local cmd=$@

	log DEBUG "Exec'ing command: ${cmd}"

	exec ${cmd}

	log ERROR "Could not exec-ute: ${cmd}"
	exit ${EXIT_ERROR}
}

function cmd_not_implemented() {
	assert false "not implemented"
}

function seq() {
	if [ $# -eq 2 ]; then
		eval echo {${1}..${2}}
	elif [ $# -eq 3 ]; then
		eval echo {${1}..${3}..${2}}
	fi
}

function which() {
	type -P $@
}

# Prints the number of seconds since epoch.
function timestamp() {
	date -u "+%s"
}

function beautify_time() {
	local value=${1}

	local unit
	local limit
	for unit in s m h d w; do
		case "${unit}" in
			s|m|h)
				limit=60
				;;
			d)
				limit=24
				;;
			w)
				limit=7
				;;
		esac

		[ ${value} -lt ${limit} ] && break

		value=$(( ${value} / ${limit} ))
	done

	echo "${value}${unit}"
}

function beautify_bytes() {
	local value=${1}

	local unit
	local limit=1024
	for unit in B k M G T; do
		[ ${value} -lt ${limit} ] && break
		value=$(( ${value} / ${limit} ))
	done

	echo "${value}${unit}"
}

function module_load() {
	local module=${1}

	if ! grep -q "^${module}" /proc/modules; then
		log DEBUG "Loading module '${module}'."
		modprobe ${module}
	fi
}

function binary_exists() {
	local binary=${1}

	if [ -n "$(type -p ${binary})" ]; then
		return ${EXIT_OK}
	fi

	return ${EXIT_ERROR}
}

function process_kill() {
	local process=${1}

	if ! isinteger process; then
		process=$(pidof ${process})
	fi

	local pid
	local sig
	for pid in ${process}; do
		for sig in 15 9; do
			[ -d "/proc/${pid}" ] || break

			kill -${sig} ${pid}
			sleep 1
		done
	done
}

function dec() {
	local hex=${1}

	if [ "${hex:0:2}" != "0x" ]; then
		hex="0x${hex}"
	fi

	printf "%d\n" "${hex}"
}

function network_is_running() {
	# Check, if the network service is running.
	service_is_active network
}

function contains_spaces() {
	local var="$@"

	# Eliminate spaces.
	local var2=${var// /}

	if [ ${#var} -ne ${#var2} ]; then
		return ${EXIT_TRUE}
	fi

	return ${EXIT_FALSE}
}