scripts/populate.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Mar 28 23:01:19 2010 +0200 (2010-03-28)
changeset 1863 11cc7a5102fa
parent 1862 7fec5db8933c
child 1864 758d5137fe87
permissions -rw-r--r--
scripts/populate: cleanups and misc fixes

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