[sanewall-dev] [PATCH] Detect commands at configure-time not run-time

Phil Whineray phil at sanewall.org
Sun May 12 21:59:04 CEST 2013


 - Enable GNU autotools ./configure script to select programs
   including alternates where available but allowing unconfigured
   operation for developer benefit

 - Remove wget_cmd which was only used by the ECN shame helper and
   which is no longer available

 - Tidied up based on feedback
---
 configure.ac     |   47 ++++++++
 sbin/sanewall.in |  334 ++++++++++++------------------------------------------
 2 files changed, 117 insertions(+), 264 deletions(-)

Hi

Version 2 of the same patch, based on Jerome's feedback:

> 1] the AC_SUBST([XXXX_CMD]) are redundant;

They have been removed, as suggested.

> 2] AC_PROG_AWK, AC_PROG_GREP and alike may be favoured:
> http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Particular-Programs.html#Particular-Programs

These are now used where available. The AC_PROG_AWK has different behaviour
to the others though - it does not include the path to the exe. Is that
expected?

I have not used the AC_MKDIR_P since that would require checking and
changing all of the calling sites also. Maybe a separate patch later.

> 3] a room for bzcat and xzcat may be anticipated.

The use of this command in Sanewall is to check the kernel's
/proc/config.gz file, if present. I don't think the other programs
will be beneficial unless the kernel starts to support those schemes.

Cheers
Phil

diff --git a/configure.ac b/configure.ac
index 0306812..046360b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,6 +28,53 @@ fi
 SANEWALL_CONFIG_DIR=$(eval echo "$sysconfdir/sanewall" | sed -e 's|^NONE|/usr/local|')
 AC_SUBST(SANEWALL_CONFIG_DIR)
 
