#! /bin/sh

if [ "`uname`" = SunOS -a "$_CONFIG_REEXEC_KSH" != "yes" ]; then
	_CONFIG_REEXEC_KSH=yes
	export _CONFIG_REEXEC_KSH
	exec /bin/ksh "$0" "$@"
fi

SB_UID_MIN=100
SB_GID_MIN=100
SB_USER=swtchbd
SB_GROUP=swtchbd
SB_SAFE_PATH=/bin:/usr/bin:/usr/local/bin
SB_LOG_EXEC=/var/log/swexec

FORCE_ATOMIC=""

if [ -z "$INSTALL" ]; then
	if [ -x /usr/ucb/install ]; then
		INSTALL=/usr/ucb/install
	else
		INSTALL=install
	fi
fi

CONFDIR=/etc/switchboard
PREFIX=/opt/switchboard

PHP_BIN=/usr/bin/php-cgi
for p in $(echo $PATH | tr ':' ' '); do
	if [ -x $p/php-cgi ]; then
		PHP_BIN="$p/php-cgi"
	fi
done

CC=${CC=cc}
CXX=${CXX=c++}
CFLAGS=${CFLAGS=-O}
CXXFLAGS=${CXXFLAGS=-O}

usage() {
	echo >&2 "usage: $0 [--prefix=PATH] [--confdir=PATH]"
	echo >&2 "       [--log-exec=FILE] [--safe-path=PATH] [--php-bin=FILE]"
	echo >&2 "       [--user=USER] [--group=GROUP] [--uid-min=UID] [--gid-min=GID]"
	echo >&2 "       [--boost-tag=TAG] [--atomic=TYPE]"
	echo >&2 "       [-I<path>] [-L<path>]"
	echo >&2 ''
	echo >&2 "   --prefix=PATH        Installation prefix for binary files ($PREFIX)"
	echo >&2 "   --confdir=PATH       Installation prefix for configuration files ($CONFDIR)"
	echo >&2 "   --log-exec=FILE      File to log setuid executations ($SB_LOG_EXEC)"
	echo >&2 "   --php-bin=FILE       Location of PHP CGI interpreter ($PHP_BIN)"
	echo >&2 "   --uid-min=UID        Lowest UID to allow executions ($SB_UID_MIN)"
	echo >&2 "   --gid-min=GID        Lowest GID to allow executions ($SB_GID_MIN)"
	echo >&2 "   --user=USER          User that switchboard will run as ($SB_USER)"
	echo >&2 "   --group=GROUP        Group that switchboard will run as ($SB_GROUP)"
	echo >&2 "   --safe-path=PATH     \$PATH that will be set for setuid executions ($SB_SAFE_PATH)"
	echo >&2 "   --boost-tag=TAG      Tag for Boost libraries (e.g. \"-gcc43-mt\")"
	echo >&2 "   --atomic=TYPE        Type of atomic operations: amd64_gcc, i386_gcc, gcc4, solaris or pthread"
	echo >&2 "   -I<path>             Search for include files in <path>"
	echo >&2 "   -L<path>             Search for libraries in <path>"
	echo >&2 "   -R<path>             Pass -R<path> to linker"
	echo >&2 ""
	echo >&2 "The following environment variables will influence configure's behaviour:"
	echo >&2 ""
	echo >&2 "   CC         C compiler name ($CC)"
	echo >&2 "   CXX        C++ compiler name ($CXX)"
	echo >&2 "   CPPFLAGS   Preprocessor flags ($CPPFLAGS)"
	echo >&2 "   LDFLAGS    Linker flags ($LDFLAGS)"
	echo >&2 "   CFLAGS     C compiler flags ($CFLAGS)"
	echo >&2 "   CXXFLAGS   C++ compiler flags ($CXXFLAGS)"
	echo >&2 "   INSTALL    install program ($INSTALL)"
}

