#!/bin/bash
# Allow user overrides of configuration options.
#
# Oracle Linux DTrace.
# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.

set -e

# We write everything to temporary files first, then rename them atomically
# into their final resting places once everything has completed, to avoid
# partial results in case of error.

# config-vars.mk is cheap to reproduce, so it's written out as a unit.
write_make_var()
{
    local val="$(printf "%s" "$2" | sed 's,^.*=,,')"

    if [[ ! -f build/.config-vars.mk.new ]]; then
        echo '# This file is automatically generated.' > build/.config-vars.mk.new
    fi

    printf '%s=%s\n' $1 "$val" >> build/.config-vars.mk.new
    printf "override CONFIGURED_VARS+=%s\n" $1 >> build/.config-vars.mk.new
}

# Write out build/.config/*.mk and build/.config/*.h, which are the same
# things written out by the Makeconfig fragments: each corresponds to one
# test, to minimize test reinvocations, since config.mk tests can be quite
# expensive to run.

write_config_var()
{
    local val="$(printf "%s" "$2" | sed 's,^.*=,,')"

    if [[ ! -d build/.config.new ]]; then
       mkdir -p build/.config.new
       touch build/.config.new/.dir.stamp
    fi

    case $val in
        no) printf '# HAVE_%s undefined\n' $1 > build/.config.new/config.$1.mk
            printf '/* #undef HAVE_%s */\n' $1 > build/.config.new/config.$1.h;;
        yes|'') printf 'HAVE_%s=y\n' $1 > build/.config.new/config.$1.mk
                printf '#define HAVE_%s 1\n' $1 > build/.config.new/config.$1.h;;
    esac
}

help()
{
	cat >&2 <<'EOF'
Installation paths:

--prefix=/usr					Prefix of all installed paths
--objdir=build					Build directory
--libdir=PREFIX/lib64				Library directory
--bindir=PREFIX/sbin				Binary directory
--sbindir=PREFIX/sbin				Alias for --bindir
--includedir=PREFIX/include			#include directory
--mandir=PREFIX/share/man			Manpage directory
--pkg-config-dir=PREFIX/share/pkgconfig		Pkg-config directory
--udevdir=PREFIX/lib/udev/rules.d		udev rules directory
--systemd-unit-dir=PREFIX/lib/systemd/system	systemd unit directory
--docdir=PREFIX/share/doc/dtrace		Documentation directory
--testdir=LIBDIR/dtrace/testsuite		Testsuite install directory

Options relating to the user environment (may need customization on
some systems, see GNUmakefile)

--user-uid=UID			The first non-system uid on the system
--dumpcap-group=GROUP		Group one must run as to invoke $DUMPCAP
--unpriv-uid=UID		A uid suitable for unprivileged processes;
				may be negative
--unpriv-home=/run/initramfs	Non-writable directory to use as $HOME for
				unprivileged processes

Options relating to kernels (for local builds against a running kernel
built locally, none of these should be needed):

--kernels="6.1 6.2 6.3"		Space-separated list of kernel versions to
				produce translators for
--kernel-mod-dir=DIR		Directory used to search for kernel build trees
				(default "/lib/modules")
--kernel-src-dir=DIR		Source location of kernel tree for local builds
--kernel-obj-dir=DIR		Kernel object directory (as passed to O=)
--kernel-src-suffix=DIR		If --kernel-src-dir is not set, suffix of kernel
				source directory (after kernel version) (default
				"source"); seen under /lib/modules
--kernel-obj-suffix=DIR		If --kernel-obj-dir is not set, suffix of kernel
				object directory (after kernel version) (default
				"build"); seen under /lib/modules

EOF
        make help-overrides-header help-overrides-option
        cat >&2 <<'EOF'
--with-systemd=[yes/no]		Install the systemd unit files (default: yes)
EOF
        echo >&2
        make help-overrides
        cat >&2 <<'EOF'

Options controlling the compiler (pass on the command line):

CC				C compiler (may be a cross-compiler)
CPP				Preprocessor, by default $(CC) -E
CPPFLAGS			Preprocessor flags
CFLAGS				Compiler flags
LDFLAGS				Linker flags
BPFC				Cross-compiler to BPF
BPFCPPFLAGS			BPF C preprocessor flags
BPFCFLAGS			BPF C compiler flags
BPFLD				BPF linker

If passed to configure as command-line arguments, all the variables
above stick for future make invocations until "make clean".

EOF
}

[[ ! -d build ]] && mkdir -p build
rm -rf build/.config.new build/.config-vars.mk.new
echo 'override CONFIGURED_VARS=' > build/.config-vars.mk.new
trap 'rm -rf build/.config.new build/.config-vars.mk.new' ERR

