#!/bin/sh

die() {
	printf "$1\n" >&2
	exit 1
}

usage() {
	cat <<EOF
usage: configure [options]

  --prefix=PREFIX        installation prefix [/usr]
  --exec-prefix=EPREFIX  installation prefix for executable files [PREFIX]
  --bindir=DIR           user executables [PREFIX/bin]
  --datadir=DIR          architecture-independent data files [PREFIX/share]
  --mandir=DIR           manual pages [DATADIR/man]
  --sysconfdir=DIR       directory for configuration files [/etc]
  --pamdir=DIR           PAM directory [SYSCONFDIR/pam.d]

  --build=build-alias    a cpu-vendor-opsys for the system where the application will be built
  --host=host-alias      a cpu-vendor-opsys for the system where the application will run
  --target=target-alias  the machine that CC will produce code for

  --enable-debug         enable debugging
  --enable-static        prepare for static build

  --without-pam          disable pam support
  --without-pam          disable shadow support

  --help, -h             display this help and exit
EOF
	exit 0
}

for x; do
	opt=${x%%=*}
	var=${x#*=}
	case "$opt" in
	--prefix) PREFIX=$var ;;
	--exec-prefix) EPREFIX=$var ;;
	--bindir) BINDIR=$var ;;
	--datadir) SHAREDIR=$var ;;
	--mandir) MANDIR=$var ;;
	--sysconfdir) SYSCONFDIR=$var ;;
	--pamdir) PAMDIR=$var ;;
	--build) BUILD=$var ;;
	--host) HOST=$var ;;
	--target) TARGET=$var ;;
	--enable-debug) DEBUG=yes ;;
	--enable-static) BUILD_STATIC=yes ;;
	--with-pam) WITHOUT_PAM=; WITHOUT_SHADOW=yes ;;
	--with-shadow) WITHOUT_SHADOW=; WITHOUT_PAM=yes ;;
	--without-pam) WITHOUT_PAM=yes ;;
	--without-shadow) WITHOUT_SHADOW=yes ;;
	--help|-h) usage ;;
	*) die "Error: unknown option $opt" ;;
	esac
done

CONFIG_MK=config.mk
rm -f "$CONFIG_MK"

# : ${VERSION:="$(git describe --dirty --tags --long --always)"}
: ${VERSION:="6.0"}

cat <<EOF >>$CONFIG_MK
PREFIX   ?=	${PREFIX:="/usr"}
EPREFIX  ?=	${EPREFIX:="${PREFIX}"}
BINDIR   ?=	${BINDIR:="${PREFIX}/bin"}
SHAREDIR ?=	${SHAREDIR:="${PREFIX}/share"}
MANDIR   ?=	${MANDIR:="${SHAREDIR}/man"}
SYSCONFDIR?=	${SYSCONFDIR:="/etc"}
PAMDIR   ?=	${PAMDIR:="${SYSCONFDIR}/pam.d"}
CFLAGS   +=	-DVERSION="\"${VERSION}\""
EOF

if [ -z "$BUILD" ]; then
	BUILD="$(uname -m)-unknown-$(uname -s | tr '[:upper:]' '[:lower:]')"
fi
if [ -z "$HOST" ]; then
	[ -z "$TARGET" ] && TARGET=$BUILD
	HOST=$TARGET
fi
if [ -z "$TARGET" ]; then
	[ -z "$HOST" ] && HOST=$BUILD
	TARGET=$HOST
fi

