Justin Vreeland 794355
#!/bin/bash
Justin Vreeland 794355
#
Justin Vreeland 794355
# This script takes the merged config files and processes them through oldconfig
Justin Vreeland 794355
# and listnewconfig
Justin Vreeland 794355
#
Justin Vreeland 794355
# Globally disable suggestion of appending '|| exit' or '|| return' to cd/pushd/popd commands
Justin Vreeland 794355
# shellcheck disable=SC2164
Justin Vreeland 794355
bde051
test -n "$RHTEST" && exit 0
bde051
Justin Vreeland 794355
usage()
Justin Vreeland 794355
{
Justin Vreeland 794355
	# alphabetical order please
Justin Vreeland 794355
	echo "process_configs.sh [ options ] package_name kernel_version"
Justin Vreeland 794355
	echo "     -a: report all errors, equivalent to [-c -n -w -i]"
Justin Vreeland 794355
	echo "     -c: error on mismatched config options"
Justin Vreeland 794355
	echo "     -i: continue on error"
Justin Vreeland 794355
	echo "     -n: error on unset config options"
Justin Vreeland 794355
	echo "     -t: test run, do not overwrite original config"
Justin Vreeland 794355
	echo "     -w: error on misconfigured config options"
Justin Vreeland 794355
	echo "     -z: commit new configs to pending directory"
Justin Vreeland 794355
	echo ""
Justin Vreeland 794355
	echo "     A special CONFIG file tag, process_configs_known_broken can be added as a"
Justin Vreeland 794355
	echo "     comment to any CONFIG file.  This tag indicates that there is no way to "
Justin Vreeland 794355
	echo "     fix a CONFIG's entry.  This tag should only be used in extreme cases"
Justin Vreeland 794355
	echo "     and is not to be used as a workaround to solve CONFIG problems."
Justin Vreeland 794355
	exit 1
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
die()
Justin Vreeland 794355
{
Justin Vreeland 794355
	echo "$1"
Justin Vreeland 794355
	exit 1
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
get_cross_compile()
Justin Vreeland 794355
{
Justin Vreeland 794355
	arch=$1
Justin Vreeland 794355
	if [[ "$CC_IS_CLANG" -eq 1 ]]; then
Justin Vreeland 794355
		echo "$arch"
Justin Vreeland 794355
	else
Justin Vreeland 794355
		echo "scripts/dummy-tools/"
Justin Vreeland 794355
	fi
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
# stupid function to find top of tree to do kernel make configs
Justin Vreeland 794355
switch_to_toplevel()
Justin Vreeland 794355
{
Justin Vreeland 794355
	path="$(pwd)"
Justin Vreeland 794355
	while test -n "$path"
Justin Vreeland 794355
	do
Justin Vreeland 794355
		test -e "$path"/MAINTAINERS && \
Justin Vreeland 794355
			test -d "$path"/drivers && \
Justin Vreeland 794355
			break
Justin Vreeland 794355
Justin Vreeland 794355
		path=$(dirname "$path")
Justin Vreeland 794355
	done
Justin Vreeland 794355
Justin Vreeland 794355
	test -n "$path"  || die "Can't find toplevel"
Justin Vreeland 794355
	echo "$path"
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
checkoptions()
Justin Vreeland 794355
{
bde051
	count=$3
bde051
	variant=$4
bde051
Justin Vreeland 794355
	/usr/bin/awk '
Justin Vreeland 794355
Justin Vreeland 794355
		/is not set/ {
Justin Vreeland 794355
			split ($0, a, "#");
Justin Vreeland 794355
			split(a[2], b);
Justin Vreeland 794355
			if (NR==FNR) {
Justin Vreeland 794355
				configs[b[1]]="is not set";
Justin Vreeland 794355
			} else {
Justin Vreeland 794355
				if (configs[b[1]] != "" && configs[b[1]] != "is not set")
Justin Vreeland 794355
					 print "Found # "b[1] " is not set, after generation, had " b[1] " " configs[b[1]] " in Source tree";
Justin Vreeland 794355
			}
Justin Vreeland 794355
		}
Justin Vreeland 794355
Justin Vreeland 794355
		/=/     {
Justin Vreeland 794355
			split ($0, a, "=");
Justin Vreeland 794355
			if (NR==FNR) {
Justin Vreeland 794355
				configs[a[1]]=a[2];
Justin Vreeland 794355
			} else {
Justin Vreeland 794355
				if (configs[a[1]] != "" && configs[a[1]] != a[2])
Justin Vreeland 794355
					 print "Found "a[1]"="a[2]" after generation, had " a[1]"="configs[a[1]]" in Source tree";
Justin Vreeland 794355
			}
Justin Vreeland 794355
		}
bde051
	' "$1" "$2" > .mismatches"${count}"
Justin Vreeland 794355
Justin Vreeland 794355
	checkoptions_error=false
bde051
	if test -s .mismatches"${count}"
Justin Vreeland 794355
	then
Justin Vreeland 794355
		while read -r LINE
Justin Vreeland 794355
		do
bde051
			if find "${REDHAT}"/configs -name "$(echo "$LINE" | awk -F "=" ' { print $1 } ' | awk ' { print $2 }')" -print0 | xargs -0 grep ^ | grep -q "process_configs_known_broken"; then
Justin Vreeland 794355
				# This is a known broken config.
Justin Vreeland 794355
				# See script help warning.
Justin Vreeland 794355
				checkoptions_error=false
Justin Vreeland 794355
			else
Justin Vreeland 794355
				checkoptions_error=true
Justin Vreeland 794355
				break
Justin Vreeland 794355
			fi
bde051
		done < .mismatches"${count}"
Justin Vreeland 794355
Justin Vreeland 794355
		! $checkoptions_error && return
Justin Vreeland 794355
bde051
		sed -i "1s/^/Error: Mismatches found in configuration files for ${arch} ${variant}\n/" .mismatches"${count}"
bde051
	else
bde051
		rm -f .mismatches"${count}"
Justin Vreeland 794355
	fi
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
parsenewconfigs()
Justin Vreeland 794355
{
Justin Vreeland 794355
	tmpdir=$(mktemp -d)
Justin Vreeland 794355
Justin Vreeland 794355
	# This awk script reads the output of make listnewconfig
Justin Vreeland 794355
	# and puts it into CONFIG_FOO files. Using the output of
Justin Vreeland 794355
	# listnewconfig is much easier to ensure we get the default
Justin Vreeland 794355
	# output.
Justin Vreeland 794355
        /usr/bin/awk -v BASE="$tmpdir" '
Justin Vreeland 794355
                /is not set/ {
Justin Vreeland 794355
                        split ($0, a, "#");
Justin Vreeland 794355
                        split(a[2], b);
Justin Vreeland 794355
                        OUT_FILE=BASE"/"b[1];
Justin Vreeland 794355
                        print $0 >> OUT_FILE;
Justin Vreeland 794355
                }
Justin Vreeland 794355
Justin Vreeland 794355
                /=/     {
Justin Vreeland 794355
                        split ($0, a, "=");
Justin Vreeland 794355
                        OUT_FILE=BASE"/"a[1];
Justin Vreeland 794355
                        if (a[2] == "n")
Justin Vreeland 794355
                                print "# " a[1] " is not set" >> OUT_FILE;
Justin Vreeland 794355
                        else
Justin Vreeland 794355
                                print $0 >> OUT_FILE;
Justin Vreeland 794355
                }
Justin Vreeland 794355
Justin Vreeland 794355
        ' .newoptions
Justin Vreeland 794355
Justin Vreeland 794355
	# This awk script parses the output of helpnewconfig.
Justin Vreeland 794355
	# Each option is separated between ----- markers
Justin Vreeland 794355
	# The goal is to put all the help text as a comment in
Justin Vreeland 794355
	# each CONFIG_FOO file. Because of how awk works
Justin Vreeland 794355
	# there's a lot of moving files around and catting to
Justin Vreeland 794355
	# get what we need.
Justin Vreeland 794355
        /usr/bin/awk -v BASE="$tmpdir" '
Justin Vreeland 794355
                BEGIN { inpatch=0;
Justin Vreeland 794355
			outfile="none";
6525d0
                        symbol="none";
6525d0
                        commit=""; }
Justin Vreeland 794355
                /^Symbol: .*$/ {
Justin Vreeland 794355
                        split($0, a, " ");
Justin Vreeland 794355
                        symbol="CONFIG_"a[2];
Justin Vreeland 794355
                        outfile=BASE "/fake_"symbol
Justin Vreeland 794355
                }
Justin Vreeland 794355
                /-----/ {
Justin Vreeland 794355
			if (inpatch == 0) {
Justin Vreeland 794355
				inpatch = 1;
Justin Vreeland 794355
			}
Justin Vreeland 794355
                        else {
Justin Vreeland 794355
                                if (symbol != "none") {
6525d0
                                    print "# Commit: "commit >> outfile
Justin Vreeland 794355
                                    system("cat " outfile " " BASE "/" symbol " > " BASE "/tmpf");
Justin Vreeland 794355
                                    system("mv " BASE "/tmpf " BASE "/" symbol);
Justin Vreeland 794355
                                    symbol="none"
6525d0
                                    commit=""
Justin Vreeland 794355
				}
Justin Vreeland 794355
                                outfile="none"
Justin Vreeland 794355
				inpatch = 0;
Justin Vreeland 794355
                        }
Justin Vreeland 794355
                }
Justin Vreeland 794355
                !/-----/ {
Justin Vreeland 794355
                        if (inpatch == 1 && outfile != "none") {
Justin Vreeland 794355
                                print "# "$0 >> outfile;
Justin Vreeland 794355
                        }
Justin Vreeland 794355
                }
6525d0
                /^Defined at .*$/ {
6525d0
                        split($0, x, " ");
6525d0
                        filenum=x[3];
6525d0
                        split(filenum, x, ":");
6525d0
                        file=x[1]
6525d0
                        line=x[2]
6525d0
                        cmd="git blame -L " line "," line " " file " | cut -d \" \" -f1 | xargs git log --pretty=format:\"%C(auto)%h %C(cyan)('%s')\" -1"
6525d0
                        cmd | getline commit
6525d0
                }
Justin Vreeland 794355
Justin Vreeland 794355
Justin Vreeland 794355
        ' .helpnewconfig
Justin Vreeland 794355
Justin Vreeland 794355
	pushd "$tmpdir" &> /dev/null
Justin Vreeland 794355
	rm fake_*
Justin Vreeland 794355
	popd &> /dev/null
Justin Vreeland 794355
	for f in "$tmpdir"/*; do
Justin Vreeland 794355
		[[ -e "$f" ]] || break
Justin Vreeland 794355
		cp "$f" "$SCRIPT_DIR/pending$FLAVOR/generic/"
Justin Vreeland 794355
	done
Justin Vreeland 794355
Justin Vreeland 794355
	rm -rf "$tmpdir"
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
function commit_new_configs()
Justin Vreeland 794355
{
Justin Vreeland 794355
	# assume we are in $source_tree/configs, need to get to top level
Justin Vreeland 794355
	pushd "$(switch_to_toplevel)" &>/dev/null
Justin Vreeland 794355
73e442
	for cfg in "$SCRIPT_DIR/${SPECPACKAGE_NAME}${KVERREL}"*.config
Justin Vreeland 794355
	do
Justin Vreeland 794355
		arch=$(head -1 "$cfg" | cut -b 3-)
Justin Vreeland 794355
		cfgtmp="${cfg}.tmp"
Justin Vreeland 794355
		cfgorig="${cfg}.orig"
Justin Vreeland 794355
		cat "$cfg" > "$cfgorig"
Justin Vreeland 794355
Justin Vreeland 794355
		if [ "$arch" = "EMPTY" ]
Justin Vreeland 794355
		then
Justin Vreeland 794355
			# This arch is intentionally left blank
Justin Vreeland 794355
			continue
Justin Vreeland 794355
		fi
Justin Vreeland 794355
		echo -n "Checking for new configs in $cfg ... "
Justin Vreeland 794355
bde051
		# shellcheck disable=SC2086
bde051
		make ${MAKEOPTS} ARCH="$arch" CROSS_COMPILE="$(get_cross_compile "$arch")" KCONFIG_CONFIG="$cfgorig" listnewconfig >& .listnewconfig
Justin Vreeland 794355
		grep -E 'CONFIG_' .listnewconfig > .newoptions
Justin Vreeland 794355
		if test -s .newoptions
Justin Vreeland 794355
		then
bde051
		# shellcheck disable=SC2086
bde051
			make ${MAKEOPTS} ARCH="$arch" CROSS_COMPILE="$(get_cross_compile "$arch")" KCONFIG_CONFIG="$cfgorig" helpnewconfig >& .helpnewconfig
Justin Vreeland 794355
			parsenewconfigs
Justin Vreeland 794355
		fi
Justin Vreeland 794355
		rm .newoptions
Justin Vreeland 794355
		echo "done"
Justin Vreeland 794355
	done
Justin Vreeland 794355
Justin Vreeland 794355
	git add "$SCRIPT_DIR/pending$FLAVOR"
Justin Vreeland 794355
	git commit -m "[redhat] AUTOMATIC: New configs"
Justin Vreeland 794355
}
Justin Vreeland 794355
bde051
function process_config()
Justin Vreeland 794355
{
bde051
	local cfg
bde051
	local arch
bde051
	local cfgtmp
bde051
	local cfgorig
bde051
	local count
bde051
	local variant
Justin Vreeland 794355
bde051
	cfg=$1
bde051
	count=$2
Justin Vreeland 794355
bde051
	arch=$(head -1 "$cfg" | cut -b 3-)
Justin Vreeland 794355
bde051
	if [ "$arch" = "EMPTY" ]
bde051
	then
bde051
		# This arch is intentionally left blank
bde051
		return
bde051
	fi
Justin Vreeland 794355
bde051
	variant=$(basename "$cfg" | cut -d"-" -f3- | cut -d"." -f1)
Justin Vreeland 794355
bde051
	cfgtmp="${cfg}.tmp"
bde051
	cfgorig="${cfg}.orig"
bde051
	cat "$cfg" > "$cfgorig"
Justin Vreeland 794355
bde051
	echo "Processing $cfg ... "
bde051
bde051
	# shellcheck disable=SC2086
bde051
	make ${MAKEOPTS} ARCH="$arch" CROSS_COMPILE="$(get_cross_compile "$arch")" KCONFIG_CONFIG="$cfgorig" listnewconfig >& .listnewconfig"${count}"
bde051
	grep -E 'CONFIG_' .listnewconfig"${count}" > .newoptions"${count}"
bde051
	if test -n "$NEWOPTIONS" && test -s .newoptions"${count}"
bde051
	then
bde051
		echo "Found unset config items in ${arch} ${variant}, please set them to an appropriate value" >> .errors"${count}"
bde051
		cat .newoptions"${count}" >> .errors"${count}"
bde051
		rm .newoptions"${count}"
bde051
		RETURNCODE=1
bde051
	fi
bde051
	rm -f .newoptions"${count}"
bde051
bde051
	grep -E 'config.*warning' .listnewconfig"${count}" > .warnings"${count}"
bde051
	if test -n "$CHECKWARNINGS" && test -s .warnings"${count}"
bde051
	then
bde051
		echo "Found misconfigured config items in ${arch} ${variant}, please set them to an appropriate value" >> .errors"${count}"
bde051
		cat .warnings"${count}" >> .errors"${count}"
bde051
	fi
bde051
	rm .warnings"${count}"
bde051
bde051
	rm .listnewconfig"${count}"
bde051
bde051
	# shellcheck disable=SC2086
bde051
	make ${MAKEOPTS} ARCH="$arch" CROSS_COMPILE="$(get_cross_compile "$arch")" KCONFIG_CONFIG="$cfgorig" olddefconfig > /dev/null || exit 1
bde051
	echo "# $arch" > "$cfgtmp"
bde051
	cat "$cfgorig" >> "$cfgtmp"
bde051
	if test -n "$CHECKOPTIONS"
bde051
	then
bde051
		checkoptions "$cfg" "$cfgtmp" "$count" "$variant"
bde051
	fi
bde051
	# if test run, don't overwrite original
bde051
	if test -n "$TESTRUN"
bde051
	then
bde051
		rm -f "$cfgtmp"
bde051
	else
bde051
		mv "$cfgtmp" "$cfg"
bde051
	fi
bde051
	rm -f "$cfgorig"
bde051
	echo "Processing $cfg complete"
bde051
}
bde051
bde051
function process_configs()
bde051
{
bde051
	# assume we are in $source_tree/configs, need to get to top level
bde051
	pushd "$(switch_to_toplevel)" &>/dev/null
bde051
bde051
	# The next line is throwaway code for transition to parallel
bde051
	# processing.  Leaving this line in place is harmless, but it can be
bde051
	# removed the next time anyone updates this function.
bde051
	[ -f .mismatches ] && rm -f .mismatches
bde051
bde051
	count=0
73e442
	for cfg in "$SCRIPT_DIR/${SPECPACKAGE_NAME}${KVERREL}"*.config
bde051
	do
bde051
		if [ "$count" -eq 0 ]; then
bde051
			# do the first one by itself so that tools are built
bde051
			process_config "$cfg" "$count"
Justin Vreeland 794355
		fi
bde051
		process_config "$cfg" "$count" &
73e442
		# shellcheck disable=SC2004
bde051
		waitpids[${count}]=$!
bde051
		((count++))
bde051
		while [ "$(jobs | grep -c Running)" -ge "$RHJOBS" ]; do :; done
Justin Vreeland 794355
	done
73e442
	# shellcheck disable=SC2048
bde051
	for pid in ${waitpids[*]}; do
73e442
		wait "${pid}"
bde051
	done
bde051
Justin Vreeland 794355
	rm "$SCRIPT_DIR"/*.config*.old
bde051
bde051
	if ls .errors* 1> /dev/null 2>&1; then
bde051
		RETURNCODE=1
bde051
		cat .errors*
bde051
		rm .errors* -f
bde051
	fi
bde051
	if ls .mismatches* 1> /dev/null 2>&1; then
bde051
		RETURNCODE=1
bde051
		cat .mismatches*
bde051
		rm .mismatches* -f
bde051
	fi
bde051
Justin Vreeland 794355
	popd > /dev/null
Justin Vreeland 794355
bde051
	[ $RETURNCODE -eq 0 ] && echo "Processed config files are in $SCRIPT_DIR"
Justin Vreeland 794355
}
Justin Vreeland 794355
Justin Vreeland 794355
CHECKOPTIONS=""
Justin Vreeland 794355
NEWOPTIONS=""
Justin Vreeland 794355
TESTRUN=""
Justin Vreeland 794355
CHECKWARNINGS=""
Justin Vreeland 794355
MAKEOPTS=""
Justin Vreeland 794355
CC_IS_CLANG=0
Justin Vreeland 794355
Justin Vreeland 794355
RETURNCODE=0
Justin Vreeland 794355
Justin Vreeland 794355
while [[ $# -gt 0 ]]
Justin Vreeland 794355
do
Justin Vreeland 794355
	key="$1"
Justin Vreeland 794355
	case $key in
Justin Vreeland 794355
		-a)
Justin Vreeland 794355
			CHECKOPTIONS="x"
Justin Vreeland 794355
			NEWOPTIONS="x"
Justin Vreeland 794355
			CHECKWARNINGS="x"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-c)
Justin Vreeland 794355
			CHECKOPTIONS="x"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-h)
Justin Vreeland 794355
			usage
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-n)
Justin Vreeland 794355
			NEWOPTIONS="x"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-t)
Justin Vreeland 794355
			TESTRUN="x"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-w)
Justin Vreeland 794355
			CHECKWARNINGS="x"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-z)
Justin Vreeland 794355
			COMMITNEWCONFIGS="x"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		-m)
Justin Vreeland 794355
			shift
bde051
			if [ "$1" = "CC=clang" ] || [ "$1" = "LLVM=1" ]; then
Justin Vreeland 794355
				CC_IS_CLANG=1
Justin Vreeland 794355
			fi
Justin Vreeland 794355
			MAKEOPTS="$MAKEOPTS $1"
Justin Vreeland 794355
			;;
Justin Vreeland 794355
		*)
Justin Vreeland 794355
			break;;
Justin Vreeland 794355
	esac
Justin Vreeland 794355
	shift
Justin Vreeland 794355
done
Justin Vreeland 794355
bde051
KVERREL="$(test -n "$1" && echo "-$1" || echo "")"
73e442
FLAVOR="$(test -n "$2" && echo "-$2" || echo "-rhel")"
bde051
# shellcheck disable=SC2015
Justin Vreeland 794355
SCRIPT=$(readlink -f "$0")
Justin Vreeland 794355
SCRIPT_DIR=$(dirname "$SCRIPT")
Justin Vreeland 794355
73e442
# Config options for RHEL should target the pending-rhel directory, not pending-common.
Justin Vreeland 794355
if [ "$FLAVOR" = "-rhel" ]
Justin Vreeland 794355
then
73e442
	FLAVOR="-rhel"
Justin Vreeland 794355
fi
Justin Vreeland 794355
Justin Vreeland 794355
# to handle this script being a symlink
Justin Vreeland 794355
cd "$SCRIPT_DIR"
Justin Vreeland 794355
Justin Vreeland 794355
if test -n "$COMMITNEWCONFIGS"; then
Justin Vreeland 794355
	commit_new_configs
Justin Vreeland 794355
else
Justin Vreeland 794355
	process_configs
Justin Vreeland 794355
fi
Justin Vreeland 794355
Justin Vreeland 794355
exit $RETURNCODE