#!/bin/bash -e
# Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

ROOT="/"
LDSO_CONF="/etc/ld.so.conf"

VERBOSE=0

UPDATE_LINKS=1

get_options() {
	while getopts "vnNXf:C:r:p" opt "$@"; do
		case $opt in
		v)
			echo "ldconfig for musl in Gentoo"
			VERBOSE=1
			;;
		r)
			ROOT=${OPTARG}
			LDSO_CONF=${ROOT}${LDSO_CONF}
			LDSO_CONF_DIR=$(dirname ${LDSO_CONF})
			;;
		f)
			LDSO_CONF=${OPTARG}
			;;
		X)
			UPDATE_LINKS=0
			;;
		\?)
			echo "Invalid option: -${opt}" >&2
			exit 1
			;;
		n|N|C|p)
			echo "Unimplemented option: -${opt}" >&2
			exit 1
			;;
		esac
	done

	if [[ ${UPDATE_LINKS} == 1 ]]; then
		echo "Updating links is not implemented."
	fi
}


repeated() {
	local l=${1}
	local drs="${@:2}"
	for m in ${drs}; do
		[[ ${m} == ${l} ]] && return 0
	done
	return 1
}

expand() {
	# We are assuming the ld.so.conf's 'include' is not recursive
	local f line l
	local glob="${LDSO_CONF_DIR}/${1}"
	local drs="${@:2} "

	for f in ${glob}; do
		[[ ! -f ${f} ]] && continue
		while read line; do
			line=${line%%#*}
			line=${line//:/ }
			line=${line//,/ }
			for l in ${line}; do
				# We must add this whether or not the directory exists
				repeated ${l} ${drs} && continue
				drs+=" ${l} "
			done
		done < ${f}
	done

	echo ${drs}
}

read_ldso_conf() {
	local drs=" "

	while read line; do
		# Sanitize the line - see ldconfig(8) for delimiters
		# Note: bash read turns tabs into spaces and read already
		# delimits on newlines with the default $IFS
		line=${line%%#*}   # Remove comments
		line=${line//:/ }  # Change colon delimiter to space
		line=${line//,/ }  # Change comma delimiter to space

		next=0
		for l in ${line}; do
			if [[ ${next} == 1 ]]; then
				next=0
				drs=$(expand ${l} ${drs})
			elif [[ ${l} == "include" ]]; then
				next=1
			else
				# glibc's ldconfig silently skips non directories
				if [[ -d ${l} ]]; then
					repeated ${l} ${drs} && continue
					drs+=" ${l} "
				fi
			fi
		done
	done < ${1}

	echo ${drs}
}

sanitize() {
	local drs=$@

	repeated "/lib" ${drs} || drs="/lib ${drs}"
	repeated "/usr/lib" ${drs} || drs="/usr/lib ${drs}"

	echo ${drs}
}

changed() {
	[[ -f ${ETC_LDSO_PATH} ]] || return 0
	local current=$(<${ETC_LDSO_PATH})
	current=${current//$'\n'/ }
	[[ ${current} != ${drs} ]] || return 1
}

get_options "$@"

if [[ ! -e ${LDSO_CONF} ]]; then
        echo "${LDSO_CONF} not found" >&2
        exit 1
fi

LDSO_CONF_DIR=$(dirname ${LDSO_CONF})

drs=$(read_ldso_conf "${LDSO_CONF}")
drs=$(sanitize ${drs})

ARCH=@@ARCH@@
LDSO_PATH="${ROOT}/lib/ld-musl-${ARCH}.so.1"
if [[ ! -e ${LDSO_PATH} ]]; then
	echo "${LDSO_PATH} not found" >&2
	exit 1
fi

LDSO_ARCH=$(basename ${LDSO_PATH})
LDSO_NAME=${LDSO_ARCH%.so.1}
ETC_LDSO_PATH="${ROOT}/etc/${LDSO_NAME}.path"

changed || exit 0
X=$(mktemp -p /tmp ${LDSO_NAME}.XXXXXX)
for d in ${drs}; do
	echo ${d} >> ${X}
done
chmod 644 ${X}
# busybox doesn't support mz -Z
cp ${X} ${ETC_LDSO_PATH}
rm ${X}