if [ -z "$OS" ]; then
	# Derive OS from cpu-manufacturer-os-kernel
	CPU=${TARGET%%-*}
	REST=${TARGET#*-}
	MANU=${REST%%-*}
	REST=${REST#*-}
	OS=${REST%%-*}
	REST=${REST#*-}
	KERNEL=${REST%%-*}
fi

OS_CFLAGS="-D__${OS}__"

case "$OS" in
	linux)
		OS_CFLAGS="$OS_CFLAGS -D_DEFAULT_SOURCE -D_GNU_SOURCE -DUID_MAX=60000 -DGID_MAX=60000"
		printf 'CURDIR   :=	.\n' >>$CONFIG_MK
		[ -z "$WITHOUT_PAM" ] && \
			printf 'PAM_DOAS  =	pam.d__doas__linux\n' >>$CONFIG_MK
		;;
esac

[ -n "$OS_CFLAGS" ] && \
	printf 'CFLAGS   +=	%s\n' "$OS_CFLAGS" >>$CONFIG_MK

[ -n "$DEBUG" ] && \
	printf 'CFLAGS   +=	-O0 -g\n' >>$CONFIG_MK

[ -n "$BUILD_STATIC" ] && \
	printf 'CFLAGS   +=	-static\n' >>$CONFIG_MK

# Add CPPFLAGS/CFLAGS/LDFLAGS to CC for testing features
XCC="${CC:=cc} $CFLAGS $OS_CFLAGS $CPPFLAGS $LDFLAGS"
# Make sure to disable --as-needed for CC tests.
XCC="$XCC -Wl,--no-as-needed"

check_func() {
	func="$1"; src="$2"; shift 2
	printf 'Checking for %-14s\t\t' "$func ..." >&2
	printf '%s\n' "$src" >"_$func.c"
	$XCC "_$func.c" -o "_$func" 2>/dev/null
	ret=$?
	rm -f "_$func.c" "_$func"
	if [ $ret -eq 0 ]; then
		printf 'yes.\n' >&2
		upperfunc="$(printf '%s\n' "$func" | tr '[[:lower:]]' '[[:upper:]]')"
		printf 'CFLAGS   +=	-DHAVE_%s\n' "$upperfunc" >>$CONFIG_MK
		return 0
	else
		printf 'no.\n' >&2
		return 1
	fi
}

authmethod() {
	#
	# Check for bsd_auth.h.
	#
	src='
#include <bsd_auth.h>
int main(void) {
	return 0;
}'
	check_func "bsd_auth_h" "$src" && {
		have_bsd_auth_h=1
		printf 'bsd\n'
		return 0
	}

	#
	# Check for pam_appl.h.
	#
	src='
#include <security/pam_appl.h>
int main(void) {
	return 0;
}'
	[ -z "$WITHOUT_PAM" ] && check_func "pam_appl_h" "$src" && {
		printf 'SRCS     +=	pam.c\n' >>$CONFIG_MK
		printf 'LDFLAGS  +=	-lpam\n' >>$CONFIG_MK
		printf 'pam\n'
		return 0
	}

	#
	# Check for shadow.h.
	#
	src='
#include <shadow.h>
int main(void) {
	return 0;
}'
	[ -z "$WITHOUT_SHADOW" ] && check_func "shadow_h" "$src" && {
		printf 'LDFLAGS  +=	-lcrypt\n' >>$CONFIG_MK
		printf 'shadow\n'
		return 0
	}

	return 1
}

#
# Check for explicit_bzero().
#
src='
#include <string.h>
int main(void) {
	explicit_bzero(NULL, 0);
	return 0;
}'
check_func "explicit_bzero" "$src" || {
	printf 'OPENBSD  +=	explicit_bzero.o\n' >>$CONFIG_MK
}

#
# Check for strlcat().
#
src='
#include <string.h>
int main(void) {
	const char s1[] = "foo";
	char s2[10];
	strlcat(s2, s1, sizeof(s2));
	return 0;
}'
check_func "strlcat" "$src" || {
	printf 'OPENBSD  +=	strlcat.o\n' >>$CONFIG_MK
}

#
# Check for strlcpy().
#
src='
#include <string.h>
int main(void) {
	const char s1[] = "foo";
	char s2[10];
	strlcpy(s2, s1, sizeof(s2));
	return 0;
}'
check_func "strlcpy" "$src" || {
	printf 'OPENBSD  +=	strlcpy.o\n' >>$CONFIG_MK
}

#
# Check for errc().
#
src='
#include <err.h>
int main(void) {
	errc(0, 0, "");
	return 0;
}'
check_func "errc" "$src" || {
	printf 'OPENBSD  +=	errc.o\n' >>$CONFIG_MK
}

#
# Check for verrc().
#
src='
#include <err.h>
int main(void) {
	verrc(0, 0, "");
	return 0;
}'
check_func "verrc" "$src" || {
	printf 'OPENBSD  +=	verrc.o\n' >>$CONFIG_MK
}

#
# Check for setprogname().
#
src='
#include <stdlib.h>
int main(void) {
	setprogname("");
	return 0;
}'
check_func "setprogname" "$src" || {
	printf 'OPENBSD  +=	progname.o\n' >>$CONFIG_MK
}

#
# Check for readpassphrase().
#
src='
#include <readpassphrase.h>
int main(void) {
	char buf[12];
	readpassphrase("", buf, sizeof(buf), 0);
	return 0;
}'
check_func "readpassphrase" "$src" || {
	printf 'OPENBSD  +=	readpassphrase.o\n' >>$CONFIG_MK
}

#
# Check for strtonum().
#
src='
#include <stdlib.h>
int main(void) {
	const char *errstr;
	strtonum("", 1, 64, &errstr);
	return 0;
}'
check_func "strtonum" "$src" || {
	printf 'OPENBSD  +=	strtonum.o\n' >>$CONFIG_MK
}

#
# Check for reallocarray().
#
src='
#include <stdlib.h>
int main(void) {
	reallocarray(NULL, 0, 0);
	return 0;
}'
check_func "reallocarray" "$src" || {
	printf 'OPENBSD  +=	reallocarray.o\n' >>$CONFIG_MK
}

#
# Check for execvpe().
#
src='
#include <unistd.h>
int main(void) {
	const char *p = { "", NULL };
	execvpe("", p, p);
	return 0;
}'
check_func "execvpe" "$src" || {
	printf 'OPENBSD  +=	execvpe.o\n' >>$CONFIG_MK
}

#
# Check for setresuid().
#
src='
#include <unistd.h>
int main(void) {
	setresuid(0, 0, 0);
	return 0;
}'
check_func "setresuid" "$src" || {
	printf 'OPENBSD  +=	setresuid.o\n' >>$CONFIG_MK
}

#
# Check for pledge().
#
src='
#include <unistd.h>
int main(void) {
	pledge("", NULL);
	return 0;
}'
check_func "pledge" "$src" || {
	printf 'OPENBSD  +=	pledge-noop.o\n' >>$CONFIG_MK
}

#
# Check for closefrom().
#
src='
#include <unistd.h>
int main(void) {
	closefrom(0);
	return 0;
}'
check_func "closefrom" "$src" || {
	printf 'OPENBSD  +=	closefrom.o\n' >>$CONFIG_MK
}

#
# Check for sysconf().
#
src='
#include <unistd.h>
int main(void) {
	(void)sysconf(0);
	return 0;
}'
check_func "sysconf" "$src"

#
# Check for /proc/$PID.
#
printf 'Checking for %-14s\t\t' "/proc/\$PID ..." >&2
if test -d /proc/$$; then
	printf 'yes.\n' >&2
	printf 'CFLAGS   +=	-DHAVE_%s\n' "PROC_PID" >>$CONFIG_MK
else
	printf 'no.\n' >&2
fi

#
# Check for dirfd().
#
src='
#include <dirent.h>
int main(void) {
	(void)dirfd(0);
	return 0;
}'
check_func "dirfd" "$src"

#
# Check for fcntl.h.
#
src='
#include <fcntl.h>
int main(void) {
	return 0;
}'
check_func "fcntl_h" "$src"

#
# Check for F_CLOSEM.
#
src='
#include <fcntl.h>
#ifndef F_CLOSEM
#error no F_CLOSEM
#endif
int main(void) {
	return 0;
}'
check_func "F_CLOSEM" "$src"

#
# Check for dirent.h.
#
src='
#include <dirent.h>
int main(void) {
	return 0;
}'
check_func "dirent_h" "$src"

#
# Check for sys/ndir.h.
#
src='
#include <sys/ndir.h>
int main(void) {
	return 0;
}'
check_func "sys_ndir_h" "$src"

#
# Check for sys/dir.h.
#
src='
#include <sys/dir.h>
int main(void) {
	return 0;
}'
check_func "sys_dir_h" "$src"

#
# Check for ndir.h.
#
src='
#include <ndir.h>
int main(void) {
	return 0;
}'
check_func "ndir_h" "$src"

#
#
#
src='
#include <stdlib.h>
int main(void){return 0;}
__attribute__((__unused__)) static void foo(void){return;}
'
check_func "__attribute__" "$src" || {
	printf 'CFLAGS	+=	-DNO_ATTRIBUTE_ON_RETURN_TYPE=1\n' >>$CONFIG_MK
}

auth=$(authmethod)
if [ $? -eq 0 ]; then
	printf 'Using auth method\t\t\t%s.\n' "$auth" >&2
else
	printf 'Error auth method\t\t\n' >&2
	exit 1
fi
