| #!/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 "${@}" |