HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux ns3133907 6.8.0-84-generic #84-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 5 22:36:38 UTC 2025 x86_64
User: cssnetorguk (1024)
PHP: 8.2.28
Disabled: NONE
Upload Files
File: //lib/kcare/libcare-patch-make
#!/bin/sh -e

usage() {
cat<<'EOF'
Makes `kpatch'es for the makesystem in the current directory.

Usage:	libcare-patch-make [-h|--help] [-u|--update || -c|--clean]
	[-p|--prepatch-ext=.EXT] \
	[-s|--srcdir=SRCDIR] \
	[-d|--destdir=DESTDIRVAR] \
	PATCH1 PATCH2 ...

Run from inside the directory with `make'ble software. Makesystem must support
install with specified DESTDIR.

  -c --clean	do a clean build, execute `make clean` first
  -u --update	only update existing patches without rebuild. useful when
		working on patch utils.
  -p --prepatch-ext	file extension used for patches applied on prebuild stage
  -s --srcdir	path to source folder of the project to be patched
  -d --destdir	specify variable makefile system uses to specify destination
		directory for the installation
EOF
		exit ${1-0}
}

xrealpath() {
	if command -v realpath >/dev/null; then
		realpath $1;
	else
		readlink -f -- "$1"
	fi
}

prepare_env() {
	export KPATCH_PATH=$(xrealpath $(dirname $0))

	if test ! -x "$KPATCH_PATH/kpatch_gensrc"; then
		echo "kpatch tools are missing" >&2
		exit 1
	fi

	LPMAKEFILE=""
	test -f lpmakefile && LPMAKEFILE="-f lpmakefile"

	LPMAKE_TEMP_DIR="${LPMAKE_PATCHED_DIR-$PWD/.lpmaketmp}"
	LPMAKE_ORIGINAL_DIR="${LPMAKE_ORIGINAL_DIR-$PWD/lpmake}"
	LPMAKE_PATCHED_DIR="${LPMAKE_PATCHED_DIR-$LPMAKE_TEMP_DIR/patched}"
	LPMAKE_PREPATCHED_DIR="${LPMAKE_PREPATCHED_DIR-$PWD/.lpmaketmp/prepatched}"
	LPMAKE_PATCHROOT="${LPMAKE_PATCHROOT-$PWD/patchroot}"

	export LPMAKE_ORIGINAL_DIR LPMAKE_PATCHED_DIR LPMAKE_PATCHROOT
	mkdir -p "$LPMAKE_ORIGINAL_DIR" "$LPMAKE_PATCHED_DIR" "$LPMAKE_PATCHROOT"

	export IS_LIBCARE_CC=y
	export CC="${LPMAKE_TEMP_DIR}/gcc"
	export CXX="${LPMAKE_TEMP_DIR}/g++"
	export KPCCREAL=$(which gcc)
	export KPCXXREAL=$(which g++)

	unset MAKELEVEL
	unset MAKEFLAGS

	red=$(tput setaf 1 || :)
	green=$(tput setaf 2 || :)
	reset=$(tput sgr0 || :)
}

restore_origs() {
	# Apply backups in reverse order
	find $srcdir -regex '.+\.[0-9]+\.lpmakeorig' | sort -rV \
		| sed -r 's/^(.+)\.[0-9]+\.lpmakeorig$/\0 \1/' \
		| xargs -r -n2 mv
}

trap "restore_origs" 0

clean() {
	if test -n "$do_clean"; then
		local oldpwd="$(pwd)"
		if test -n "$srcdir"; then
			cd "$srcdir"
		fi

		make $LPMAKEFILE clean
		rm -rf "$LPMAKE_ORIGINAL_DIR" "$LPMAKE_PATCHED_DIR"

		if test -n "$KPATCH_LTO_REPLAY_PLUGIN"; then
			echo "${red}clean lto files${reset}"
			rm -rf "$KPATCH_ASM_DIR" patchroot *cgraph *.ltrans* *.wpa* *.res *.i *.lto_wrapper*
		fi

		if test -n "$srcdir"; then
			cd "$oldpwd"
		fi
	fi
}

build_original() {
	export KPATCH_STAGE=original
	export KPCC_DBGFILTER_ARGS="$KPCC_DBGFILTER_ARGS"

	echo "${green}BUILDING ORIGINAL CODE${reset}"
	make $LPMAKEFILE

	echo "${green}INSTALLING ORIGINAL OBJECTS INTO $LPMAKE_ORIGINAL_DIR${reset}"
	make $LPMAKEFILE install				\
		"$destdir=$LPMAKE_ORIGINAL_DIR"
}

