#!/bin/bash

# pulled right out of mkinitrd....
export LD_HWCAP_MASK=0
DSO_DEPS=""
LDSO=""
get_dso_deps() {
    root="$1" ; shift
    bin="$1" ; shift
    LDSODIR="$1" ; shift
    DSO_DEPS=""

    declare -a FILES
    declare -a NAMES
    [ -z "$LDSODIR" ] && LDSODIR=$LIBDIR

    # this is a hack, but the only better way requires binutils or elfutils
    # be installed.  i.e., we need readelf to find the interpretter.
    if [ -n "$LDSO" ]; then
        $LDSO --verify $root/$bin >/dev/null 2>&1
        case $? in
          [02]) ;;
            *) unset LDSO ;;
        esac
    fi
    if [ -z "$LDSO" ]; then
        for ldso in $root/$LDSODIR/ld*.so* ; do
            [ -L $ldso ] && continue
            [ -x $ldso ] || continue
            $ldso --verify $root/$bin >/dev/null 2>&1
            case $? in
                [02]) LDSO=$(echo $ldso |sed -e "s,$root,,") ; break ;;
            esac
        done
    fi

    # I still hate shell.
    declare -i n=0
    while read NAME I0 FILE ADDR I1 ; do
        [ "$FILE" == "not" ] && FILE="$FILE $ADDR"
        NAMES[$n]="$NAME"
        FILES[$n]="$FILE"
        let n++
    done << EOF
        $(/usr/sbin/chroot $root env --unset=LD_LIBRARY_PATH \
                                     LD_TRACE_PRELINKING=1 LD_WARN= \
                                     LD_TRACE_LOADED_OBJECTS=1 $LDSO $bin)
EOF

    [ ${#FILES[*]} -eq 0 ] && return 1

    # we don't want the name of the binary in the list
    if [ "${FILES[0]}" == "$bin" ]; then
        FILES[0]=""
        NAMES[0]=""
        [ ${#FILES[*]} -eq 1 ] && return 1
    fi

    declare -i n=0
    while [ $n -lt ${#FILES[*]} ]; do
        FILE="${FILES[$n]}"
        if [ "$FILE" == "not found" ]; then
            echo "WARNING: The dynamic object $bin requires ${NAMES[$n]} n order to properly function."
            continue
        fi
       case "$FILE" in
         /lib*)
           TLIBDIR=`echo "$FILE" | sed 's,\(/lib[^/]*\)/.*$,\1,'`
           BASE=`basename "$FILE"`
           # Prefer nosegneg libs over direct segment accesses on i686.
           if [ -f "$TLIBDIR/i686/nosegneg/$BASE" ]; then
             FILE="$TLIBDIR/i686/nosegneg/$BASE"
           # Otherwise, prefer base libraries rather than their optimized
           # variants.
           elif [ -f "$TLIBDIR/$BASE" ]; then
             FILE="$TLIBDIR/$BASE"
           fi
           ;;
       esac
        dynamic="yes"
        let n++
    done

    DSO_DEPS="${FILES[@]}"

    for l in $(/usr/sbin/chroot $root find /$LDSODIR -maxdepth 1 -type l -name ld*.so*); do
       [ "$(/usr/sbin/chroot $root readlink -f $l)" == "$LDSO" ] && DSO_DEPS="$DSO_DEPS $l"
    done
    if [ "$(uname -m)" == "s390x" ]; then
       for l in $(/usr/sbin/chroot $root find /lib -maxdepth 1 -type l -name ld*.so*); do
          [ "$(/usr/sbin/chroot $root readlink -f $l)" == "$LDSO" ] && DSO_DEPS="$DSO_DEPS $l"
       done
    fi

    [ -n "$DEBUG" ] && echo "DSO_DEPS for $bin are $DSO_DEPS"
}

instFile() {
    FILE=$1
    DESTROOT=$2

    [ -n "$DEBUG" ] && echo "Installing $FILE"
    if [ -e $DESTROOT/$FILE -o -L $DESTROOT/$FILE ]; then
      return
    elif [ ! -d $DESTROOT/`dirname $FILE` ]; then
      mkdir -p $DESTROOT/`dirname $FILE`
    fi
    if [ -L $FILE ]; then
	cp -al $FILE $DESTROOT/`dirname $FILE`
	instFile ./`dirname $FILE`/`readlink $FILE` $DESTROOT
	return
    else
	cp -aL $FILE $DESTROOT/`dirname $FILE`
    fi

    f=$(file $FILE)
    echo $f | egrep -q ": (setuid )?ELF" &&
    echo $f | egrep -qv "statically linked" &&  {
        if echo $f | grep -q " 64-bit " ; then
            get_dso_deps $(pwd) "$FILE" lib64
        else
            get_dso_deps $(pwd) "$FILE" lib
        fi
        local DEPS="$DSO_DEPS"
        for x in $DEPS ; do
            instFile ./$x $DESTROOT
        done
    }
    unset f
}

instDir() {
    DIR=$1
    DESTROOT=$2

    [ -n "$DEBUG" ] && echo "Installing $DIR"
    if [ -d $DESTROOT/$DIR -o -h $DESTROOT/$DIR ]; then
      return
    fi
    cp -a --parents $DIR $DESTROOT/
}

