scripts/populate.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Fri Mar 26 23:17:23 2010 +0100 (2010-03-26)
changeset 1862 7fec5db8933c
parent 1861 a5c020c3d31d
child 1863 11cc7a5102fa
permissions -rw-r--r--
scripts/populate: fix handling the forced libraries list-file

If a list-file is used, then each library in the file will be handled
twice (not a real issue, as the second iteration will find the library
already present, just avoid doing the job twice).
     1 #!@@CT_bash@@
     2 # This script will populate the root directory with libs from the sysroot.
     3 # (C) 2007 Yann E. MORIN
     4 # Licensed under the GPL v2
     5 set -e
     6 
     7 # Use the tools discovered by crosstool-NG's ./configure:
     8 install="@@CT_install@@"
     9 grep="@@CT_grep@@"
    10 sed="@@CT_sed@@"
    11 
    12 # Detect where the toolchain is:
    13 CT_PREFIX_DIR="$(cd "$(dirname "$0")/.."; pwd)"
    14 CT_GCC="${0%-populate}-gcc"
    15 CT_READELF="${0%-populate}-readelf"
    16 CT_CFG_PREFIX_DIR="$("${CT_GCC}" -v 2>&1            \
    17                      |tr ' ' '\n'                   \
    18                      |"${grep}" -E -- '--prefix='   \
    19                      |cut -d = -f 2-
    20                     )"
    21 CT_CFG_SYSROOT_DIR="$("${CT_GCC}" -v 2>&1                   \
    22                       |tr ' ' '\n'                          \
    23                       |"${grep}" -E -- '--with-sysroot='    \
    24                       |cut -d = -f 2-
    25                      )"
    26 CT_SYSROOT_DIR="$(echo "${CT_CFG_SYSROOT_DIR}"                                  \
    27                   |"${sed}" -r -e "s:^${CT_CFG_PREFIX_DIR}:${CT_PREFIX_DIR}:;"  \
    28                   |"${sed}" -r -e 's,/+,/,g;'                                   \
    29                  )"
    30 
    31 myname=$(basename "$0")
    32 
    33 doHelp() {
    34     cat <<_EOF_
    35 NAME
    36     $myname - populate the target root file system
    37 
    38 SYNOPSIS
    39     $myname OPTIONS -s source_root -d destination_root
    40 
    41 DESCRIPTION
    42     $myname will 'populate' your target root file system ('src_dir') with
    43     libraries from the toolchain (eg. libc.so...), storing the result into
    44     'dst_dir'.
    45 
    46 OPTIONS
    47     -s src_dir
    48         use 'src_dir' as the un-populated (source) root directory
    49 
    50     -d dst_dir
    51         use 'dst_dir' as the place to put the populated root directory
    52 
    53     -r sysroot_dir
    54         use 'sysroot_dir' as the sysroot instead of the toolchain default
    55 
    56     -l name1[:name2[...]]
    57         Always add the specified shared library/ies name1, name2... from the
    58         toolchain (in the sys-root). Actual library names are searched as
    59         follows (where 'name' is replaced with the given name) in the
    60         sys-root directory:
    61           - libname.so
    62           - name.so
    63           - name
    64         If the file is found, then the SONAME of the library is used, and the
    65         library is copied with that name. If the library was not found, this
    66         yields an error (unless -f was given).
    67 
    68     -L file
    69         Read 'file' for a list of shared libraries to always add from the
    70         toolchain. The file should contain one library name per line; text
    71         after a # is ignored until the end of the line; spaces are ignored;
    72         empty lines are ignored. Libraries are searched for as with -l.
    73 
    74     -f  force execution: if destination directory already exists, it will be
    75         removed first; if a specified library (above) was not found, continue.
    76         Note: if using -m and the destination directory already exists, it
    77         is *not* removed, see below.
    78 
    79     -m  Merge the source root directory with the destination root directory.
    80         If the latter does not exist, it is created, and -m is ignored.
    81         If the destination droot directory exists, then the content of the
    82         source root directory is copied in there, and the result is populated
    83         as usual.
    84         It can be usefull if constructing a rootfs incrementally from many
    85         smaller source root directories, or if your destination root directory
    86         is an NFS export that your target mounts as / (and you don't want to
    87         re-run exportfs -av everytime). USE WITH CARE!
    88 
    89     -v  Be verbose. By default, populate is absolutely silent.
    90 
    91 _EOF_
    92 }
    93 
    94 CT_ROOT_SRC_DIR=
    95 CT_ROOT_DST_DIR=
    96 CT_LIB_LIST=
    97 CT_LIB_FILE=
    98 CT_MERGE=
    99 CT_FORCE=
   100 CT_PRINTF=:
   101 OPTIND=1
   102 while getopts ":s:d:r:l:L:fmvh" CT_OPT; do
   103     case "${CT_OPT}" in
   104         s)  CT_ROOT_SRC_DIR="${OPTARG}";;
   105         d)  CT_ROOT_DST_DIR="${OPTARG}";;
   106         r)  CT_SYSROOT_DIR="${OPTARG}";;
   107         l)  CT_LIB_LIST="${CT_LIB_LIST}:${OPTARG}";;
   108         L)  CT_LIB_FILE="${OPTARG}";;
   109         f)  CT_FORCE=y;;
   110         m)  CT_MERGE=y;;
   111         v)  CT_PRINTF=printf;;
   112         h)  doHelp
   113             exit 0
   114             ;;
   115         :)  echo "$myname: '-${OPTARG}' takes exactly one argument."
   116             exit 1
   117             ;;
   118         ?)  echo "$myname: unknown option '-${OPTARG}'."
   119             exit 1
   120             ;;
   121     esac
   122 done
   123 
   124 # Sanity checks
   125 if [ -z "${CT_ROOT_SRC_DIR}" -o -z "${CT_ROOT_DST_DIR}" ]; then
   126     doHelp
   127     exit 1
   128 fi
   129 if [ ! -d "${CT_ROOT_SRC_DIR}" ]; then
   130     echo "$myname: '${CT_ROOT_SRC_DIR}': no such file or directory"
   131     exit 1
   132 fi
   133 if [ ! -d "${CT_SYSROOT_DIR}" ]; then
   134     echo "$myname: '${CT_SYSROOT_DIR}': no such file or directory"
   135     exit 1
   136 fi
   137 # If the dest dir does not exist, all is well
   138 # If merging, we accept an existing dest directory
   139 # If forcing and not merging, we remove an exiting dest directory
   140 # If not forcing and not merging, we do not accept an exiting dest directory
   141 if [ -d "${CT_ROOT_DST_DIR}" ]; then
   142     case "${CT_FORCE}:${CT_MERGE}" in
   143         *:y)    ;;
   144         y:)     rm -rf "${CT_ROOT_DST_DIR}";;
   145         :)      echo "$myname: '${CT_ROOT_DST_DIR}': already exists" && exit 1 ;;
   146     esac
   147 fi
   148 src_inode=$(stat -c '%i' "${CT_ROOT_SRC_DIR}/.")
   149 dst_inode=$(stat -c '%i' "${CT_ROOT_DST_DIR}/." 2>/dev/null || true)
   150 if [ "${src_inode}" -eq "$((dst_inode+0))" ]; then
   151     echo "$myname: source and destination are the same!"
   152     exit 1
   153 fi
   154 
   155 # Check existence of the forced libraries file
   156 if [ -n "${CT_LIB_FILE}" -a ! \( -f "${CT_LIB_FILE}" -a -r "${CT_LIB_FILE}" \) ]; then
   157     echo "$myname: forced libraries file '${CT_LIB_FILE}' not found!"
   158     exit 1
   159 fi
   160 
   161 # Create the working copy, no issue if already existing
   162 mkdir -p "${CT_ROOT_DST_DIR}"
   163 
   164 # Make all path absolute
   165 CT_ROOT_SRC_DIR=$(cd "${CT_ROOT_SRC_DIR}"; pwd)
   166 CT_ROOT_DST_DIR=$(cd "${CT_ROOT_DST_DIR}"; pwd)
   167 
   168 # Populate the destination directory with files from the source directory
   169 pushd "${CT_ROOT_SRC_DIR}" >/dev/null
   170 cp -a . "${CT_ROOT_DST_DIR}"
   171 popd >/dev/null
   172 
   173 # A function do search for a library
   174 # Usage: do_add_lib libname
   175 # returns: 0 if library was found and added, !0 otherwise
   176 do_add_lib() {
   177     local libname="$1"
   178     local true_libname
   179     local dir
   180     local mode
   181 
   182     for dir in lib usr/lib; do
   183         ${CT_PRINTF} "    trying in '%s'" "${dir}"
   184         libfile="${CT_SYSROOT_DIR}/${dir}/${libname}"
   185         ${CT_PRINTF} ": '%s'\n" "${libfile}"
   186         if [ -e "${libfile}" ]; then
   187             mkdir -p "${dir}"
   188             true_libname=$("${CT_READELF}" -d "${libfile}"          \
   189                            |"${grep}" "Library soname:"             \
   190                            |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;'   \
   191                           )
   192             case "${libfile}" in
   193                 */ld*)  mode=0755;;
   194                 *)      mode=0644;;
   195             esac
   196             ${CT_PRINTF} "      installing as '%s/%s', mode='%s'\n" "${dir}" "${true_libname}" "${mode}"
   197             "${install}" -m "${mode}" "${libfile}" "${dir}/${true_libname}"
   198             return 0
   199             break
   200         fi
   201     done
   202     return 1
   203 }
   204 
   205 # We'll work in the copied rootfs
   206 pushd "${CT_ROOT_DST_DIR}" >/dev/null
   207 
   208 # First of, copy the forced libraries into the working copy
   209 lib_list=
   210 if [ -n "${CT_LIB_FILE}" ]; then
   211     lib_list=$("${sed}" -r -e ':loop; s/#.*//;'         \
   212                            -e 's/[[:space:]]+//g;'      \
   213                            -e 's/([^:])$/\1:/;'         \
   214                            -e '/$/N; s/\n//; tloop;'    \
   215                         "${CT_LIB_FILE}"
   216               )
   217 fi
   218 CT_LIB_LIST=$(echo "${CT_LIB_LIST}:${lib_list}"             \
   219               |"${sed}" -r -e 's/^:+//; s/:+$//; s/:+/ /g;' \
   220              )
   221 if [ -n "${CT_LIB_LIST}" ]; then
   222     ${CT_PRINTF} "Installing forced libraries...\n"
   223     for name in ${CT_LIB_LIST}; do
   224         [ -z "${name}" ] && continue
   225         found=0
   226         for libname in "lib${name}.so" "${name}.so" "${name}"; do
   227             ${CT_PRINTF} "  searching for '%s'\n" "${libname}"
   228             if do_add_lib "${libname}"; then
   229                 found=1
   230                 break
   231             fi
   232         done
   233         if [ ${found} -eq 0 ]; then
   234             echo "$myname: library '${libname}' not found!"
   235             [ "${CT_FORCE}" = y ] || exit 1
   236         fi
   237     done
   238 fi
   239 
   240 # Parse the working copy for executables and libraries
   241 still_needed=1
   242 while [ ${still_needed} -eq 1 ]; do
   243     ${CT_PRINTF} "Looping...\n"
   244     still_needed=0
   245     for f in $(find . -type f -exec file {} \;                                              \
   246                |"${grep}" -E ': ELF [[:digit:]]+-bit (L|M)SB (executable|shared object),'   \
   247                |cut -d ":" -f 1                                                             \
   248               ); do
   249         ${CT_PRINTF} "Scanning '%s'\n" "${f}"
   250         for libname in $("${CT_READELF}" -d "${f}"                              \
   251                          |"${grep}" -E '\(NEEDED\)[[:space:]]+Shared library:'  \
   252                          |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;'                 \
   253                         ); do
   254             ${CT_PRINTF} "  searching for '%s'\n" "${libname}"
   255             if [    -e "lib/${libname}"     \
   256                  -o -e "usr/lib/${libname}" ]; then
   257                 ${CT_PRINTF} "    already present\n"
   258                 continue
   259             fi
   260             if do_add_lib "${libname}"; then
   261                 still_needed=1
   262             else
   263                 echo "$myname: library '${libname}' not found!"
   264             fi
   265         done
   266     done
   267 done
   268 
   269 # OK, we're done. Back off.
   270 popd >/dev/null