yann@1863: #!/bin/sh yann@217: # This script will populate the root directory with libs from the sysroot. yann@217: # (C) 2007 Yann E. MORIN yann@217: # Licensed under the GPL v2 yann@1177: set -e yann@217: yann@1400: # Use the tools discovered by crosstool-NG's ./configure: yann@1190: install="@@CT_install@@" yann@1190: grep="@@CT_grep@@" yann@1190: sed="@@CT_sed@@" yann@1177: yann@1861: # Detect where the toolchain is: yann@1861: CT_PREFIX_DIR="$(cd "$(dirname "$0")/.."; pwd)" yann@1861: CT_GCC="${0%-populate}-gcc" yann@1861: CT_READELF="${0%-populate}-readelf" yann@1861: CT_CFG_PREFIX_DIR="$("${CT_GCC}" -v 2>&1 \ yann@1861: |tr ' ' '\n' \ yann@1861: |"${grep}" -E -- '--prefix=' \ yann@1861: |cut -d = -f 2- yann@1861: )" yann@1861: CT_CFG_SYSROOT_DIR="$("${CT_GCC}" -v 2>&1 \ yann@1861: |tr ' ' '\n' \ yann@1861: |"${grep}" -E -- '--with-sysroot=' \ yann@1861: |cut -d = -f 2- yann@1861: )" yann@1863: CT_SYSROOT_DIR="$(printf "${CT_CFG_SYSROOT_DIR}\n" \ yann@1861: |"${sed}" -r -e "s:^${CT_CFG_PREFIX_DIR}:${CT_PREFIX_DIR}:;" \ yann@1861: |"${sed}" -r -e 's,/+,/,g;' \ yann@1861: )" yann@1861: yann@1861: myname=$(basename "$0") yann@1861: yann@217: doHelp() { yann@217: cat <<_EOF_ yann@910: NAME yann@910: $myname - populate the target root file system yann@217: yann@910: SYNOPSIS yann@910: $myname OPTIONS -s source_root -d destination_root yann@217: yann@910: DESCRIPTION yann@1863: This script will 'populate' your target root file system 'source_root' yann@1863: with libraries from the toolchain (eg. libc.so...), storing the result yann@1863: into 'dst_dir'. yann@217: yann@910: OPTIONS yann@910: -s src_dir yann@1863: Use 'src_dir' as the un-populated (source) root directory. yann@910: yann@910: -d dst_dir yann@1863: Use 'dst_dir' as the place to put the populated root directory. yann@1863: See the -f and -m options, below, on the required (non-)existence yann@1863: of this directory. yann@910: ncase@1859: -r sysroot_dir yann@1863: Use 'sysroot_dir' as the sysroot instead of the toolchain default. ncase@1859: yann@910: -l name1[:name2[...]] yann@910: Always add the specified shared library/ies name1, name2... from the yann@2279: toolchain (in the sysroot). Actual library names are searched as yann@910: follows (where 'name' is replaced with the given name) in the yann@2279: sysroot directory: yann@910: - libname.so yann@910: - name.so yann@910: - name yann@910: If the file is found, then the SONAME of the library is used, and the yann@910: library is copied with that name. If the library was not found, this yann@910: yields an error (unless -f was given). yann@910: yann@910: -L file yann@910: Read 'file' for a list of shared libraries to always add from the yann@910: toolchain. The file should contain one library name per line; text yann@910: after a # is ignored until the end of the line; spaces are ignored; yann@910: empty lines are ignored. Libraries are searched for as with -l. yann@910: yann@1863: -f Force execution: if destination directory already exists, it will be yann@910: removed first; if a specified library (above) was not found, continue. yann@1860: Note: if using -m and the destination directory already exists, it yann@1860: is *not* removed, see below. yann@1860: yann@1860: -m Merge the source root directory with the destination root directory. yann@1860: If the latter does not exist, it is created, and -m is ignored. yann@1863: If the destination root directory exists, then the content of the yann@1860: source root directory is copied in there, and the result is populated yann@1860: as usual. antony@2564: It can be useful if constructing a rootfs incrementally from many yann@1860: smaller source root directories, or if your destination root directory yann@1860: is an NFS export that your target mounts as / (and you don't want to yann@1860: re-run exportfs -av everytime). USE WITH CARE! yann@258: yann@1352: -v Be verbose. By default, populate is absolutely silent. yann@910: yann@217: _EOF_ yann@217: } yann@217: yann@217: CT_ROOT_SRC_DIR= yann@217: CT_ROOT_DST_DIR= yann@910: CT_LIB_LIST= yann@910: CT_LIB_FILE= yann@1860: CT_MERGE= yann@1860: CT_FORCE= yann@1352: CT_PRINTF=: yann@1177: OPTIND=1 yann@1860: while getopts ":s:d:r:l:L:fmvh" CT_OPT; do yann@217: case "${CT_OPT}" in yann@217: s) CT_ROOT_SRC_DIR="${OPTARG}";; yann@217: d) CT_ROOT_DST_DIR="${OPTARG}";; ncase@1859: r) CT_SYSROOT_DIR="${OPTARG}";; yann@910: l) CT_LIB_LIST="${CT_LIB_LIST}:${OPTARG}";; yann@910: L) CT_LIB_FILE="${OPTARG}";; yann@259: f) CT_FORCE=y;; yann@1860: m) CT_MERGE=y;; yann@1352: v) CT_PRINTF=printf;; yann@217: h) doHelp yann@217: exit 0 yann@217: ;; yann@1863: :) printf "$myname: '-${OPTARG}' takes exactly one argument.\n" yann@217: exit 1 yann@217: ;; yann@1863: ?) printf "$myname: unknown option '-${OPTARG}'.\n" yann@217: exit 1 yann@217: ;; yann@217: esac yann@217: done yann@217: yann@217: # Sanity checks yann@217: if [ -z "${CT_ROOT_SRC_DIR}" -o -z "${CT_ROOT_DST_DIR}" ]; then yann@217: doHelp yann@217: exit 1 yann@217: fi yann@217: if [ ! -d "${CT_ROOT_SRC_DIR}" ]; then yann@1863: printf "$myname: '${CT_ROOT_SRC_DIR}': no such file or directory\n" yann@217: exit 1 yann@217: fi ncase@1859: if [ ! -d "${CT_SYSROOT_DIR}" ]; then yann@1863: printf "$myname: '${CT_SYSROOT_DIR}': no such file or directory\n" ncase@1859: exit 1 ncase@1859: fi yann@1860: # If the dest dir does not exist, all is well yann@1860: # If merging, we accept an existing dest directory yann@1860: # If forcing and not merging, we remove an exiting dest directory yann@1860: # If not forcing and not merging, we do not accept an exiting dest directory yann@1860: if [ -d "${CT_ROOT_DST_DIR}" ]; then yann@1860: case "${CT_FORCE}:${CT_MERGE}" in yann@1860: *:y) ;; yann@1860: y:) rm -rf "${CT_ROOT_DST_DIR}";; yann@1863: :) printf "$myname: '${CT_ROOT_DST_DIR}': already exists\n" yann@1863: exit 1 yann@1863: ;; yann@1860: esac yann@217: fi yann@1863: src_inode=$(ls -1id "${CT_ROOT_SRC_DIR}/." |awk '{ print $1 }') yann@1863: dst_inode=$(ls -1id "${CT_ROOT_DST_DIR}/." 2>/dev/null |awk '{ print $1 }') yann@1352: if [ "${src_inode}" -eq "$((dst_inode+0))" ]; then yann@1863: printf "$myname: source and destination are the same!\n" yann@217: exit 1 yann@217: fi yann@217: yann@910: # Check existence of the forced libraries file yann@910: if [ -n "${CT_LIB_FILE}" -a ! \( -f "${CT_LIB_FILE}" -a -r "${CT_LIB_FILE}" \) ]; then yann@1863: printf "$myname: forced libraries file '${CT_LIB_FILE}' not found!\n" yann@910: exit 1 yann@910: fi yann@910: yann@1860: # Create the working copy, no issue if already existing yann@217: mkdir -p "${CT_ROOT_DST_DIR}" yann@217: yann@217: # Make all path absolute yann@253: CT_ROOT_SRC_DIR=$(cd "${CT_ROOT_SRC_DIR}"; pwd) yann@253: CT_ROOT_DST_DIR=$(cd "${CT_ROOT_DST_DIR}"; pwd) yann@1863: CT_SYSROOT_DIR=$(cd "${CT_SYSROOT_DIR}"; pwd) yann@217: yann@1678: # Populate the destination directory with files from the source directory yann@1863: cd "${CT_ROOT_SRC_DIR}" yann@1678: cp -a . "${CT_ROOT_DST_DIR}" yann@1863: cd - >/dev/null yann@910: yann@910: # A function do search for a library yann@910: # Usage: do_add_lib libname yann@910: # returns: 0 if library was found and added, !0 otherwise yann@910: do_add_lib() { yann@910: local libname="$1" yann@910: local true_libname yann@1177: local dir yann@1352: local mode yann@1352: yann@1177: for dir in lib usr/lib; do yann@1864: if [ -e "${dir}/${libname}" ]; then yann@1864: ${CT_PRINTF} " already present\n" yann@1864: return 0 yann@1864: fi yann@1864: done yann@1864: for dir in lib usr/lib; do yann@1352: ${CT_PRINTF} " trying in '%s'" "${dir}" yann@1177: libfile="${CT_SYSROOT_DIR}/${dir}/${libname}" yann@1352: ${CT_PRINTF} ": '%s'\n" "${libfile}" yann@910: if [ -e "${libfile}" ]; then yann@1177: mkdir -p "${dir}" yann@1177: true_libname=$("${CT_READELF}" -d "${libfile}" \ yann@1177: |"${grep}" "Library soname:" \ yann@1177: |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;' \ yann@1177: ) yann@1352: case "${libfile}" in yann@1352: */ld*) mode=0755;; yann@1352: *) mode=0644;; yann@1352: esac yann@1352: ${CT_PRINTF} " installing as '%s/%s', mode='%s'\n" "${dir}" "${true_libname}" "${mode}" yann@1352: "${install}" -m "${mode}" "${libfile}" "${dir}/${true_libname}" yann@1864: do_resolve_deps "${dir}/${true_libname}" yann@1177: return 0 yann@910: fi yann@910: done yann@1177: return 1 yann@910: } yann@910: yann@1864: # A function to resolve all NEEDED entries for the given file, relative yann@1864: # to the working directory (eg. dst_dir) yann@1864: # Usage: do_resolve_deps some/where/some/file yann@1864: # Returns: 0, meaning all dependencies were found yann@1864: # If not all dependencies could be found, exists with error code 1 yann@1864: # (unless forced) yann@1864: do_resolve_deps() { yann@1864: local file="${1}" yann@1864: local libname yann@1864: yann@1864: for libname in $("${CT_READELF}" -d "${file}" \ yann@1864: |"${grep}" -E '\(NEEDED\)[[:space:]]+Shared library:' \ yann@1864: |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;' \ yann@1864: ); do yann@1864: [ -n "${libname}" ] || continue yann@1864: ${CT_PRINTF} "Searching for '%s' needed by '%s'\n" "${libname}" "${file}" yann@1864: if ! do_add_lib "${libname}"; then yann@1864: printf "$myname: library '${libname}' not found!\n" yann@1864: [ "${CT_FORCE}" = "y" ] || exit 1 yann@1864: fi yann@1864: done yann@1864: } yann@1864: yann@1352: # We'll work in the copied rootfs yann@1863: cd "${CT_ROOT_DST_DIR}" yann@1352: yann@910: # First of, copy the forced libraries into the working copy yann@1862: lib_list= yann@910: if [ -n "${CT_LIB_FILE}" ]; then yann@1177: lib_list=$("${sed}" -r -e ':loop; s/#.*//;' \ yann@1177: -e 's/[[:space:]]+//g;' \ yann@1177: -e 's/([^:])$/\1:/;' \ yann@1177: -e '/$/N; s/\n//; tloop;' \ yann@1177: "${CT_LIB_FILE}" yann@1177: ) yann@910: fi yann@1863: CT_LIB_LIST=$(printf "${CT_LIB_LIST}:${lib_list}\n" \ yann@1177: |"${sed}" -r -e 's/^:+//; s/:+$//; s/:+/ /g;' \ yann@1177: ) yann@1352: if [ -n "${CT_LIB_LIST}" ]; then yann@1352: for name in ${CT_LIB_LIST}; do yann@1352: [ -z "${name}" ] && continue yann@1352: found=0 yann@1352: for libname in "lib${name}.so" "${name}.so" "${name}"; do yann@1864: ${CT_PRINTF} "Searching for forced library '%s'\n" "${libname}" yann@1352: if do_add_lib "${libname}"; then yann@1352: found=1 yann@1352: break yann@1352: fi yann@1352: done yann@1352: if [ ${found} -eq 0 ]; then yann@1863: printf "$myname: library '${libname}' not found!\n" yann@1863: [ "${CT_FORCE}" = "y" ] || exit 1 yann@910: fi yann@910: done yann@1352: fi yann@217: yann@1864: # Create a temporary place where to store... temp files. yann@1864: rand="$( dd if=/dev/urandom bs=1024 count=1 2>/dev/null \ yann@1864: |md5sum \ yann@1864: |awk '{ print $1; }' yann@1864: )" yann@1864: CT_TMP_DIR="${TMPDIR:-/tmp}/populate-${rand}-${$}" yann@1864: ( umask 0077; mkdir "${CT_TMP_DIR}" ) || { printf "Could not create temporary directory\n"; exit 1; } yann@1864: trap "rm -rf ${CT_TMP_DIR}" EXIT yann@1864: yann@1864: # List all ELF (executables|shared objects)... yann@1864: find . -type f -exec file {} \; \ yann@1864: |"${grep}" -E ': ELF [[:digit:]]+-bit (L|M)SB (executable|shared object),' \ yann@1864: |cut -d ":" -f 1 \ yann@1864: >"${CT_TMP_DIR}/files.list" yann@1864: yann@1864: # ... and use that list to find missing dependencies yann@1864: while read file; do yann@1864: do_resolve_deps "${file}" yann@1864: done <"${CT_TMP_DIR}/files.list" yann@1864: yann@1864: rm -rf "${CT_TMP_DIR}" yann@1864: trap - EXIT yann@1352: yann@1352: # OK, we're done. Back off. yann@1863: cd - >/dev/null