#!/usr/bin/env bash # This script scans $(HOST_DIR)/{bin,sbin} for all ELF files, and checks # they have an RPATH to $(HOST_DIR)/lib if they need libraries from # there. # Override the user's locale so we are sure we can parse the output of # readelf(1) and file(1) export LC_ALL=C main() { local pkg="${1}" local hostdir="${2}" local file ret # Remove duplicate and trailing '/' for proper match hostdir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${hostdir}" )" ret=0 while read file; do is_elf "${file}" || continue elf_needs_rpath "${file}" "${hostdir}" || continue check_elf_has_rpath "${file}" "${hostdir}" && continue if [ ${ret} -eq 0 ]; then ret=1 printf "***\n" printf "*** ERROR: package %s installs executables without proper RPATH:\n" "${pkg}" fi printf "*** %s\n" "${file}" done < <( find "${hostdir}"/{bin,sbin} -type f 2>/dev/null ) return ${ret} } is_elf() { local f="${1}" readelf -l "${f}" 2>/dev/null \ |grep -E 'Requesting program interpreter:' >/dev/null 2>&1 } # This function tells whether a given ELF executable (first argument) # needs a RPATH pointing to the host library directory or not. It # needs such an RPATH if at least of the libraries used by the ELF # executable is available in the host library directory. This function # returns 0 when a RPATH is needed, 1 otherwise. elf_needs_rpath() { local file="${1}" local hostdir="${2}" local lib while read lib; do [ -e "${hostdir}/lib/${lib}" ] && return 0 done < <( readelf -d "${file}" \ |sed -r -e '/^.* \(NEEDED\) .*Shared library: \[(.+)\]$/!d;' \ -e 's//\1/;' \ ) return 1 } # This function checks whether at least one of the RPATH of the given # ELF executable (first argument) properly points to the host library # directory (second argument), either through an absolute RPATH or a # relative RPATH. Having such a RPATH will make sure the ELF # executable will find at runtime the shared libraries it depends # on. This function returns 0 when a proper RPATH was found, or 1 # otherwise. check_elf_has_rpath() { local file="${1}" local hostdir="${2}" local rpath dir while read rpath; do for dir in ${rpath//:/ }; do # Remove duplicate and trailing '/' for proper match dir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${dir}" )" [ "${dir}" = "${hostdir}/lib" ] && return 0 [ "${dir}" = "\$ORIGIN/../lib" ] && return 0 done done < <( readelf -d "${file}" \ |sed -r -e '/.* \(R(UN)?PATH\) +Library r(un)?path: \[(.+)\]$/!d' \ -e 's//\3/;' \ ) return 1 } main "${@}"