scripts/populate.in
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Sat Oct 06 23:48:07 2012 +0200 (2012-10-06)
changeset 3083 3a7b2eee9dcd
parent 2564 5d4e91c0343e
permissions -rw-r--r--
scripts: add option to start an interactive debug shell

Add an option that, when a command fails:
- starts an interactive shell with the failed command's environment
- attempts re-execution of the failed command, continues, or aborts
at user's whim.

Before starting the debug-shell, the backtrace is printed.
When exiting for an abort, the standard error message is printed.

Based on an idea and a patch from: Johannes Stezenbach <js@sig21.net>
http://sourceware.org/ml/crossgcc/2012-09/msg00144.html

Signed-off-by: Johannes Stezenbach <js@sig21.net>
[yann.morin.1998@free.fr: integrate in the fault handler]
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Acked-by: Johannes Stezenbach <js@sig21.net>
Patchwork-Id: 191571
Patchwork-Id: 191668
     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 sysroot). Actual library names are searched as
    61         follows (where 'name' is replaced with the given name) in the
    62         sysroot 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 useful 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         if [ -e "${dir}/${libname}" ]; then
   189             ${CT_PRINTF} "    already present\n"
   190             return 0
   191         fi
   192     done
   193     for dir in lib usr/lib; do
   194         ${CT_PRINTF} "    trying in '%s'" "${dir}"
   195         libfile="${CT_SYSROOT_DIR}/${dir}/${libname}"
   196         ${CT_PRINTF} ": '%s'\n" "${libfile}"
   197         if [ -e "${libfile}" ]; then
   198             mkdir -p "${dir}"
   199             true_libname=$("${CT_READELF}" -d "${libfile}"          \
   200                            |"${grep}" "Library soname:"             \
   201                            |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;'   \
   202                           )
   203             case "${libfile}" in
   204                 */ld*)  mode=0755;;
   205                 *)      mode=0644;;
   206             esac
   207             ${CT_PRINTF} "      installing as '%s/%s', mode='%s'\n" "${dir}" "${true_libname}" "${mode}"
   208             ${install} -m "${mode}" "${libfile}" "${dir}/${true_libname}"
   209             do_resolve_deps "${dir}/${true_libname}"
   210             return 0
   211         fi
   212     done
   213     return 1
   214 }
   215 
   216 # A function to resolve all NEEDED entries for the given file, relative
   217 # to the working directory (eg. dst_dir)
   218 # Usage: do_resolve_deps some/where/some/file
   219 # Returns: 0, meaning all dependencies were found
   220 # If not all dependencies could be found, exists with error code 1
   221 # (unless forced)
   222 do_resolve_deps() {
   223     local file="${1}"
   224     local libname
   225     
   226     for libname in $("${CT_READELF}" -d "${file}"                           \
   227                      |"${grep}" -E '\(NEEDED\)[[:space:]]+Shared library:'  \
   228                      |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;'                 \
   229                     ); do
   230         [ -n "${libname}" ] || continue
   231         ${CT_PRINTF} "Searching for '%s' needed by '%s'\n" "${libname}" "${file}"
   232         if ! do_add_lib "${libname}"; then
   233             printf "$myname: library '${libname}' not found!\n"
   234             [ "${CT_FORCE}" = "y" ] || exit 1
   235         fi
   236     done
   237 }
   238 
   239 # We'll work in the copied rootfs
   240 cd "${CT_ROOT_DST_DIR}"
   241 
   242 # First of, copy the forced libraries into the working copy
   243 lib_list=
   244 if [ -n "${CT_LIB_FILE}" ]; then
   245     lib_list=$("${sed}" -r -e ':loop; s/#.*//;'         \
   246                            -e 's/[[:space:]]+//g;'      \
   247                            -e 's/([^:])$/\1:/;'         \
   248                            -e '/$/N; s/\n//; tloop;'    \
   249                         "${CT_LIB_FILE}"
   250               )
   251 fi
   252 CT_LIB_LIST=$(printf "${CT_LIB_LIST}:${lib_list}\n"         \
   253               |"${sed}" -r -e 's/^:+//; s/:+$//; s/:+/ /g;' \
   254              )
   255 if [ -n "${CT_LIB_LIST}" ]; then
   256     for name in ${CT_LIB_LIST}; do
   257         [ -z "${name}" ] && continue
   258         found=0
   259         for libname in "lib${name}.so" "${name}.so" "${name}"; do
   260             ${CT_PRINTF} "Searching for forced library '%s'\n" "${libname}"
   261             if do_add_lib "${libname}"; then
   262                 found=1
   263                 break
   264             fi
   265         done
   266         if [ ${found} -eq 0 ]; then
   267             printf "$myname: library '${libname}' not found!\n"
   268             [ "${CT_FORCE}" = "y" ] || exit 1
   269         fi
   270     done
   271 fi
   272 
   273 # Create a temporary place where to store... temp files.
   274 rand="$( dd if=/dev/urandom bs=1024 count=1 2>/dev/null \
   275          |md5sum                                        \
   276          |awk '{ print $1; }'
   277        )"
   278 CT_TMP_DIR="${TMPDIR:-/tmp}/populate-${rand}-${$}"
   279 ( umask 0077; mkdir "${CT_TMP_DIR}" ) || { printf "Could not create temporary directory\n"; exit 1; }
   280 trap "rm -rf ${CT_TMP_DIR}" EXIT
   281 
   282 # List all ELF (executables|shared objects)...
   283 find . -type f -exec file {} \;                                             \
   284 |"${grep}" -E ': ELF [[:digit:]]+-bit (L|M)SB (executable|shared object),'  \
   285 |cut -d ":" -f 1                                                            \
   286 >"${CT_TMP_DIR}/files.list"
   287 
   288 # ... and use that list to find missing dependencies
   289 while read file; do
   290     do_resolve_deps "${file}"
   291 done <"${CT_TMP_DIR}/files.list"
   292 
   293 rm -rf "${CT_TMP_DIR}"
   294 trap - EXIT
   295 
   296 # OK, we're done. Back off.
   297 cd - >/dev/null