for option in "$@"; do
    case "$option" in
        --help) help; exit 1;;
        --prefix=*) write_make_var prefix "$option";;
        --objdir=*) write_make_var objdir "$option";;
        --libdir=*) write_make_var LIBDIR "$option";;
        --bindir=*) write_make_var SBINDIR "$option";;
        --sbindir=*) write_make_var SBINDIR "$option";;
        --includedir=*) write_make_var INCLUDEDIR "$option";;
        --udevdir=*) write_make_var UDEVDIR "$option";;
        --systemd-unit-dir=*) write_make_var SYSTEMDUNITDIR "$option";;
        --docdir=*) write_make_var DOCDIR "$option";;
        --mandir=*) write_make_var MANDIR "$option";;
        --pkg-config-dir=*) write_make_var PKGCONFIGDIR "$option";;
        --testdir=*) write_make_var TESTDIR "$option";;
        CC=*) write_make_var CC "$option";;
        CPP=*) write_make_var PREPROCESS "$option";;
        CFLAGS=*) write_make_var CFLAGS "$option";;
        CPPFLAGS=*) write_make_var CPPFLAGS "$option";;
        LDFLAGS=*) write_make_var LDFLAGS "$option";;
        BPFC=*) write_make_var BPFC "$option";;
        BPFCPPFLAGS=*) write_make_var BPFCPPFLAGS "$option";;
        BPFCFLAGS=*) write_make_var BPFCFLAGS "$option";;
        BPFLD=*) write_make_var BPFLD "$option";;
        --user-uid=*) write_make_var USER_UID "$option";;
        --dumpcap-group=*) write_make_var DUMPCAP_GROUP "$option";;
        --unpriv-uid=*) write_make_var UNPRIV_UID "$option";;
        --unpriv-home=*) write_make_var UNPRIV_HOME "$option";;
        --kernels=*) write_make_var KERNELS "$option";;
        --kernel-mod-dir=*) write_make_var KERNELMODDIR "$option";;
        --kernel-src-dir=*) write_make_var KERNELSRCDIR "$option";;
        --kernel-obj-dir=*) write_make_var KERNELOBJDIR "$option";;
        --kernel-src-suffix=*) write_make_var KERNELSRCNAME "$option";;
        --kernel-obj-suffix=*) write_make_var KERNELBLDNAME "$option";;
        --with-systemd|--with-systemd=y*) write_make_var WITH_SYSTEMD "y";;
        --with-systemd=n*|--without-systemd) write_make_var WITH_SYSTEMD "";;
        HAVE_ELF_GETSHDRSTRNDX=*) write_config_var ELF_GETSHDRSTRNDX "$option";;
        --with-libctf=*) write_config_var LIBCTF "$option";;
        HAVE_LIBCTF=*) write_config_var LIBCTF "$option";;
        HAVE_STRRSTR=*) write_config_var STRRSTR "$option";;
        HAVE_FUSE_LOG=*) write_config_var FUSE_LOG "$option";;
        --with-libfuse3=*) write_config_var LIBFUSE3 "$option";;
        HAVE_LIBFUSE3=*) write_config_var LIBFUSE3 "$option";;
        HAVE_FUSE_NUMA=*) write_config_var FUSE_NUMA "$option";;
        HAVE_CLOSE_RANGE=*) write_config_var CLOSE_RANGE "$option";;
        HAVE_GETTID=*) write_config_var GETTID "$option";;
        HAVE_VALGRIND=*) write_config_var VALGRIND "$option";;
        HAVE_BPFV3=*) write_config_var BPFV3 "$option";;
        HAVE_BPFMASM=*) write_config_var BPFMASM "$option";;
        *) echo "Unknown option $option" >&2
           exit 1;;
    esac
done

echo 'Writing build/config-vars.mk'
rm -f build/config-vars.mk
mv -f build/.config-vars.mk.new build/config-vars.mk

rm -rf build/.config
[[ ! -d build/.config.new ]] && \
  mkdir -p build/.config.new && \
  touch build/.config.new/empty.h build/.config.new/empty.mk
mv -f build/.config.new build/.config

# Arrange for build/config.{h,mk} to exist as soon as this
# script ends, so that users can see that the files we said we
# wrote out are actually written out.  Don't use the makefile
# rules, to avoid having to wait for configuration test
# runs that are not needed at this stage.
echo 'Writing build/config.{h,mk}'
rm -f build/config.h build/config.mk
cat build/.config/*.h > build/config.h
cat build/.config/*.mk > build/config.mk

exit 0

