#!/bin/bash -efu

. shell-error

LOCALFILES=()
FILES=()
DIRS=()

append_uniq()
{
	local arr i sz v
	eval "sz=\${#$1[*]}"
	for (( i=0; $i < $sz; i++ )); do
		eval "v=\"\${$1[$i]}\""
		[ "$v" != "$2" ] ||
			return 0
	done
	eval "$1+=(\"\$2\")"
}

append_progs()
{
	local n f SEARCH_PATH=''

	[ -z "$LOCALBUILDDIR" ] ||
		SEARCH_PATH="$LOCALBUILDDIR$RUNTIMEDIR/sbin:$LOCALBUILDDIR$RUNTIMEDIR/bin"

	SEARCH_PATH="${SEARCH_PATH:+$SEARCH_PATH:}$BUSYBOX_PATH:$SYSTEM_PATH"

	for n; do
		[ -n "$n" ] ||
			continue
		if [ -z "${n##/*}" ]; then
			message "WARNING: it doesn't make sense to search in PATH for a utility with absolute path: $n"
			append_uniq FILES "$n"
			continue
		elif [ -z "${n##*/*}" ]; then
			message "WARNING: it doesn't make sense to search in PATH for a utility with subpath: $n"
			n="${n##*/}"
		fi
		found=
		while read -d: -r path; do
			[ -n "$path" ] ||
				continue
			f="$path/$n"
			if [ -x "$f" ]; then
				found=1
				break
			fi
		done <<<"$SEARCH_PATH"

		[ -n "$found" ] ||
			fatal "Not found utility: $n"

		[ -n "${f##$RUNTIMEDIR/*}" ] ||
			continue

		[ -z "$LOCALBUILDDIR" ] || [ -n "${f##$LOCALBUILDDIR/*}" ] ||
			continue

		append_uniq FILES "$f"
	done
}

for n in \
	"$RUNTIMEDIR" "$BASEDATADIR" \
	${LOCALBUILDDIR:+"${LOCALBUILDDIR-}$RUNTIMEDIR"} \
	${PUT_FEATURE_DIRS-} $PUT_DIRS;
do
	append_uniq DIRS "$n"
done

FILES+=(
	"$UDEVD"
	"$UDEVADM"
	/lib/udev/ata_id
	/lib/udev/cdrom_id
	/lib/udev/scsi_id
)

for n in \
	/lib/udev/{edd_id,vol_id,path_id,usb_id,firmware} \
	/usr/share/terminfo/l \
	/var/resolv \
	"$KERNEL_MODULES_DIR"/modules.{builtin,order,builtin.modinfo} \
	/etc/modprobe.conf;
do
	[ ! -e "$n" ] ||
		append_uniq FILES "$n"
done

append_progs \
	blkid cat chmod chroot cp depmod dmesg findmnt grep kill killall5 ln \
	logger ls lsmod mkdir mknod mktemp modprobe mount mountpoint mv \
	readlink rm rmdir setsid sh sleep start-stop-daemon switch_root \
	touch umount which bash ${PUT_FEATURE_PROGS-} ${PUT_PROGS-}

while read -d: -r n; do
	[ -n "$n" ] ||
		continue
	(set +f; shopt -s nullglob dotglob; printf '%s\n' "$n"/*) > "$TEMPDIR/list"
	while read -r bin; do
		[ -n "$bin" ] ||
			continue
		for pattern in '*/shell-*' ${PUT_FEATURE_PROGS_WILDCARD-}; do
			[ -z "${bin##$pattern}" ] ||
				continue
			if [ -n "$LOCALBUILDDIR" ] && [ -z "${bin##$LOCALBUILDDIR/*}" ]; then
				append_uniq LOCALFILES "$bin"
				continue
			fi
			[ -n "${bin##$RUNTIMEDIR/*}" ] ||
				continue
			append_uniq FILES "$bin"
		done
	done < "$TEMPDIR/list"
done <<<"$BUILDDIR_PATH:$BUSYBOX_PATH:$SYSTEM_PATH"
rm -f -- "$TEMPDIR/list"

for n in ${PUT_FEATURE_FILES-} $PUT_FILES; do
	append_uniq FILES "$n"
done

cd "$ROOTDIR"

mkdir_save_symlinks()
{
	local dir sub_dir follow_dir canon_path

	for dir in "$@"; do
		[ -n "$dir" ] ||
			continue

		sub_dir="$(dirname "$dir")"

		if [ ! -e "$sub_dir" ] && [ ! -h "$sub_dir" ]; then
			mkdir_save_symlinks "$sub_dir"
		fi

		if [ ! -h "/$dir" ]; then
			mkdir $verbose -p -- "./$dir"
		else
			follow_dir=".$(readlink -f "/$dir")"
			mkdir_save_symlinks "$follow_dir"

			canon_path="$(realpath --relative-to="$sub_dir" "$follow_dir")"
			ln -s "$canon_path" "./$dir"
		fi
	done
}

mkdir_save_symlinks \
	{dev,mnt,root,run,proc,sys,tmp,{,usr/}{,s}bin,{,usr/}{share,lib{,32,x32,64}},var/{cache,lock/subsys,log,run}} \
	lib/{modules,udev,initrd/{all,kmodules,post,pre}} \
	etc/{{initrd,modprobe.d,sysconfig},udev/rules.d} \
	.initrd/{killall,uevent/events,uevent/queues/udev/.tmp} \
	home/root \
	"${KERNEL_MODULES_DIR#/}" \
	#

initrd-release

mkfifo ./.initrd/telinit
mkfifo ./.initrd/rdshell

printf '%s\n' "${DIRS[@]}"       |xargs -r put-tree .
printf '%s\n' "${FILES[@]}"      |xargs -r put-file .
printf '%s\n' "${LOCALFILES[@]}" |xargs -r put-file -r "$LOCALBUILDDIR" .

ln_if_missing()
{
	[ -h "$2" ] || [ -e "$2" ] || ln $verbose -s -- "$1" "$2"
}

BASH="$(find ./bin ./sbin ./usr/bin ./usr/sbin ./usr/local/bin ./usr/local/sbin -name bash -print -quit)"
BASH="${BASH#.}"

ln_if_missing "$BASH"    ./bin/bash
ln_if_missing "$UDEVD"   ./sbin/udevd
ln_if_missing "$UDEVADM" ./sbin/udevadm

for i in rc0 rc1 rc2 rc3 rc4 rc5 rc6 init; do
	mkdir -p "./etc/rc.d/$i.d"
	ln -s -f "rc.d/$i.d" "./etc/$i.d"
done

for n in group gshadow passwd shadow fstab; do
	touch "./etc/$n"
done

# No shell access inside initramfs by default.
[ -s ./etc/sysconfig/rdshell ] ||
	printf 'RDSHELL_MODE=disable\n' >./etc/sysconfig/rdshell

for d in lib etc; do
	if [ -d "/$d/modprobe.d" ]; then
		verbose "Copying files from $d/modprobe.d ..."
		find -L "/$d/modprobe.d" \
				-name '*.conf' \
			-exec cp -aLt ./etc/modprobe.d -- '{}' '+'
	fi

	if [ -d "/$d/udev/initramfs-rules.d" ]; then
		verbose "Copying files from /$d/udev/initramfs-rules.d ..."
		find -L "/$d/udev/initramfs-rules.d" \
				-name '*.rules' \
			-exec cp -aLt ./etc/udev/rules.d -- '{}' '+'
	fi
done