+AC_PROG_AWK()
+AC_PATH_PROG([CAT_CMD], [cat], [])
+AC_PATH_PROG([CHMOD_CMD], [chmod], [])
+AC_PATH_PROG([CHOWN_CMD], [chown], [])
+AC_PATH_PROG([CUT_CMD], [cut], [])
+AC_PATH_PROG([DATE_CMD], [date], [])
+AC_PATH_PROG([EGREP_CMD], [egrep], [])
+AC_PATH_PROG([EXPR_CMD], [expr], [])
+AC_PATH_PROG([FIND_CMD], [find], [])
+AC_PATH_PROG([FOLD_CMD], [fold], [])
+AC_PROG_GREP()
+AC_PATH_PROG([HEAD_CMD], [head], [])
+AC_PATH_PROG([HOSTNAME_CMD], [hostname], [])
+AC_PATH_PROGS([INSMOD_CMD], [modprobe insmod], [])
+AC_PATH_PROG([IP6TABLES_CMD], [ip6tables], [])
+AC_PATH_PROG([IP_CMD], [ip], [])
+AC_PATH_PROG([IP6TABLES_RESTORE_CMD], [ip6tables-restore], [], [$PATH:/sbin])
+AC_PATH_PROG([IP6TABLES_SAVE_CMD], [ip6tables-save], [], [$PATH:/sbin])
+AC_PATH_PROG([IPTABLES_CMD], [iptables], [], [$PATH:/sbin])
+AC_PATH_PROG([IPTABLES_RESTORE_CMD], [iptables-restore], [], [$PATH:/sbin])
+AC_PATH_PROG([IPTABLES_SAVE_CMD], [iptables-save], [], [$PATH:/sbin])
+AC_PATH_PROG([LOGGER_CMD], [logger], [])
+AC_PATH_PROG([LSMOD_CMD], [lsmod], [], [$PATH:/sbin])
+AC_PATH_PROG([MKDIR_CMD], [mkdir], [])
+AC_PATH_PROG([MV_CMD], [mv], [])
+AC_PATH_PROGS([PAGER_CMD], [pager less more cat], [])
+AC_PATH_PROG([RENICE_CMD], [echo], [:])
+AC_PATH_PROG([RM_CMD], [rm], [])
+AC_PROG_SED()
+AC_PATH_PROG([SORT_CMD], [sort], [])
+AC_PATH_PROG([SS_CMD], [ss], [])
+AC_PATH_PROG([SYSCTL_CMD], [sysctl], [], [$PATH:/sbin])
+AC_PATH_PROG([TOUCH_CMD], [touch], [])
+AC_PATH_PROG([TR_CMD], [tr], [])
+AC_PATH_PROG([UNAME_CMD], [uname], [])
+AC_PATH_PROG([UNIQ_CMD], [uniq], [])
+AC_PATH_PROGS([ZCAT_CMD], [zcat gzcat gunzip gzip], [])
+AC_CHECK_PROGS([ZCAT_PROG], [zcat gzcat gunzip gzip], [])
+ZCAT_OPTS=
+if test "z$ZCAT_PROG" = zgunzip; then
+ZCAT_OPTS="-c"
+fi
+if test "z$ZCAT_PROG" = zgzip; then
+ZCAT_OPTS="-d -c"
+fi
+AC_SUBST(ZCAT_OPTS)
+
 AC_CONFIG_FILES([
 	Makefile
 	sbin/Makefile
diff --git a/sbin/sanewall.in b/sbin/sanewall.in
index 27ae0b7..f0c8500 100755
--- a/sbin/sanewall.in
+++ b/sbin/sanewall.in
@@ -110,236 +110,80 @@ both() {
 
 export PATH="${PATH}:/bin:/usr/bin:/sbin:/usr/sbin"
 
-# External commands sanewall will need.
-# If one of those is not found, sanewall will refuse to run.
-
-which_cmd() {
-	local block=1
-	if [ "a${1}" = "a-n" ]
+# Set the environment variable to the value given, unless the value
+# starts with an @ (./configure has not been run). In that case, try
+# to use the built-in default but verify it can be found with "which".
+set_or_def() {
+	if [ "$1" = "-n" ]; then local notreq="Y"; shift; fi
+	if [ "$(echo $2 | grep '^@')" ]
 	then
-		local block=0
-		shift
-	fi
-
-	unalias $2 >/dev/null 2>&1
-	local cmd=`which $2 2>/dev/null | head -n 1`
-	if [ $? -gt 0 -o ! -x "${cmd}" ]
-	then
-		if [ ${block} -eq 1 ]
+		exe="$(which $3)"
+		if [ "$exe" ]
 		then
-			echo >&2
-			echo >&2 "ERROR:	Command '$2' not found in the system path."
-			echo >&2 "	Sanewall requires this command for its operation."
-			echo >&2 "	Please install the required package and retry."
-			echo >&2
-			echo >&2 "	Note that you need an operational 'which' command"
-			echo >&2 "	for sanewall to find all the external programs it"
-			echo >&2 "	needs. Check it yourself. Run:"
-			echo >&2
-			echo >&2 "	which $2"
-			exit 1
-		fi
-		return 1
-	fi
-
-	eval $1=${cmd}
-	return 0
-}
-
-# command on demand support.
-require_cmd() {
-	local block=1
-	if [ "a$1" = "a-n" ]
-	then
-		local block=0
-		shift
-	fi
-
-	# if one is found, return success
-	for x in "${@}"
-	do
-		eval var=`echo ${x} | tr 'a-z' 'A-Z'`_CMD
-		eval val=\$\{${var}\}
-		if [ -z "${val}" ]
+			eval "$1=$exe"
+		elif [ "$notreq" ]
 		then
-			which_cmd -n "${var}" "${x}"
-			test $? -eq 0 && return 0
+			eval "$1=$3"
+		else
+			echo "Missing required command: $1 (default $3)"
+			exit 1
 		fi
-	done
-
-	if [ $block -eq 1 ]
-	then
-		echo >&2
-		echo >&2 "ERROR:	SANEWALL REQUIRES THESE COMMANDS:"
-		echo >&2
-		echo >&2 "	${@}"
-		echo >&2
-		echo >&2 "	You have requested the use of an optional sanewall"
-		echo >&2 "	feature that requires certain external programs"
-		echo >&2 "	to be installed in the running system."
-		echo >&2
-		echo >&2 "	Please consult your Linux distribution manual to"
-		echo >&2 "	install the package(s) that provide these external"
-		echo >&2 "	programs and retry."
-		echo >&2
-		echo >&2 "	Note that you need an operational 'which' command"
-		echo >&2 "	for sanewall to find all the external programs it"
-		echo >&2 "	needs. Check it yourself. Run:"
-		echo >&2
-		for x in "${@}"
-		do
-			echo >&2 "	which $x"
-		done
-
-		exit 1
-	fi
-
-	return 1
-}
-
-# Currently the following commands are required only when needed.
-# (i.e. Command on Demand)
-#
-# wget or curl (either is fine)
-# zcat or gzcat or gzip (either or none is fine)
-# less or more (either or none is fine)
-# ip
-# ss
-# date
-# hostname
-# modprobe or insmod
-# gawk or awk
-# nice (none is fine)
-
-# Commands that are mandatory for sanewall operation:
-which_cmd CAT_CMD cat
-which_cmd CUT_CMD cut
-which_cmd CHOWN_CMD chown
-which_cmd CHMOD_CMD chmod
-which_cmd EGREP_CMD egrep
-which_cmd EXPR_CMD expr
-which_cmd FIND_CMD find
-which_cmd FOLD_CMD fold
-which_cmd GREP_CMD grep
-which_cmd HEAD_CMD head
-which_cmd LSMOD_CMD lsmod
-which_cmd MKDIR_CMD mkdir
-which_cmd MV_CMD mv
-which_cmd RM_CMD rm
-which_cmd SED_CMD sed
-which_cmd SORT_CMD sort
-which_cmd SYSCTL_CMD sysctl
-which_cmd TOUCH_CMD touch
-which_cmd TR_CMD tr
-which_cmd UNAME_CMD uname
-which_cmd UNIQ_CMD uniq
-which_cmd LOGGER_CMD logger
-
-if [ "${IPVER}" = "both" -o  "${IPVER}" = "ipv4" ]
-then
-	which_cmd IPTABLES_CMD iptables
-	which_cmd IPTABLES_SAVE_CMD iptables-save
-	which_cmd IPTABLES_RESTORE_CMD iptables-restore
-fi
-
-if [ "${IPVER}" = "both" -o  "${IPVER}" = "ipv6" ]
-then
-	which_cmd IP6TABLES_CMD ip6tables
-	which_cmd IP6TABLES_SAVE_CMD ip6tables-save
-	which_cmd IP6TABLES_RESTORE_CMD ip6tables-restore
-fi
-
-# Special commands
-pager_cmd() {
-	if [ -z "${LESS_CMD}" ]
-	then
-		require_cmd -n less more
-		test -z "${LESS_CMD}" && LESS_CMD="${MORE_CMD}"
-		test -z "${LESS_CMD}" && LESS_CMD="${CAT_CMD}"
-	fi
-
-	"${LESS_CMD}" "${@}"
-}
-
-zcat_cmd() {
-	require_cmd -n zcat gzcat gzip
-	test -z "${ZCAT_CMD}" && ZCAT_CMD="${GZCAT_CMD}"
-
-	if [ ! -z "${ZCAT_CMD}" ]
-	then
-		"${ZCAT_CMD}" "${@}"
-		return $?
-	elif [ ! -z "${GZIP_CMD}" ]
-	then
-		"${CAT_CMD}" "${@}" | "${GZIP_CMD}" -dc
-		return $?
+	else
+		eval "$1='$2'"
 	fi
-
-	echo >&2 " "
-	echo >&2 " IMPORTANT WARNING:"
-	echo >&2 " ------------------"
-	echo >&2 " Sanewall cannot find any of the commands: zcat, gzcat, gzip."
-	echo >&2 " Make sure you have one of these available in the system path."
-	echo >&2 " "
-
-	return 1
 }
 
-gawk_cmd() {
-	require_cmd -n gawk awk
-	test -z "${GAWK_CMD}" && GAWK_CMD="${AWK_CMD}"
-
-	if [ ! -z "${GAWK_CMD}" ]
-	then
-		"${GAWK_CMD}" "${@}"
-		return $?
-	fi
-
-	echo >&2 " "
-	echo >&2 " IMPORTANT WARNING:"
-	echo >&2 " ------------------"
-	echo >&2 " Sanewall cannot find any of the commands: gawk, awk."
-	echo >&2 " Make sure you have one of these available in the system path."
-	echo >&2 " "
-
-	return 1
+set_or_def AWK_CMD "@AWK@" "awk"
+set_or_def CAT_CMD "@CAT_CMD@" "cat"
+set_or_def CHMOD_CMD "@CHMOD_CMD@" "chmod"
+set_or_def CHOWN_CMD "@CHOWN_CMD@" "chown"
+set_or_def CUT_CMD "@CUT_CMD@" "cut"
+set_or_def DATE_CMD "@DATE_CMD@" "date"
+set_or_def EGREP_CMD "@EGREP_CMD@" "egrep"
+set_or_def EXPR_CMD "@EXPR_CMD@" "expr"
+set_or_def FIND_CMD "@FIND_CMD@" "find"
+set_or_def FOLD_CMD "@FOLD_CMD@" "fold"
+set_or_def GREP_CMD "@GREP@" "grep"
+set_or_def HEAD_CMD "@HEAD_CMD@" "head"
+set_or_def INSMOD_CMD "@INSMOD_CMD@" "insmod"
+set_or_def IP6TABLES_CMD "@IP6TABLES_CMD@" "ip6tables"
+set_or_def IP6TABLES_RESTORE_CMD "@IP6TABLES_RESTORE_CMD@" "ip6tables-restore"
+set_or_def IP6TABLES_SAVE_CMD "@IP6TABLES_SAVE_CMD@" "ip6tables-save"
+set_or_def IPTABLES_CMD "@IPTABLES_CMD@" "iptables"
+set_or_def IPTABLES_RESTORE_CMD "@IPTABLES_RESTORE_CMD@" "iptables-restore"
+set_or_def IPTABLES_SAVE_CMD "@IPTABLES_SAVE_CMD@" "iptables-save"
+set_or_def LOGGER_CMD "@LOGGER_CMD@" "logger"
+set_or_def LSMOD_CMD "@LSMOD_CMD@" "lsmod"
+set_or_def MKDIR_CMD "@MKDIR_CMD@" "mkdir"
+set_or_def MV_CMD "@MV_CMD@" "mv"
+set_or_def PAGER_CMD "@PAGER_CMD@" "cat"
+set_or_def RENICE_CMD "@RENICE_CMD@" "echo"
+set_or_def RM_CMD "@RM_CMD@" "rm"
+set_or_def SED_CMD "@SED@" "sed"
+set_or_def SORT_CMD "@SORT_CMD@" "sort"
+set_or_def SYSCTL_CMD "@SYSCTL_CMD@" "sysctl"
+set_or_def TOUCH_CMD "@TOUCH_CMD@" "touch"
+set_or_def TR_CMD "@TR_CMD@" "tr"
+set_or_def UNAME_CMD "@UNAME_CMD@" "uname"
+set_or_def UNIQ_CMD "@UNIQ_CMD@" "uniq"
+set_or_def ZCAT_CMD "@ZCAT_CMD@" "zcat"
+set_or_def -n ZCAT_OPTS "@ZCAT_OPTS@" ""
+
+extra_wizard_commands() {
+	set_or_def IP_CMD "@IP_CMD@" "ip"
+	set_or_def SS_CMD "@SS_CMD@" "ss"
+	set_or_def HOSTNAME_CMD "@HOSTNAME_CMD@" "hostname"
 }
 
 modprobe_cmd() {
-	require_cmd -n modprobe insmod
-	test -z "${MODPROBE_CMD}" && MODPROBE_CMD="${INSMOD_CMD}"
-
-	if [ ! -z "${MODPROBE_CMD}" ]
+	"${INSMOD_CMD}" "${@}"
+	status=$?
+	if [ $status -eq 17 ]
 	then
-		"${MODPROBE_CMD}" "${@}"
-		status=$?
-		if [ $status -eq 17 ]
-		then
-			# insmod: module already loaded - not a problem
-			return 0
-		else
-			return $status
-		fi
-	fi
-
-	echo >&2 " "
-	echo >&2 " IMPORTANT WARNING:"
-	echo >&2 " ------------------"
-	echo >&2 " Sanewall cannot find any of the commands: modprobe, insmod."
-	echo >&2 " Make sure you have one of these available in the system path."
-	echo >&2 " "
-
-	return 1
-}
-
-renice_cmd() {
-	if [ -z "${RENICE_CMD}" ]
-	then
-		require_cmd -n renice
-		test -z "${RENICE_CMD}" && RENICE_CMD=":"
+		# insmod: module already loaded - not a problem
+		return 0
 	fi
-
-	"${RENICE_CMD}" "${@}"
+	return $status
 }
 
 iptables_cmd() {
@@ -576,35 +420,21 @@ sanewall_concurrent_run_lock() {
 umask 077
 
 # Be nice on production environments
-renice_cmd 10 $$ >/dev/null 2>/dev/null
+${RENICE_CMD} 10 $$ >/dev/null 2>/dev/null
 
 # Use the old, static FIREHOL minor version
 FIREHOL_MINOR_VERSION=257
 
 if [ "${IPVER}" = "ipv6" ]
 then
-  list="IP6TABLES_CMD IP6TABLES_SAVE_CMD IP6TABLES_RESTORE_CMD"
   TABLES="/proc/net/ip6_tables_names"
 elif [ "${IPVER}" = "ipv4" ]
 then
-  list="IPTABLES_CMD IPTABLES_SAVE_CMD IPTABLES_RESTORE_CMD"
   TABLES="/proc/net/ip_tables_names"
 else
-  list="IPTABLES_CMD IPTABLES_SAVE_CMD IPTABLES_RESTORE_CMD IP6TABLES_CMD IP6TABLES_SAVE_CMD IP6TABLES_RESTORE_CMD"
   TABLES="/proc/net/ip_tables_names /proc/net/ip6_tables_names"
 fi
 
-for check in $list
-do
-        checkname=`echo $check | ${SED_CMD} -e 's/_CMD$//' | ${TR_CMD} A-Z_ a-z-`
-	eval checkenv=\$$check
-	if [ -z "${checkenv}" -o ! -x "${checkenv}" ]; then
-		echo >&2 "Cannot find an executable ${checkname} command."
-		exit 0
-	fi
-done
-
-
 # Initialize iptables
 iptables_cmd -nxvL >/dev/null 2>&1
 
@@ -648,7 +478,7 @@ else
 fi
 
 # The default configuration file, it can be changed on the command line
-SANEWALL_CONFIG_DIR="@SANEWALL_CONFIG_DIR@"
+set_or_def -n SANEWALL_CONFIG_DIR "@SANEWALL_CONFIG_DIR@" "/etc/sanewall"
 SANEWALL_CONFIG="${SANEWALL_CONFIG_DIR}/sanewall.conf"
 
 
@@ -2628,26 +2458,6 @@ cd "${SANEWALL_DEFAULT_WORKING_DIRECTORY}" || exit 1
 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 # ------------------------------------------------------------------------------
 
-# Fetch a URL and output it to the standard output.
-sanewall_wget() {
-	local url="${1}"
-
-	require_cmd wget curl
-
-	if [ ! -z "${WGET_CMD}" ]
-	then
-		${WGET_CMD} -O - "${url}" 2>/dev/null
-		return $?
-	elif [ ! -z "${CURL_CMD}" ]
-	then
-		${CURL_CMD} -s "${url}"
-		return $?
-	fi
-
-	error "Cannot use either 'wget' or 'curl' to fetch '${url}'."
-	return 1
-}
-
 ecn_shame() {
 	softwarning "ECN_SHAME IP list no longer available, helper is ignored."
 	return 0
@@ -3595,7 +3405,7 @@ fi
 if [ -z "${KERNEL_CONFIG}" -a -f "/proc/config.gz" ]
 then
 	KERNEL_CONFIG="/proc/config.gz"
-	zcat_cmd /proc/config.gz >"${SANEWALL_DIR}/kcfg" || KERNEL_CONFIG=
+	${ZCAT_CMD} ${ZCAT_OPTS} /proc/config.gz >"${SANEWALL_DIR}/kcfg" || KERNEL_CONFIG=
 fi
 
 if [ -z "${KERNEL_CONFIG}" -a -f "/lib/modules/`${UNAME_CMD} -r`/build/.config" ]
@@ -6206,10 +6016,10 @@ wait_for_interface() {
 		timeout=$1
 	fi
 
-	local start=`date +%s`
+	local start=`${DATE_CMD} +%s`
 	local found=0
 
-	while [ "`date +%s`" -lt $(($start+$timeout)) -a $found -eq 0 ]
+	while [ "`${DATE_CMD} +%s`" -lt $(($start+$timeout)) -a $found -eq 0 ]
 	do
 		local addr=`ip addr show $iface 2> /dev/null | awk '$1 ~ /^inet$/ {print $2}'`
 		if [ -n "$addr" ]
@@ -6386,7 +6196,7 @@ case "${arg}" in
 			echo "--- FILTER ---------------------------------------------------------------------"
 			echo
 			iptables_cmd -nxvL
-		) | pager_cmd
+		) | ${PAGER_CMD}
 		exit $?
 		;;
 
@@ -6796,11 +6606,7 @@ fi
 
 if [ "${SANEWALL_MODE}" = "WIZARD" ]
 then
-	# require commands for wizard mode
-	require_cmd ip
-	require_cmd ss
-	require_cmd date
-	require_cmd hostname
+	extra_wizard_commands
 
 	wizard_ask() {
 		local prompt="${1}"; shift
@@ -7638,7 +7444,7 @@ EOF
 
 # at the same time, replace all full iptables/ip6tables references with our
 # versions to protect the currently running firewall
-${CAT_CMD} ${SANEWALL_CONFIG} | ${SED_CMD} -e "s|${IPTABLES_CMD}|ipv4 iptables|g" -e "s|${IP6TABLES_CMD}|ipv6 iptables|g" | gawk_cmd -f "${SANEWALL_TMP}.awk" >${SANEWALL_TMP}
+${CAT_CMD} ${SANEWALL_CONFIG} | ${SED_CMD} -e "s|${IPTABLES_CMD}|ipv4 iptables|g" -e "s|${IP6TABLES_CMD}|ipv6 iptables|g" | ${AWK_CMD} -f "${SANEWALL_TMP}.awk" >${SANEWALL_TMP}
 ${RM_CMD} -f "${SANEWALL_TMP}.awk"
 
 # ------------------------------------------------------------------------------
-- 
1.7.9.5

-- 
http://www.sanewall.org/
Sanewall - making sense of firewalling


More information about the Sanewall-Dev mailing list