while [ "$#" -gt 0 ]; do
	arg=$1; shift
	case "$arg" in
		-I*)
			rest=$(echo "$arg" | cut -c3-)
			if [ -z "$rest" ]; then
				rest=$1; shift
			fi
			CPPFLAGS="$CPPFLAGS -I$rest"
			;;
		-L*)
			rest=$(echo "$arg" | cut -c3-)
			if [ -z "$rest" ]; then
				rest=$1; shift
			fi
			LDFLAGS="$LDFLAGS -L$rest"
			;;
		-R*)
			rest=$(echo "$arg" | cut -c3-)
			if [ -z "$rest" ]; then
				rest=$1; shift
			fi
			LDFLAGS="$LDFLAGS -R$rest"
			;;
		--log-exec=*)
			path=$(echo "$arg" | sed 's/--log-exec=//')
			SB_LOG_EXEC="$path"
			;;
		--php-bin=*)
			path=$(echo "$arg" | sed 's/--php-bin=//')
			PHP_BIN="$path"
			;;
		--prefix=*)
			path=$(echo "$arg" | sed 's/--prefix=//')
			PREFIX="$path"
			;;
		--confdir=*)
			path=$(echo "$arg" | sed 's/--confdir=//')
			CONFDIR="$path"
			;;
		--safe-path=*)
			path=$(echo "$arg" | sed 's/--safe-path=//')
			SB_SAFE_PATH="$path"
			;;
		--user=*)
			path=$(echo "$arg" | sed 's/--user=//')
			SB_USER="$path"
			;;
		--group=*)
			path=$(echo "$arg" | sed 's/--group=//')
			SB_GROUP="$path"
			;;
		--uid-min=*)
			path=$(echo "$arg" | sed 's/--uid-min=//')
			SB_UID_MIN="$path"
			;;
		--gid-min=*)
			path=$(echo "$arg" | sed 's/--gid-min=//')
			SB_GID_MIN="$path"
			;;
		--boost-tag=*)
			tag=$(echo "$arg" | sed 's/--boost-tag=//')
			BOOST_TAG="$tag"
			;;
		--atomic=*)
			type=$(echo "$arg" | sed 's/--atomic=//')
			FORCE_ATOMIC="$type"
			;;
		--help)
			usage
			exit 0
			;;
		*)
			usage
			exit 1
			;;
	esac
done

rm -f config.log Makefile.config

SWEXEC_EXTRA_LIBS=""
EXTRA_LIBS=""
EXTRA_CFLAGS="$CFLAGS"
EXTRA_CXXFLAGS="$CXXFLAGS"
EXTRA_CPPFLAGS="$CPPFLAGS"
EXTRA_LDFLAGS="$LDFLAGS"

msg() {
	fmt=$1; shift
	printf "$fmt" "$@"
	printf "$fmt" "$@" >>config.log
}

msg "Using C compiler:    $CC\n"
msg "Using C++ compiler:  $CXX\n"
msg "Using CPPFLAGS:      $CPPFLAGS\n"
msg "Using CFLAGS:        $CFLAGS\n"
msg "Using CXXFLAGS:      $CXXFLAGS\n"
msg "Using LDFLAGS:       $LDFLAGS\n"
msg '\n'

try_compile_c() {
	rm -f conftest.c
	echo "$@" >conftest.c
	retval=1
	echo "$CC" $CPPFLAGS $CFLAGS conftest.c -o conftest >>config.log
	if "$CC" $CPPFLAGS $CFLAGS conftest.c -o conftest >>config.log 2>&1; then
		retval=0
	fi
	rm -f conftest.c conftest
	return $retval
}

try_compile_cxx() {
	rm -f conftest.cc
	echo "$@" >conftest.cc
	retval=1
	echo "$CXX" $CPPFLAGS $CXXFLAGS conftest.cc -o conftest >>config.log
	if "$CXX" $CPPFLAGS $CXXFLAGS conftest.cc -o conftest >>config.log 2>&1; then
		retval=0
	fi
	rm -f conftest.cc conftest
	return $retval
}

msg "checking if C compiler ($CC) works...\n"
if ! try_compile_c 'int main() { return 0; }'; then
	msg "$0: error: C compiler does not work"
	exit 1
fi

printf "checking if C++ compiler ($CXX) works...\n"
if ! try_compile_cxx 'int main() { return 0; }'; then
	msg "$0: error: C++ compiler does not work"
	exit 1
fi

check_header() {
	if [ $1 = cxx ]; then
		file=conftest.cc
	else
		file=conftest.c
	fi
	printf "#include <$2>\nint main() { return 0; }" >$file
	retval=0
	if [ $1 = cxx ]; then
		echo "$CXX" $CPPFLAGS $CXXFLAGS $file -o conftest >>config.log 
		if ! "$CXX" $CPPFLAGS $CXXFLAGS $file -o conftest >>config.log 2>&1; then
			retval=1
		fi
	else
		echo "$CC" $CPPFLAGS $CFLAGS $file -o conftest >>config.log
		if ! "$CC" $CPPFLAGS $CFLAGS $file -o conftest >>config.log 2>&1; then
			retval=1
		fi
	fi

	return $retval
}

