check-host-rpath 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #!/usr/bin/env bash
  2. # This script scans $(HOST_DIR)/{bin,sbin} for all ELF files, and checks
  3. # they have an RPATH to $(HOST_DIR)/lib if they need libraries from
  4. # there.
  5. # Override the user's locale so we are sure we can parse the output of
  6. # readelf(1) and file(1)
  7. export LC_ALL=C
  8. main() {
  9. local pkg="${1}"
  10. local hostdir="${2}"
  11. local file ret
  12. # Remove duplicate and trailing '/' for proper match
  13. hostdir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${hostdir}" )"
  14. ret=0
  15. while read file; do
  16. is_elf "${file}" || continue
  17. elf_needs_rpath "${file}" "${hostdir}" || continue
  18. check_elf_has_rpath "${file}" "${hostdir}" && continue
  19. if [ ${ret} -eq 0 ]; then
  20. ret=1
  21. printf "***\n"
  22. printf "*** ERROR: package %s installs executables without proper RPATH:\n" "${pkg}"
  23. fi
  24. printf "*** %s\n" "${file}"
  25. done < <( find "${hostdir}"/{bin,sbin} -type f 2>/dev/null )
  26. return ${ret}
  27. }
  28. is_elf() {
  29. local f="${1}"
  30. readelf -l "${f}" 2>/dev/null \
  31. |grep -E 'Requesting program interpreter:' >/dev/null 2>&1
  32. }
  33. # This function tells whether a given ELF executable (first argument)
  34. # needs a RPATH pointing to the host library directory or not. It
  35. # needs such an RPATH if at least of the libraries used by the ELF
  36. # executable is available in the host library directory. This function
  37. # returns 0 when a RPATH is needed, 1 otherwise.
  38. elf_needs_rpath() {
  39. local file="${1}"
  40. local hostdir="${2}"
  41. local lib
  42. while read lib; do
  43. [ -e "${hostdir}/lib/${lib}" ] && return 0
  44. done < <( readelf -d "${file}" \
  45. |sed -r -e '/^.* \(NEEDED\) .*Shared library: \[(.+)\]$/!d;' \
  46. -e 's//\1/;' \
  47. )
  48. return 1
  49. }
  50. # This function checks whether at least one of the RPATH of the given
  51. # ELF executable (first argument) properly points to the host library
  52. # directory (second argument), either through an absolute RPATH or a
  53. # relative RPATH. Having such a RPATH will make sure the ELF
  54. # executable will find at runtime the shared libraries it depends
  55. # on. This function returns 0 when a proper RPATH was found, or 1
  56. # otherwise.
  57. check_elf_has_rpath() {
  58. local file="${1}"
  59. local hostdir="${2}"
  60. local rpath dir
  61. while read rpath; do
  62. for dir in ${rpath//:/ }; do
  63. # Remove duplicate and trailing '/' for proper match
  64. dir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${dir}" )"
  65. [ "${dir}" = "${hostdir}/lib" ] && return 0
  66. [ "${dir}" = "\$ORIGIN/../lib" ] && return 0
  67. done
  68. done < <( readelf -d "${file}" \
  69. |sed -r -e '/.* \(R(UN)?PATH\) +Library r(un)?path: \[(.+)\]$/!d' \
  70. -e 's//\3/;' \
  71. )
  72. return 1
  73. }
  74. main "${@}"