build_prepatched() {
	export KPATCH_STAGE=prepatched
	export KPCC_DBGFILTER_ARGS="$KPCC_DBGFILTER_ARGS"

	i=0
	for patch; do
		test -z "${patch#*$prepatch_ext}" || continue
		echo "${red}applying prebuild patch $patch...${reset}"
		patch -b -z .${i}.lpmakeorig -p1 < $patch
		i=$((i+1))
	done

	if test $i -eq 0 -a -z "$KPATCH_EMIT_DEBUG_FRAME" \
		&& ! make -np $LPMAKEFILE | grep -q KPATCH_EMIT_DEBUG_FRAME; then
		# No prebuild patches and KPATCH_EMIT_DEBUG_FRAME is not set.
		# We can skip prepatch stage.
		return
	fi

	echo "${green}BUILDING PREPATCHED CODE${reset}"
	make -B $LPMAKEFILE

	echo "${green}INSTALLING PREPATCHED OBJECTS INTO $LPMAKE_PREPATCHED_DIR${reset}"
	make $LPMAKEFILE install "$destdir=$LPMAKE_PREPATCHED_DIR"
}

build_patched() {
	export KPATCH_STAGE=patched
	export KPCC_APPEND_ARGS="-Wl,-q"

	if test -n "$KPATCH_LTO_REPLAY_PLUGIN"; then
		echo "${green}copy lto files to $KPATCH_ASM_DIR${reset}"
		find -iname \*.wpa.000i.cgraph -exec cp --parents {} "$KPATCH_ASM_DIR/$PWD/" \; || echo
		find -iname \*.res -exec cp --parents {} "$KPATCH_ASM_DIR/$PWD/" \; || echo
		find "$KP_PROJECT_DIR" -iname '*ltrans*[so]' -delete || echo
	fi

	local i=0
	for patch; do
		shift
		test -n "${patch#*$prepatch_ext}" || continue
		set -- "$@" "$patch"
		i=$((i+1))
	done

	for patch; do
		echo "${red}applying $patch...${reset}"
		patch -b -z .${i}.lpmakeorig -p1 < $patch
		i=$((i+1))
	done

	echo "${green}BUILDING PATCHED CODE${reset}"
	make $LPMAKEFILE

	echo "${green}INSTALLING PATCHED OBJECTS INTO $LPMAKE_PATCHED_DIR${reset}"
	make $LPMAKEFILE install				\
		"$destdir=$LPMAKE_PATCHED_DIR"
}

build_objects() {
	restore_origs

	mkdir -p "$(dirname $CC)" && ln -sf "${KPATCH_PATH}/libcare-cc" "$CC"
	mkdir -p "$(dirname $CXX)" && ln -sf "${KPATCH_PATH}/libcare-cc" "$CXX"

	local oldpwd="$(pwd)"
	if test -n "$srcdir"; then
		cd "$srcdir"
	fi

	build_original
	build_prepatched "$@"
	build_patched "$@"

	if test -n "$srcdir"; then
		cd "$oldpwd"
	fi
}

build_kpatches() {
	mkdir -p "${LPMAKE_PATCHROOT}"

	echo "${green}MAKING PATCHES${reset}"

	for execfile in $(find "$LPMAKE_ORIGINAL_DIR" -perm /0111 -type f); do
		origexec="$execfile"
		filename="${origexec##*$LPMAKE_ORIGINAL_DIR/}"
		patchedexec="$LPMAKE_PATCHED_DIR/$filename"
		prepatchedexec="$LPMAKE_PREPATCHED_DIR/$filename"

		buildid=$(eu-readelf -n "$origexec" | sed -n '/Build ID:/ { s/.* //; p }')
		if ! eu-readelf -S "$patchedexec" | grep -q '.kpatch'; then
			continue
		fi

		test -n "$buildid" || continue

		chmod u+w "${origexec}" "${patchedexec}"

		elfmake_args="$origexec $patchedexec ${patchedexec}.kpatch"
		if test -f "$prepatchedexec"; then
			elfmake_args="-w $prepatchedexec $elfmake_args"
		fi

		echo "$KPATCH_PATH/${KPATCH_ELFMAKE:-kpatch_dlmake}" $elfmake_args
		"$KPATCH_PATH/${KPATCH_ELFMAKE:-kpatch_dlmake}" $elfmake_args > "${patchedexec}.kpatch.txt" 2>&1

		cp "${patchedexec}.kpatch" "${LPMAKE_PATCHROOT}"/${buildid}.kpatch
		echo "patch for ${origexec} is in ${LPMAKE_PATCHROOT}/${buildid}.kpatch"
	done
}

main() {
	PROG_NAME=$(basename $0)

	TEMP=$(getopt -o s:ucd:p: --long srcdir:update,clean,destdir:,prepatch-ext: -n ${PROG_NAME} -- "$@" || usage 1)
	eval set -- "$TEMP"

	destdir="DESTDIR"
	while true; do
		case $1 in
		-s|--srcdir)
			shift
			srcdir="$1"
			shift
			;;
		-u|--update)
			shift
			only_update=1
			;;
		-c|--clean)
			shift
			do_clean=1
			;;
		-d|--destdir)
			shift
			destdir=$1
			shift
			;;
		-p|--prepatch-ext)
			shift
			prepatch_ext=$1
			shift
			;;
		--)
			shift; break;
			;;
		esac
	done

	prepare_env

	if test -z "$only_update"; then
		clean
		build_objects "$@"
	fi
	build_kpatches
}

main "$@"