check_func() {
	func=$1; shift
	lib=$1; shift
	if [ ! -z "$lib" ]; then
		args="-l$lib"
	fi
	printf "void $func(void); int main() { $func(); return 0; }\n" >conftest.c
	retval=0
	echo "$CC" $CPPFLAGS $CFLAGS $args conftest.c -o conftest >>config.log
	if ! "$CC" $CPPFLAGS $CFLAGS $args conftest.c -o conftest >>config.log 2>&1; then
		retval=1
	fi
	return $retval
}

check_lib() {
	lib=$1; shift
	printf "int main() { return 0; }\n" >conftest.c
	retval=0
	echo "$CC" $CPPFLAGS $CFLAGS $LDFLAGS -l$lib "$@" conftest.c -o conftest >>config.log 
	if ! "$CC" $CPPFLAGS $CFLAGS $LDFLAGS -l$lib "$@" conftest.c -o conftest >>config.log 2>&1; then
		retval=1
	fi
	return $retval
}

echo "checking for Boost..."
if ! check_header cxx boost/format.hpp; then
	msg '\n'
	msg "A required Boost header <boost/format.hpp> was not found.\n"
	msg "(See config.log for details.)\n"
	msg '\n'
	msg "Boost <http://www.boost.org> is required to compile switchboard.\n"
	msg "If you have already installed Boost, you might need to add the\n"
	msg "right -I options to configure so your compiler can find it.\n"
	exit 1
fi

if ! check_lib boost_serialization$BOOST_TAG; then
	msg '\n'
	msg "A required Boost library (-lboost_serialization) was not found.\n"
	msg "(See config.log for details.)\n"
	msg '\n'
	msg "Boost <http://www.boost.org> is required to compile switchboard.\n"
	msg "If you have already installed Boost, you might need to add the\n"
	msg "right -L options to configure so your compiler can find it.\n"
	exit 1
fi

echo "checking for Solaris projects..."
HAVE_PROJECTS=no
if check_func setproject project; then
	HAVE_PROJECTS=yes
	SWEXEC_EXTRA_LIBS="$SWEXEC_EXTRA_LIBS -lproject"
	echo "... yes"
else
	echo "... no"
fi

echo "checking for libnsl..."
if check_lib nsl; then
	EXTRA_LIBS="$EXTRA_LIBS -lnsl"
	echo "... yes"
else
	echo "... no"
fi

echo "checking for libsocket..."
if check_lib socket; then
	echo "... yes"
	EXTRA_LIBS="$EXTRA_LIBS -lsocket"
else
	echo "... no"
fi

echo "checking for atomic operations..."

if [ -z "$FORCE_ATOMIC" ]; then
	cat >conftest.c <<__EOF__
#include "swatomic.h"
int main() {
	int i = 5;
	sw_atomic_inc(&i);
	if (i == 6)
		return 0;
	return 1;
}
__EOF__
	# try gcc4 builtins
	ATOMIC_SRC="atomic_gcc4.c"
	echo "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_gcc4.c -o conftest >>config.log
	if ! "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_gcc4.c -o conftest >>config.log 2>&1; then
		# no; try amd64 asm
		ATOMIC_SRC="atomic_amd64_gcc.c"
		echo "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_amd64_gcc.c -o conftest >>config.log
		if ! "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_amd64_gcc.c -o conftest >>config.log 2>&1; then
			# no; try i386 asm
			ATOMIC_SRC="atomic_i386_gcc.c"
			echo "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_i386_gcc.c -o conftest >>config.log
			if ! "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_i386_gcc.c -o conftest >>config.log 2>&1; then
				# no; try Solaris builtins
				ATOMIC_SRC="atomic_solaris.c"
				echo "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_solaris.c -o conftest >>config.log
				if ! "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_solaris.c -o conftest >>config.log 2>&1; then
					# no; try pthreads
					ATOMIC_SRC="atomic_pthread.c"
					echo "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_pthread.c -o conftest >>config.log
					if ! "$CC" $CPPFLAGS $CFLAGS conftest.c atomic_pthread.c -o conftest >>config.log 2>&1; then
						echo >&2 "error: could not find any suitable atomics for this system"
						exit 1
					fi
				fi
			fi
		fi
	fi
