From 840893e2b37470749d11e249becdba40b91adc92 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Fri, 17 Jun 2011 20:01:35 -0400 Subject: properly support $BASEDIR This add proper support for a $BASEDIR, wherein as much as possible is taken from the user specified root, instead of mixing and matching binaries and modules. This avoids conflicts, particularly with binaries like udev or module-init-tools which may have newer functionality that the root in the $BASEDIR requires. This is somewhat of a large patch, which involves a few key changes: 1) Add a new class of "private" functions: _add_*, which act as a "back end" for the equivalent non-underscore-prefixed functions. 2) Refactor the add_* family of functions to use these new back end functions. This generally simplifies the logic as we have a clear division of labor. 3) Instead of using ldd, which is a glorified wrapper around the RTLD, create a wrapper around the RTLD and invoke it ourselves. This is basically just a small performance improvement -- the bulk of the parsing done by this function's output is done in pure bash. Signed-off-by: Dave Reisner --- functions | 139 +++++++++++++++++++++++++++++++++++++++---------------------- mkinitcpio | 20 ++++++++- 2 files changed, 108 insertions(+), 51 deletions(-) diff --git a/functions b/functions index 580e636..ab0f850 100644 --- a/functions +++ b/functions @@ -124,10 +124,11 @@ add_dir() { # Add a directory to the initcpio image. # $1: absolute path of directory on image - if [[ ! -e "$BUILDROOT/$1" ]]; then - (( QUIET )) || plain "adding dir: %s" "$1" - command install -dm755 "$BUILDROOT/$1" - fi + (( ! $# )) && return 1 + + local path=$1 mode=${2:-755} + + _add_dir "$path" "$mode" } add_symlink() { @@ -135,13 +136,10 @@ add_symlink() { # $1: pathname of symlink on image # $2: absolute path to target of symlink - local file=$1 dest=$2 + (( $# == 2 )) || return 1 - add_dir $(get_dirname "$file") - if [[ ! -e "$TMPDIR/root/$dest" ]]; then - (( QUIET )) || plain "adding symlink: $file -> $dest" - ln -s "$dest" "$BUILDROOT/$file" - fi + _add_dir "$(get_dirname "$1")" + _add_symlink "$2" "$1" } add_file() { @@ -150,26 +148,22 @@ add_file() { # $1: path to file # $2: destination on initcpio (optional, defaults to same as source) - local file dest + (( $# )) || return 1 - file=$1 - dest=${2:-${file##$BASEDIR}} + # determine source and destination + local src= dest=${2:-$1} mode= - if [[ -f "$file" ]]; then - if [[ -L "$file" ]]; then - add_symlink "$file" "$(readlink -f "$file")" - add_file "$(readlink -f "$file")" - return - fi + src=$BASEDIR$1 - if [[ ! -e "$BUILDROOT/$dest" ]]; then - (( QUIET )) || plain "adding file: %s" "$dest" - command install -Dm$(stat -c '%a' "$file") "$file" "$BUILDROOT/$dest" - fi - else - error "file '$file' does not exist" + [[ -f "$src" ]] || { error "$src: No such file"; return 1; } + + mode=$(stat -c %a "$src") + if [[ -z "$mode" ]]; then + error "failed to stat file: \`$src'" return 1 fi + + _add_file "${dest#$BASEDIR}" "$src" "$mode" } add_module() { @@ -213,40 +207,85 @@ add_module() { esac } +_ldd() { + LD_TRACE_LOADED_OBJECTS=1 "$LD_SO" "$@" +} + +_add_file() { + # add a file to $BUILDROOT + # $1: pathname on initcpio + # $2: source on disk + # $3: mode + + (( $# == 3 )) || return $EINVAL + [[ -e "$BUILDROOT$1" ]] && return $EEXIST + + (( QUIET )) || plain "adding file: %s" "$1" + install -Dm$3 "$2" "$BUILDROOT$1" +} + +_add_dir() { + # add a directory (with parents) to $BUILDROOT + # $1: pathname on initcpio + # $2: mode + + (( $# == 2 )) || [[ "$1" == /?* ]] || return 1 # bad args + [[ -e "$BUILDROOT$1" ]] && return 0 # file exists + + (( QUIET )) || plain "adding dir: %s" "$1" + command install -dm$2 "$BUILDROOT$1" +} + +_add_symlink() { + # add a symlink to $buildroot + # $1: name on initcpio + # $2: target of $1 + + (( $# == 2 )) || return $EINVAL + [[ -L "$BUILDROOT$1" ]] && return $EEXIST + + (( QUIET )) || plain "adding symlink: %s -> %s" "$2" "$1" + ln -s "$2" "$BUILDROOT$1" +} + add_binary() { # add a binary file to the initcpio image. library dependencies will # be discovered and added. # $1: path to binary # $2: destination on initcpio (optional, defaults to same as source) - local bin dest lib + local -a sodeps + local regex binary dest mode sodep resolved dirname - bin=$(type -P "$1") - dest=$2 + binary=$BASEDIR$1 - if [[ ! -f "$bin" ]]; then - error "'$1' is not a file" - return 1 - fi + [[ -f "$binary" ]] || { error "$binary not found"; return 1; } - case "$(file -b "$bin")" in - *script*) - plain "adding '$type' script, ensure proper interp exists..." - add_file "$bin" ${dest+"$dest"} - ;; - *executable*|*shared\ object*|*symbolic\ link*) - add_file "$bin" ${dest+"$dest"} - # note, this will also handle 'not a dynamic executable' spit out - # by static binaries... the deps will produce nothing - while read -r lib; do - [[ -f "$lib" ]] && add_file "$lib" - done < <(ldd "$bin" 2>/dev/null | sed '1d;s|.*=>\(.*\)|\1|;s/(0x[0-9a-f]\+)//') - ;; - *) - error "unknown type '$type' for binary '$bin'" - return 1 - ;; - esac + dest=${2:-$binary} + mode=$(stat -c %a "$binary") + + # always add the binary itself + _add_file "${dest#$BASEDIR}" "${binary#$BASEDIR}" "$mode" + + $LD_SO --verify "$binary" &>/dev/null || return # not a binary! + + # resolve sodeps + regex='^[[:space:]]*[^/].+ => (.*) \(.*\)' + while read line; do + [[ "$line" =~ $regex ]] && sodep=${BASH_REMATCH[1]} || continue + + if [[ -f "$sodep" ]]; then # -f follows symlinks, don't believe it! + if [[ ! -L $sodep ]]; then + _add_file "$sodep" "$BASEDIR$sodep" "$(stat -c %a "$sodep")" + else + resolved=$(readlink -e "$basedir$sodep") + dirname=${resolved%/*} + _add_dir "${dirname#$basedir}" 755 + _add_symlink "$sodep" "${resolved#$BASEDIR}" + _add_file "${resolved#$BASEDIR}" "$resolved" 755 + fi + fi + done < <(_ldd "$binary") } parse_hook() { diff --git a/mkinitcpio b/mkinitcpio index 85e81b2..4082ba5 100755 --- a/mkinitcpio +++ b/mkinitcpio @@ -14,6 +14,7 @@ shopt -s extglob # Settings KERNELVERSION=$(uname -r) +CARCH=$(uname -m) FUNCTIONS=functions CONFIG=mkinitcpio.conf HOOKDIR=hooks @@ -21,7 +22,7 @@ INSTDIR=install PRESETDIR=mkinitcpio.d COMPRESSION=gzip -declare TMPDIR BASEDIR MODULE_FILE GENIMG PRESET COMPRESSION_OPTIONS BUILDROOT +declare TMPDIR BASEDIR MODULE_FILE GENIMG PRESET COMPRESSION_OPTIONS BUILDROOT LD_SO declare NC= BOLD= BLUE= GREEN= RED= YELLOW= declare -i QUIET=1 SHOW_AUTOMODS=0 SAVELIST=0 COLOR=1 declare -a SKIPHOOKS ADDED_MODULES @@ -285,6 +286,23 @@ trap '[[ $FUNCNAME = parse_hook ]] && (( ++builderrors ))' ERR #parse 'global' hook, as defined in ${CONFIG} parse_hook +# resolve the linker and add it +case $CARCH in + i686) LD_SO=("$BASEDIR"/lib/ld-linux.so.?*) ;; + x86_64) LD_SO=("$BASEDIR"/lib/ld-linux-${CARCH//_/-}.so.?*) ;; + *) die "unknown architecture: $CARCH" ;; +esac + +if (( ${#LD_SO[*]} != 1 )); then # uh oh... + die "failed to resolve the location of /lib/ld.so. Please report this bug." +fi + +resolved=$(readlink -e "$LD_SO") +_add_dir "${resolved%/*}" 755 +_add_symlink "${LD_SO#$BASEDIR}" "${resolved#$BASEDIR}" +_add_file "${resolved#$BASEDIR}" "${resolved#$BASEDIR}" 755 +unset resolved + for hook in ${HOOKS}; do in_array "$hook" "${SKIPHOOKS[@]}" && continue unset MODULES BINARIES FILES SCRIPT -- cgit v1.2.3-24-g4f1b