scripts/populate.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Wed Mar 24 22:36:51 2010 +0100 (2010-03-24)
changeset 1860 ed94d8e12b63
parent 1859 f4e17e0e2574
child 1861 a5c020c3d31d
permissions -rw-r--r--
scripts/populate: add -m option, to merge source and dest

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