else
	if [ ! -f atomic_$FORCE_ATOMIC.c ]; then
		echo >&2 "invalid atomic type: $FORCE_ATOMIC"
		exit 1
	fi

	ATOMIC_SRC=atomic_$FORCE_ATOMIC.c
fi

echo "... $ATOMIC_SRC"

echo "checking if -lpthread is required for threads..."
THREAD_LIB=""
cat >conftest.c <<__EOF__
#include <pthread.h>
void *f(void *arg) { return NULL; }
int main() {
	pthread_t tid;
	pthread_create(&tid, NULL, f, NULL);
}
__EOF__
echo "$CC" $CPPFLAGS $CFLAGS conftest.c -o conftest >>config.log
if ! "$CC" $CPPFLAGS $CFLAGS conftest.c -o conftest >>config.log 2>&1; then
	echo "$CC" $CPPFLAGS $CFLAGS conftest.c -o conftest -lpthread >>config.log
	if "$CC" $CPPFLAGS $CFLAGS conftest.c -o conftest -lpthread >>config.log 2>&1; then
		THREAD_LIB=-lpthread
		echo "... yes"
	else
		echo >&2 "error: could not find thread library."
		exit 1
	fi
else
	echo "... no"
fi

echo "checking for PAM..."
HAVE_PAM=no
if check_header c security/pam_appl.h; then
	if check_func pam_start pam; then
		echo "... yes"
		HAVE_PAM=yes
		SWEXEC_EXTRA_LIBS="$SWEXEC_EXTRA_LIBS -lpam"
	else
		echo "... no (missing pam_start)"
	fi
else
	echo "... no (missing <security/pam_appl.h>)"
fi

rm -f conftest.c conftest

rm -f setup.h

cat >setup.h <<__EOF__
/* Automatically generated by configure.  Do not edit. */
#ifndef SETUP_H
#define SETUP_H

#define SB_UID_MIN $SB_UID_MIN
#define SB_GID_MIN $SB_GID_MIN
#define SB_USER "$SB_USER"
#define SB_GROUP "$SB_GROUP"
#define SB_LOG_EXEC "$SB_LOG_EXEC"
#define SB_SAFE_PATH "$SB_SAFE_PATH"
#define PHP_BIN "$PHP_BIN"
#define PREFIX "$PREFIX"
#define CONFDIR "$CONFDIR"
__EOF__

if [ $HAVE_PROJECTS = yes ]; then
	echo "#define HAVE_PROJECTS 1" >> setup.h
fi

if [ $HAVE_PAM = yes ]; then
	echo "#define HAVE_PAM 1" >>setup.h
fi

echo "#endif" >>setup.h

echo >>Makefile.config "# Automatically generated by configure.  Do not edit."
echo >>Makefile.config "CC=$CC"
echo >>Makefile.config "CXX=$CXX"
echo >>Makefile.config "EXTRA_CPPFLAGS=$CPPFLAGS"
echo >>Makefile.config "EXTRA_LDFLAGS=$LDFLAGS"
echo >>Makefile.config "EXTRA_CFLAGS=$CFLAGS"
echo >>Makefile.config "EXTRA_CXXFLAGS=$CXXFLAGS"
echo >>Makefile.config "EXTRA_LIBS=$EXTRA_LIBS"
echo >>Makefile.config "SWEXEC_EXTRA_LIBS=$SWEXEC_EXTRA_LIBS"
echo >>Makefile.config "SB_UID_MIN=$SB_UID_MIN"
echo >>Makefile.config "SB_GID_MIN=$SB_GID_MIN"
echo >>Makefile.config "SB_USER=$SB_USER"
echo >>Makefile.config "SB_GROUP=$SB_GROUP"
echo >>Makefile.config "SB_LOG_EXEC=$SB_LOG_EXEC"
echo >>Makefile.config "SB_SAFE_PATH=$SB_SAFE_PATH"
echo >>Makefile.config "PHP_BIN=$PHP_BIN"
echo >>Makefile.config "INSTALL=$INSTALL"
echo >>Makefile.config "PREFIX=$PREFIX"
echo >>Makefile.config "CONFDIR=$CONFDIR"
echo >>Makefile.config "BOOST_TAG=$BOOST_TAG"
echo >>Makefile.config "ATOMIC_SRC=$ATOMIC_SRC"
echo >>Makefile.config "THREAD_LIB=$THREAD_LIB"
