drop support for QA_DT_HASH/QA_STRICT_DT_HASH
[portage.git] / bin / misc-functions.sh
index c3109981d006ff6901b4524632f88016aa6c5fde..55d37f29d2ac4e7de8becead69a731cf795ae79f 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 1999-2011 Gentoo Foundation
+# Copyright 1999-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 #
 # Miscellaneous shell functions that make use of the ebuild env but don't need
@@ -17,7 +17,9 @@ shift $#
 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}/ebuild.sh"
 
 install_symlink_html_docs() {
-       cd "${D}" || die "cd failed"
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local ED=${D} ;; esac
+       cd "${ED}" || die "cd failed"
        #symlink the html documentation (if DOC_SYMLINKS_DIR is set in make.conf)
        if [ -n "${DOC_SYMLINKS_DIR}" ] ; then
                local mydocdir docdir
@@ -41,7 +43,20 @@ install_symlink_html_docs() {
 }
 
 # replacement for "readlink -f" or "realpath"
+READLINK_F_WORKS=""
 canonicalize() {
+       if [[ -z ${READLINK_F_WORKS} ]] ; then
+               if [[ $(readlink -f -- /../ 2>/dev/null) == "/" ]] ; then
+                       READLINK_F_WORKS=true
+               else
+                       READLINK_F_WORKS=false
+               fi
+       fi
+       if ${READLINK_F_WORKS} ; then
+               readlink -f -- "$@"
+               return
+       fi
+
        local f=$1 b n=10 wd=$(pwd)
        while (( n-- > 0 )); do
                while [[ ${f: -1} = / && ${#f} -gt 1 ]]; do
@@ -64,11 +79,13 @@ canonicalize() {
 prepcompress() {
        local -a include exclude incl_d incl_f
        local f g i real_f real_d
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local ED=${D} ;; esac
 
        # Canonicalize path names and check for their existence.
-       real_d=$(canonicalize "${D}")
+       real_d=$(canonicalize "${ED}")
        for (( i = 0; i < ${#PORTAGE_DOCOMPRESS[@]}; i++ )); do
-               real_f=$(canonicalize "${D}${PORTAGE_DOCOMPRESS[i]}")
+               real_f=$(canonicalize "${ED}${PORTAGE_DOCOMPRESS[i]}")
                f=${real_f#"${real_d}"}
                if [[ ${real_f} != "${f}" ]] && [[ -d ${real_f} || -f ${real_f} ]]
                then
@@ -79,7 +96,7 @@ prepcompress() {
                fi
        done
        for (( i = 0; i < ${#PORTAGE_DOCOMPRESS_SKIP[@]}; i++ )); do
-               real_f=$(canonicalize "${D}${PORTAGE_DOCOMPRESS_SKIP[i]}")
+               real_f=$(canonicalize "${ED}${PORTAGE_DOCOMPRESS_SKIP[i]}")
                f=${real_f#"${real_d}"}
                if [[ ${real_f} != "${f}" ]] && [[ -d ${real_f} || -f ${real_f} ]]
                then
@@ -128,7 +145,7 @@ prepcompress() {
 
        # Split the include list into directories and files
        for f in "${include[@]}"; do
-               if [[ -d ${D}${f} ]]; then
+               if [[ -d ${ED}${f} ]]; then
                        incl_d[${#incl_d[@]}]=${f}
                else
                        incl_f[${#incl_f[@]}]=${f}
@@ -138,25 +155,89 @@ prepcompress() {
        # Queue up for compression.
        # ecompress{,dir} doesn't like to be called with empty argument lists.
        [[ ${#incl_d[@]} -gt 0 ]] && ecompressdir --queue "${incl_d[@]}"
-       [[ ${#incl_f[@]} -gt 0 ]] && ecompress --queue "${incl_f[@]/#/${D}}"
+       [[ ${#incl_f[@]} -gt 0 ]] && ecompress --queue "${incl_f[@]/#/${ED}}"
        [[ ${#exclude[@]} -gt 0 ]] && ecompressdir --ignore "${exclude[@]}"
        return 0
 }
 
 install_qa_check() {
-       local f x
+       local f i qa_var x
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local EPREFIX= ED=${D} ;; esac
+
+       cd "${ED}" || die "cd failed"
+
+       qa_var="QA_FLAGS_IGNORED_${ARCH/-/_}"
+       eval "[[ -n \${!qa_var} ]] && QA_FLAGS_IGNORED=(\"\${${qa_var}[@]}\")"
+       if [[ ${#QA_FLAGS_IGNORED[@]} -eq 1 ]] ; then
+               local shopts=$-
+               set -o noglob
+               QA_FLAGS_IGNORED=(${QA_FLAGS_IGNORED})
+               set +o noglob
+               set -${shopts}
+       fi
 
-       cd "${D}" || die "cd failed"
+       # Check for files built without respecting *FLAGS. Note that
+       # -frecord-gcc-switches must be in all *FLAGS variables, in
+       # order to avoid false positive results here.
+       # NOTE: This check must execute before prepall/prepstrip, since
+       # prepstrip strips the .GCC.command.line sections.
+       if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT} && \
+               [[ "${CFLAGS}" == *-frecord-gcc-switches* ]] && \
+               [[ "${CXXFLAGS}" == *-frecord-gcc-switches* ]] && \
+               [[ "${FFLAGS}" == *-frecord-gcc-switches* ]] && \
+               [[ "${FCFLAGS}" == *-frecord-gcc-switches* ]] ; then
+               rm -f "${T}"/scanelf-ignored-CFLAGS.log
+               for x in $(scanelf -qyRF '%k %p' -k \!.GCC.command.line "${ED}" | \
+                       sed -e "s:\!.GCC.command.line ::") ; do
+                       # Separate out file types that are known to support
+                       # .GCC.command.line sections, using the `file` command
+                       # similar to how prepstrip uses it.
+                       f=$(file "${x}") || continue
+                       [[ -z ${f} ]] && continue
+                       if [[ ${f} == *"SB executable"* ||
+                               ${f} == *"SB shared object"* ]] ; then
+                               echo "${x}" >> "${T}"/scanelf-ignored-CFLAGS.log
+                       fi
+               done
+
+               if [[ -f "${T}"/scanelf-ignored-CFLAGS.log ]] ; then
+
+                       if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then
+                               for x in "${QA_FLAGS_IGNORED[@]}" ; do
+                                       sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-CFLAGS.log
+                               done
+                       fi
+                       # Filter anything under /usr/lib/debug/ in order to avoid
+                       # duplicate warnings for splitdebug files.
+                       sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \
+                               -i "${T}"/scanelf-ignored-CFLAGS.log
+                       f=$(<"${T}"/scanelf-ignored-CFLAGS.log)
+                       if [[ -n ${f} ]] ; then
+                               __vecho -ne '\n'
+                               eqawarn "${BAD}QA Notice: Files built without respecting CFLAGS have been detected${NORMAL}"
+                               eqawarn " Please include the following list of files in your report:"
+                               eqawarn "${f}"
+                               __vecho -ne '\n'
+                               sleep 1
+                       else
+                               rm -f "${T}"/scanelf-ignored-CFLAGS.log
+                       fi
+               fi
+       fi
 
        export STRIP_MASK
        prepall
-       hasq "${EAPI}" 0 1 2 3 || prepcompress
+       has "${EAPI}" 0 1 2 3 || prepcompress
        ecompressdir --dequeue
        ecompress --dequeue
 
+       # Prefix specific checks
+       [[ ${ED} != ${D} ]] && install_qa_check_prefix
+
        f=
        for x in etc/app-defaults usr/man usr/info usr/X11R6 usr/doc usr/locale ; do
-               [[ -d $D/$x ]] && f+="  $x\n"
+               [[ -d ${ED}/$x ]] && f+="  $x\n"
        done
 
        if [[ -n $f ]] ; then
@@ -165,18 +246,30 @@ install_qa_check() {
                eqawarn "$f"
        fi
 
+       if [[ -d ${ED}/etc/udev/rules.d ]] ; then
+               f=
+               for x in $(ls "${ED}/etc/udev/rules.d") ; do
+                       f+="  etc/udev/rules.d/$x\n"
+               done
+               if [[ -n $f ]] ; then
+                       eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:"
+                       eqawarn
+                       eqawarn "$f"
+               fi
+       fi
+
        # Now we look for all world writable files.
-       local i
-       for i in $(find "${D}/" -type f -perm -2); do
-               vecho "QA Security Notice:"
-               vecho "- ${i:${#D}:${#i}} will be a world writable file."
-               vecho "- This may or may not be a security problem, most of the time it is one."
-               vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly."
+       local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${ED}:- :")
+       if [[ -n ${unsafe_files} ]] ; then
+               __vecho "QA Security Notice: world writable file(s):"
+               __vecho "${unsafe_files}"
+               __vecho "- This may or may not be a security problem, most of the time it is one."
+               __vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly."
                sleep 1
-       done
+       fi
 
-       if type -P scanelf > /dev/null && ! hasq binchecks ${RESTRICT}; then
-               local qa_var insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET}
+       if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then
+               local insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET}
                local x
 
                # display warnings when using stricter because we die afterwards
@@ -193,16 +286,16 @@ install_qa_check() {
                #   3) Null paths are banned because the loader will search $PWD when
                #      it finds null paths.
                local forbidden_dirs="${PORTAGE_BUILDDIR}"
-               if [[ -n "$ROOT" ]] && [[ "$ROOT" != "/" ]]; then
-                       forbidden_dirs="${forbidden_dirs} ${ROOT}"
+               if [[ -n "${ROOT}" && "${ROOT}" != "/" ]]; then
+                       forbidden_dirs+=" ${ROOT}"
                fi
-               local dir="" rpath_files=$(scanelf -F '%F:%r' -qBR "${D}")
+               local dir l rpath_files=$(scanelf -F '%F:%r' -qBR "${ED}")
                f=""
                for dir in ${forbidden_dirs}; do
                        for l in $(echo "${rpath_files}" | grep -E ":${dir}|::|: "); do
                                f+="  ${l%%:*}\n"
                                if ! has stricter ${FEATURES}; then
-                                       vecho "Auto fixing rpaths for ${l%%:*}"
+                                       __vecho "Auto fixing rpaths for ${l%%:*}"
                                        TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null
                                fi
                        done
@@ -210,18 +303,18 @@ install_qa_check() {
 
                # Reject set*id binaries with $ORIGIN in RPATH #260331
                x=$(
-                       find "${D}" -type f \( -perm -u+s -o -perm -g+s \) -print0 | \
+                       find "${ED}" -type f \( -perm -u+s -o -perm -g+s \) -print0 | \
                        xargs -0 scanelf -qyRF '%r %p' | grep '$ORIGIN'
                )
 
                # Print QA notice.
                if [[ -n ${f}${x} ]] ; then
-                       vecho -ne '\n'
+                       __vecho -ne '\n'
                        eqawarn "QA Notice: The following files contain insecure RUNPATHs"
                        eqawarn " Please file a bug about this at http://bugs.gentoo.org/"
                        eqawarn " with the maintaining herd of the package."
                        eqawarn "${f}${f:+${x:+\n}}${x}"
-                       vecho -ne '\n'
+                       __vecho -ne '\n'
                        if [[ -n ${x} ]] || has stricter ${FEATURES} ; then
                                insecure_rpath=1
                        fi
@@ -236,10 +329,10 @@ install_qa_check() {
                [[ -n ${!qa_var} ]] && QA_TEXTRELS=${!qa_var}
                [[ -n ${QA_STRICT_TEXTRELS} ]] && QA_TEXTRELS=""
                export QA_TEXTRELS="${QA_TEXTRELS} lib*/modules/*.ko"
-               f=$(scanelf -qyRF '%t %p' "${D}" | grep -v 'usr/lib/debug/')
+               f=$(scanelf -qyRF '%t %p' "${ED}" | grep -v 'usr/lib/debug/')
                if [[ -n ${f} ]] ; then
                        scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log
-                       vecho -ne '\n'
+                       __vecho -ne '\n'
                        eqawarn "QA Notice: The following files contain runtime text relocations"
                        eqawarn " Text relocations force the dynamic linker to perform extra"
                        eqawarn " work at startup, waste system resources, and may pose a security"
@@ -248,7 +341,7 @@ install_qa_check() {
                        eqawarn " For more information, see http://hardened.gentoo.org/pic-fix-guide.xml"
                        eqawarn " Please include the following list of files in your report:"
                        eqawarn "${f}"
-                       vecho -ne '\n'
+                       __vecho -ne '\n'
                        die_msg="${die_msg} textrels,"
                        sleep 1
                fi
@@ -276,7 +369,7 @@ install_qa_check() {
                                        [[ -n ${QA_STRICT_WX_LOAD} ]] && QA_WX_LOAD=""
                                        export QA_EXECSTACK="${QA_EXECSTACK} lib*/modules/*.ko"
                                        export QA_WX_LOAD="${QA_WX_LOAD} lib*/modules/*.ko"
-                                       f=$(scanelf -qyRAF '%e %p' "${D}" | grep -v 'usr/lib/debug/')
+                                       f=$(scanelf -qyRAF '%e %p' "${ED}" | grep -v 'usr/lib/debug/')
                                        ;;
                        esac
                        ;;
@@ -284,7 +377,7 @@ install_qa_check() {
                if [[ -n ${f} ]] ; then
                        # One more pass to help devs track down the source
                        scanelf -qyRAF '%e %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-execstack.log
-                       vecho -ne '\n'
+                       __vecho -ne '\n'
                        eqawarn "QA Notice: The following files contain writable and executable sections"
                        eqawarn " Files with such sections will not work properly (or at all!) on some"
                        eqawarn " architectures/operating systems.  A bug should be filed at"
@@ -294,32 +387,21 @@ install_qa_check() {
                        eqawarn " Note: Bugs should be filed for the respective maintainers"
                        eqawarn " of the package in question and not hardened@g.o."
                        eqawarn "${f}"
-                       vecho -ne '\n'
+                       __vecho -ne '\n'
                        die_msg="${die_msg} execstacks"
                        sleep 1
                fi
 
                # Check for files built without respecting LDFLAGS
-               if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && [[ "${PN}" != *-bin ]] ; then
-                       qa_var="QA_DT_HASH_${ARCH/-/_}"
-                       eval "[[ -n \${!qa_var} ]] && QA_DT_HASH=(\"\${${qa_var}[@]}\")"
-                       f=$(scanelf -qyRF '%k %p' -k .hash "${D}" | sed -e "s:\.hash ::")
+               if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \
+                       ! has binchecks ${RESTRICT} ; then 
+                       f=$(scanelf -qyRF '%k %p' -k .hash "${ED}" | sed -e "s:\.hash ::")
                        if [[ -n ${f} ]] ; then
                                echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log
-                               if [ "${QA_STRICT_DT_HASH-unset}" == unset ] ; then
-                                       if [[ ${#QA_DT_HASH[@]} -gt 1 ]] ; then
-                                               for x in "${QA_DT_HASH[@]}" ; do
-                                                       sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log
-                                               done
-                                       else
-                                               local shopts=$-
-                                               set -o noglob
-                                               for x in ${QA_DT_HASH} ; do
-                                                       sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log
-                                               done
-                                               set +o noglob
-                                               set -${shopts}
-                                       fi
+                               if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then
+                                       for x in "${QA_FLAGS_IGNORED[@]}" ; do
+                                               sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log
+                                       done
                                fi
                                # Filter anything under /usr/lib/debug/ in order to avoid
                                # duplicate warnings for splitdebug files.
@@ -327,11 +409,11 @@ install_qa_check() {
                                        -i "${T}"/scanelf-ignored-LDFLAGS.log
                                f=$(<"${T}"/scanelf-ignored-LDFLAGS.log)
                                if [[ -n ${f} ]] ; then
-                                       vecho -ne '\n'
+                                       __vecho -ne '\n'
                                        eqawarn "${BAD}QA Notice: Files built without respecting LDFLAGS have been detected${NORMAL}"
                                        eqawarn " Please include the following list of files in your report:"
                                        eqawarn "${f}"
-                                       vecho -ne '\n'
+                                       __vecho -ne '\n'
                                        sleep 1
                                else
                                        rm -f "${T}"/scanelf-ignored-LDFLAGS.log
@@ -339,38 +421,6 @@ install_qa_check() {
                        fi
                fi
 
-               # Save NEEDED information after removing self-contained providers
-               scanelf -qyRF '%a;%p;%S;%r;%n' "${D}" | { while IFS= read -r l; do
-                       arch=${l%%;*}; l=${l#*;}
-                       obj="/${l%%;*}"; l=${l#*;}
-                       soname=${l%%;*}; l=${l#*;}
-                       rpath=${l%%;*}; l=${l#*;}; [ "${rpath}" = "  -  " ] && rpath=""
-                       needed=${l%%;*}; l=${l#*;}
-                       if [ -z "${rpath}" -o -n "${rpath//*ORIGIN*}" ]; then
-                               # object doesn't contain $ORIGIN in its runpath attribute
-                               echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED
-                               echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
-                       else
-                               dir=${obj%/*}
-                               # replace $ORIGIN with the dirname of the current object for the lookup
-                               opath=$(echo :${rpath}: | sed -e "s#.*:\(.*\)\$ORIGIN\(.*\):.*#\1${dir}\2#")
-                               sneeded=$(echo ${needed} | tr , ' ')
-                               rneeded=""
-                               for lib in ${sneeded}; do
-                                       found=0
-                                       for path in ${opath//:/ }; do
-                                               [ -e "${D}/${path}/${lib}" ] && found=1 && break
-                                       done
-                                       [ "${found}" -eq 0 ] && rneeded="${rneeded},${lib}"
-                               done
-                               rneeded=${rneeded:1}
-                               if [ -n "${rneeded}" ]; then
-                                       echo "${obj} ${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED
-                                       echo "${arch:3};${obj};${soname};${rpath};${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
-                               fi
-                       fi
-               done }
-
                if [[ ${insecure_rpath} -eq 1 ]] ; then
                        die "Aborting due to serious QA concerns with RUNPATH/RPATH"
                elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then
@@ -380,7 +430,7 @@ install_qa_check() {
                # Check for shared libraries lacking SONAMEs
                qa_var="QA_SONAME_${ARCH/-/_}"
                eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")"
-               f=$(scanelf -ByF '%S %p' "${D}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${D}:/:")
+               f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:")
                if [[ -n ${f} ]] ; then
                        echo "${f}" > "${T}"/scanelf-missing-SONAME.log
                        if [[ "${QA_STRICT_SONAME-unset}" == unset ]] ; then
@@ -401,10 +451,10 @@ install_qa_check() {
                        sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log
                        f=$(<"${T}"/scanelf-missing-SONAME.log)
                        if [[ -n ${f} ]] ; then
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                                eqawarn "QA Notice: The following shared libraries lack a SONAME"
                                eqawarn "${f}"
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                                sleep 1
                        else
                                rm -f "${T}"/scanelf-missing-SONAME.log
@@ -414,7 +464,7 @@ install_qa_check() {
                # Check for shared libraries lacking NEEDED entries
                qa_var="QA_DT_NEEDED_${ARCH/-/_}"
                eval "[[ -n \${!qa_var} ]] && QA_DT_NEEDED=(\"\${${qa_var}[@]}\")"
-               f=$(scanelf -ByF '%n %p' "${D}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${D}:/:")
+               f=$(scanelf -ByF '%n %p' "${ED}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:")
                if [[ -n ${f} ]] ; then
                        echo "${f}" > "${T}"/scanelf-missing-NEEDED.log
                        if [[ "${QA_STRICT_DT_NEEDED-unset}" == unset ]] ; then
@@ -435,10 +485,10 @@ install_qa_check() {
                        sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log
                        f=$(<"${T}"/scanelf-missing-NEEDED.log)
                        if [[ -n ${f} ]] ; then
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                                eqawarn "QA Notice: The following shared libraries lack NEEDED entries"
                                eqawarn "${f}"
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                                sleep 1
                        else
                                rm -f "${T}"/scanelf-missing-NEEDED.log
@@ -448,7 +498,35 @@ install_qa_check() {
                PORTAGE_QUIET=${tmp_quiet}
        fi
 
-       local unsafe_files=$(find "${D}" -type f '(' -perm -2002 -o -perm -4002 ')')
+       # Create NEEDED.ELF.2 regardless of RESTRICT=binchecks, since this info is
+       # too useful not to have (it's required for things like preserve-libs), and
+       # it's tempting for ebuild authors to set RESTRICT=binchecks for packages
+       # containing pre-built binaries.
+       if type -P scanelf > /dev/null ; then
+               # Save NEEDED information after removing self-contained providers
+               rm -f "$PORTAGE_BUILDDIR"/build-info/NEEDED{,.ELF.2}
+               scanelf -qyRF '%a;%p;%S;%r;%n' "${D}" | { while IFS= read -r l; do
+                       arch=${l%%;*}; l=${l#*;}
+                       obj="/${l%%;*}"; l=${l#*;}
+                       soname=${l%%;*}; l=${l#*;}
+                       rpath=${l%%;*}; l=${l#*;}; [ "${rpath}" = "  -  " ] && rpath=""
+                       needed=${l%%;*}; l=${l#*;}
+                       echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED
+                       echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
+               done }
+
+               [ -n "${QA_SONAME_NO_SYMLINK}" ] && \
+                       echo "${QA_SONAME_NO_SYMLINK}" > \
+                       "${PORTAGE_BUILDDIR}"/build-info/QA_SONAME_NO_SYMLINK
+
+               if has binchecks ${RESTRICT} && \
+                       [ -s "${PORTAGE_BUILDDIR}/build-info/NEEDED.ELF.2" ] ; then
+                       eqawarn "QA Notice: RESTRICT=binchecks prevented checks on these ELF files:"
+                       eqawarn "$(while read -r x; do x=${x#*;} ; x=${x%%;*} ; echo "${x#${EPREFIX}}" ; done < "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2)"
+               fi
+       fi
+
+       local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')' | sed -e "s:^${ED}:/:")
        if [[ -n ${unsafe_files} ]] ; then
                eqawarn "QA Notice: Unsafe files detected (set*id and world writable)"
                eqawarn "${unsafe_files}"
@@ -468,8 +546,8 @@ install_qa_check() {
        # Sanity check syntax errors in init.d scripts
        local d
        for d in /etc/conf.d /etc/init.d ; do
-               [[ -d ${D}/${d} ]] || continue
-               for i in "${D}"/${d}/* ; do
+               [[ -d ${ED}/${d} ]] || continue
+               for i in "${ED}"/${d}/* ; do
                        [[ -L ${i} ]] && continue
                        # if empty conf.d/init.d dir exists (baselayout), then i will be "/etc/conf.d/*" and not exist
                        [[ ! -e ${i} ]] && continue
@@ -477,20 +555,26 @@ install_qa_check() {
                done
        done
 
+       # Look for leaking LDFLAGS into pkg-config files
+       f=$(egrep -sH '^Libs.*-Wl,(-O[012]|--hash-style)' "${ED}"/usr/*/pkgconfig/*.pc)
+       if [[ -n ${f} ]] ; then
+               eqawarn "QA Notice: pkg-config files with wrong LDFLAGS detected:"
+               eqawarn "${f//${D}}"
+       fi
+
        # this should help to ensure that all (most?) shared libraries are executable
        # and that all libtool scripts / static libraries are not executable
        local j
-       for i in "${D}"opt/*/lib{,32,64} \
-                "${D}"lib{,32,64}       \
-                "${D}"usr/lib{,32,64}   \
-                "${D}"usr/X11R6/lib{,32,64} ; do
+       for i in "${ED}"opt/*/lib* \
+                "${ED}"lib* \
+                "${ED}"usr/lib* ; do
                [[ ! -d ${i} ]] && continue
 
                for j in "${i}"/*.so.* "${i}"/*.so ; do
                        [[ ! -e ${j} ]] && continue
                        [[ -L ${j} ]] && continue
                        [[ -x ${j} ]] && continue
-                       vecho "making executable: ${j#${D}}"
+                       __vecho "making executable: ${j#${ED}}"
                        chmod +x "${j}"
                done
 
@@ -498,7 +582,7 @@ install_qa_check() {
                        [[ ! -e ${j} ]] && continue
                        [[ -L ${j} ]] && continue
                        [[ ! -x ${j} ]] && continue
-                       vecho "removing executable bit: ${j#${D}}"
+                       __vecho "removing executable bit: ${j#${ED}}"
                        chmod -x "${j}"
                done
 
@@ -507,7 +591,7 @@ install_qa_check() {
                        [[ ! -L ${j} ]] && continue
                        linkdest=$(readlink "${j}")
                        if [[ ${linkdest} == /* ]] ; then
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                                eqawarn "QA Notice: Found an absolute symlink in a library directory:"
                                eqawarn "           ${j#${D}} -> ${linkdest}"
                                eqawarn "           It should be a relative symlink if in the same directory"
@@ -522,12 +606,12 @@ install_qa_check() {
        # http://bugs.gentoo.org/4411
        abort="no"
        local a s
-       for a in "${D}"usr/lib*/*.a ; do
+       for a in "${ED}"usr/lib*/*.a ; do
                s=${a%.a}.so
                if [[ ! -e ${s} ]] ; then
                        s=${s%usr/*}${s##*/usr/}
                        if [[ -e ${s} ]] ; then
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                                eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}"
                                abort="yes"
                        fi
@@ -536,21 +620,21 @@ install_qa_check() {
        [[ ${abort} == "yes" ]] && die "add those ldscripts"
 
        # Make sure people don't store libtool files or static libs in /lib
-       f=$(ls "${D}"lib*/*.{a,la} 2>/dev/null)
+       f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null)
        if [[ -n ${f} ]] ; then
-               vecho -ne '\n'
+               __vecho -ne '\n'
                eqawarn "QA Notice: Excessive files found in the / partition"
                eqawarn "${f}"
-               vecho -ne '\n'
+               __vecho -ne '\n'
                die "static archives (*.a) and libtool library files (*.la) do not belong in /"
        fi
 
        # Verify that the libtool files don't contain bogus $D entries.
        local abort=no gentoo_bug=no always_overflow=no
-       for a in "${D}"usr/lib*/*.la ; do
+       for a in "${ED}"usr/lib*/*.la ; do
                s=${a##*/}
-               if grep -qs "${D}" "${a}" ; then
-                       vecho -ne '\n'
+               if grep -qs "${ED}" "${a}" ; then
+                       __vecho -ne '\n'
                        eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths"
                        abort="yes"
                fi
@@ -620,8 +704,8 @@ install_qa_check() {
                                #esac
                                if [[ $always_overflow = yes ]] ; then
                                        eerror
-                                       eerror "QA Notice: Package has poor programming practices which may compile"
-                                       eerror "           fine but exhibit random runtime failures."
+                                       eerror "QA Notice: Package triggers severe warnings which indicate that it"
+                                       eerror "           may exhibit random runtime failures."
                                        eerror
                                        eerror "${f}"
                                        eerror
@@ -629,11 +713,11 @@ install_qa_check() {
                                        eerror " with the maintaining herd of the package."
                                        eerror
                                else
-                                       vecho -ne '\n'
-                                       eqawarn "QA Notice: Package has poor programming practices which may compile"
-                                       eqawarn "           fine but exhibit random runtime failures."
+                                       __vecho -ne '\n'
+                                       eqawarn "QA Notice: Package triggers severe warnings which indicate that it"
+                                       eqawarn "           may exhibit random runtime failures."
                                        eqawarn "${f}"
-                                       vecho -ne '\n'
+                                       __vecho -ne '\n'
                                fi
                        fi
                done
@@ -657,8 +741,8 @@ install_qa_check() {
 
                        if [[ $gentoo_bug = yes ]] ; then
                                eerror
-                               eerror "QA Notice: Package has poor programming practices which may compile"
-                               eerror "           but will almost certainly crash on 64bit architectures."
+                               eerror "QA Notice: Package triggers severe warnings which indicate that it"
+                               eerror "           will almost certainly crash on 64bit architectures."
                                eerror
                                eerror "${f}"
                                eerror
@@ -666,56 +750,183 @@ install_qa_check() {
                                eerror " with the maintaining herd of the package."
                                eerror
                        else
-                               vecho -ne '\n'
-                               eqawarn "QA Notice: Package has poor programming practices which may compile"
-                               eqawarn "           but will almost certainly crash on 64bit architectures."
+                               __vecho -ne '\n'
+                               eqawarn "QA Notice: Package triggers severe warnings which indicate that it"
+                               eqawarn "           will almost certainly crash on 64bit architectures."
                                eqawarn "${f}"
-                               vecho -ne '\n'
+                               __vecho -ne '\n'
                        fi
 
                fi
                if [[ ${abort} == "yes" ]] ; then
                        if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then
-                               die "install aborted due to" \
-                                       "poor programming practices shown above"
+                               die "install aborted due to severe warnings shown above"
                        else
                                echo "Please do not file a Gentoo bug and instead" \
                                "report the above QA issues directly to the upstream" \
                                "developers of this software." | fmt -w 70 | \
                                while read -r line ; do eqawarn "${line}" ; done
                                eqawarn "Homepage: ${HOMEPAGE}"
-                               hasq stricter ${FEATURES} && die "install aborted due to" \
-                                       "poor programming practices shown above"
+                               has stricter ${FEATURES} && \
+                                       die "install aborted due to severe warnings shown above"
                        fi
                fi
        fi
 
        # Portage regenerates this on the installed system.
-       rm -f "${D}"/usr/share/info/dir{,.gz,.bz2}
+       rm -f "${ED}"/usr/share/info/dir{,.gz,.bz2} || die "rm failed!"
 
-       if hasq multilib-strict ${FEATURES} && \
+       if has multilib-strict ${FEATURES} && \
           [[ -x /usr/bin/file && -x /usr/bin/find ]] && \
           [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]]
        then
                local abort=no dir file firstrun=yes
                MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g')
                for dir in ${MULTILIB_STRICT_DIRS} ; do
-                       [[ -d ${D}/${dir} ]] || continue
-                       for file in $(find ${D}/${dir} -type f | grep -v "^${D}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do
+                       [[ -d ${ED}/${dir} ]] || continue
+                       for file in $(find ${ED}/${dir} -type f | grep -v "^${ED}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do
                                if file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" ; then
                                        if [[ ${firstrun} == yes ]] ; then
                                                echo "Files matching a file type that is not allowed:"
                                                firstrun=no
                                        fi
                                        abort=yes
-                                       echo "   ${file#${D}//}"
+                                       echo "   ${file#${ED}//}"
                                fi
                        done
                done
                [[ ${abort} == yes ]] && die "multilib-strict check failed!"
        fi
+
+       # ensure packages don't install systemd units automagically
+       if ! has systemd ${INHERITED} && \
+               [[ -d "${ED}"/lib/systemd/system ]]
+       then
+               eqawarn "QA Notice: package installs systemd unit files (/lib/systemd/system)"
+               eqawarn "           but does not inherit systemd.eclass."
+               has stricter ${FEATURES} \
+                       && die "install aborted due to missing inherit of systemd.eclass"
+       fi
 }
 
+install_qa_check_prefix() {
+       if [[ -d ${ED}/${D} ]] ; then
+               find "${ED}/${D}" | \
+               while read i ; do
+                       eqawarn "QA Notice: /${i##${ED}/${D}} installed in \${ED}/\${D}"
+               done
+               die "Aborting due to QA concerns: files installed in ${ED}/${D}"
+       fi
+
+       if [[ -d ${ED}/${EPREFIX} ]] ; then
+               find "${ED}/${EPREFIX}/" | \
+               while read i ; do
+                       eqawarn "QA Notice: ${i#${D}} double prefix"
+               done
+               die "Aborting due to QA concerns: double prefix files installed"
+       fi
+
+       if [[ -d ${D} ]] ; then
+               INSTALLTOD=$(find ${D%/} | egrep -v "^${ED}" | sed -e "s|^${D%/}||" | awk '{if (length($0) <= length("'"${EPREFIX}"'")) { if (substr("'"${EPREFIX}"'", 1, length($0)) != $0) {print $0;} } else if (substr($0, 1, length("'"${EPREFIX}"'")) != "'"${EPREFIX}"'") {print $0;} }')
+               if [[ -n ${INSTALLTOD} ]] ; then
+                       eqawarn "QA Notice: the following files are outside of the prefix:"
+                       eqawarn "${INSTALLTOD}"
+                       die "Aborting due to QA concerns: there are files installed outside the prefix"
+               fi
+       fi
+
+       # all further checks rely on ${ED} existing
+       [[ -d ${ED} ]] || return
+
+       # this does not really belong here, but it's closely tied to
+       # the code below; many runscripts generate positives here, and we
+       # know they don't work (bug #196294) so as long as that one
+       # remains an issue, simply remove them as they won't work
+       # anyway, avoid etc/init.d/functions.sh from being thrown away
+       if [[ ( -d "${ED}"/etc/conf.d || -d "${ED}"/etc/init.d ) && ! -f "${ED}"/etc/init.d/functions.sh ]] ; then
+               ewarn "removed /etc/init.d and /etc/conf.d directories until bug #196294 has been resolved"
+               rm -Rf "${ED}"/etc/{conf,init}.d
+       fi
+
+       # check shebangs, bug #282539
+       rm -f "${T}"/non-prefix-shebangs-errs
+       local WHITELIST=" /usr/bin/env "
+       # this is hell expensive, but how else?
+       find "${ED}" -executable \! -type d -print0 \
+                       | xargs -0 grep -H -n -m1 "^#!" \
+                       | while read f ;
+       do
+               local fn=${f%%:*}
+               local pos=${f#*:} ; pos=${pos%:*}
+               local line=${f##*:}
+               # shebang always appears on the first line ;)
+               [[ ${pos} != 1 ]] && continue
+               local oldIFS=${IFS}
+               IFS=$'\r'$'\n'$'\t'" "
+               line=( ${line#"#!"} )
+               IFS=${oldIFS}
+               [[ ${WHITELIST} == *" ${line[0]} "* ]] && continue
+               local fp=${fn#${D}} ; fp=/${fp%/*}
+               # line[0] can be an absolutised path, bug #342929
+               local eprefix=$(canonicalize ${EPREFIX})
+               local rf=${fn}
+               # in case we deal with a symlink, make sure we don't replace it
+               # with a real file (sed -i does that)
+               if [[ -L ${fn} ]] ; then
+                       rf=$(readlink ${fn})
+                       [[ ${rf} != /* ]] && rf=${fn%/*}/${rf}
+                       # ignore symlinks pointing to outside prefix
+                       # as seen in sys-devel/native-cctools
+                       [[ $(canonicalize "/${rf#${D}}") != ${eprefix}/* ]] && continue
+               fi
+               # does the shebang start with ${EPREFIX}, and does it exist?
+               if [[ ${line[0]} == ${EPREFIX}/* || ${line[0]} == ${eprefix}/* ]] ; then
+                       if [[ ! -e ${ROOT%/}${line[0]} && ! -e ${D%/}${line[0]} ]] ; then
+                               # hmm, refers explicitly to $EPREFIX, but doesn't exist,
+                               # if it's in PATH that's wrong in any case
+                               if [[ ":${PATH}:" == *":${fp}:"* ]] ; then
+                                       echo "${fn#${D}}:${line[0]} (explicit EPREFIX but target not found)" \
+                                               >> "${T}"/non-prefix-shebangs-errs
+                               else
+                                       eqawarn "${fn#${D}} has explicit EPREFIX in shebang but target not found (${line[0]})"
+                               fi
+                       fi
+                       continue
+               fi
+               # unprefixed shebang, is the script directly in $PATH?
+               if [[ ":${PATH}:" == *":${fp}:"* ]] ; then
+                       if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then
+                               # is it unprefixed, but we can just fix it because a
+                               # prefixed variant exists
+                               eqawarn "prefixing shebang of ${fn#${D}}"
+                               # statement is made idempotent on purpose, because
+                               # symlinks may point to the same target, and hence the
+                               # same real file may be sedded multiple times since we
+                               # read the shebangs in one go upfront for performance
+                               # reasons
+                               sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}"
+                               continue
+                       else
+                               # this is definitely wrong: script in $PATH and invalid shebang
+                               echo "${fn#${D}}:${line[0]} (script ${fn##*/} installed in PATH but interpreter ${line[0]} not found)" \
+                                       >> "${T}"/non-prefix-shebangs-errs
+                       fi
+               else
+                       # unprefixed/invalid shebang, but outside $PATH, this may be
+                       # intended (e.g. config.guess) so remain silent by default
+                       has stricter ${FEATURES} && \
+                               eqawarn "invalid shebang in ${fn#${D}}: ${line[0]}"
+               fi
+       done
+       if [[ -e "${T}"/non-prefix-shebangs-errs ]] ; then
+               eqawarn "QA Notice: the following files use invalid (possible non-prefixed) shebangs:"
+               while read line ; do
+                       eqawarn "  ${line}"
+               done < "${T}"/non-prefix-shebangs-errs
+               rm -f "${T}"/non-prefix-shebangs-errs
+               die "Aborting due to QA concerns: invalid shebangs found"
+       fi
+}
 
 install_mask() {
        local root="$1"
@@ -728,7 +939,7 @@ install_mask() {
        local no_inst
        for no_inst in ${install_mask}; do
                set +o noglob
-               quiet_mode || einfo "Removing ${no_inst}"
+               __quiet_mode || einfo "Removing ${no_inst}"
                # normal stuff
                rm -Rf "${root}"/${no_inst} >&/dev/null
 
@@ -747,6 +958,9 @@ preinst_mask() {
                 return 1
        fi
 
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local ED=${D} ;; esac
+
        # Make sure $PWD is not ${D} so that we don't leave gmon.out files
        # in there in case any tools were built with -pg in CFLAGS.
        cd "${T}"
@@ -754,16 +968,16 @@ preinst_mask() {
        # remove man pages, info pages, docs if requested
        local f
        for f in man info doc; do
-               if hasq no${f} $FEATURES; then
+               if has no${f} $FEATURES; then
                        INSTALL_MASK="${INSTALL_MASK} /usr/share/${f}"
                fi
        done
 
-       install_mask "${D}" "${INSTALL_MASK}"
+       install_mask "${ED}" "${INSTALL_MASK}"
 
        # remove share dir if unnessesary
-       if hasq nodoc $FEATURES -o hasq noman $FEATURES -o hasq noinfo $FEATURES; then
-               rmdir "${D}usr/share" &> /dev/null
+       if has nodoc $FEATURES || has noman $FEATURES || has noinfo $FEATURES; then
+               rmdir "${ED}usr/share" &> /dev/null
        fi
 }
 
@@ -772,29 +986,33 @@ preinst_sfperms() {
                 eerror "${FUNCNAME}: D is unset"
                 return 1
        fi
+
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local ED=${D} ;; esac
+
        # Smart FileSystem Permissions
-       if hasq sfperms $FEATURES; then
+       if has sfperms $FEATURES; then
                local i
-               find "${D}" -type f -perm -4000 -print0 | \
+               find "${ED}" -type f -perm -4000 -print0 | \
                while read -r -d $'\0' i ; do
                        if [ -n "$(find "$i" -perm -2000)" ] ; then
-                               ebegin ">>> SetUID and SetGID: [chmod o-r] /${i#${D}}"
+                               ebegin ">>> SetUID and SetGID: [chmod o-r] /${i#${ED}}"
                                chmod o-r "$i"
                                eend $?
                        else
-                               ebegin ">>> SetUID: [chmod go-r] /${i#${D}}"
+                               ebegin ">>> SetUID: [chmod go-r] /${i#${ED}}"
                                chmod go-r "$i"
                                eend $?
                        fi
                done
-               find "${D}" -type f -perm -2000 -print0 | \
+               find "${ED}" -type f -perm -2000 -print0 | \
                while read -r -d $'\0' i ; do
                        if [ -n "$(find "$i" -perm -4000)" ] ; then
                                # This case is already handled
                                # by the SetUID check above.
                                true
                        else
-                               ebegin ">>> SetGID: [chmod o-r] /${i#${D}}"
+                               ebegin ">>> SetGID: [chmod o-r] /${i#${ED}}"
                                chmod o-r "$i"
                                eend $?
                        fi
@@ -807,35 +1025,39 @@ preinst_suid_scan() {
                 eerror "${FUNCNAME}: D is unset"
                 return 1
        fi
+
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local ED=${D} ;; esac
+
        # total suid control.
-       if hasq suidctl $FEATURES; then
+       if has suidctl $FEATURES; then
                local i sfconf x
                sfconf=${PORTAGE_CONFIGROOT}etc/portage/suidctl.conf
                # sandbox prevents us from writing directly
                # to files outside of the sandbox, but this
                # can easly be bypassed using the addwrite() function
                addwrite "${sfconf}"
-               vecho ">>> Performing suid scan in ${D}"
-               for i in $(find "${D}" -type f \( -perm -4000 -o -perm -2000 \) ); do
+               __vecho ">>> Performing suid scan in ${ED}"
+               for i in $(find "${ED}" -type f \( -perm -4000 -o -perm -2000 \) ); do
                        if [ -s "${sfconf}" ]; then
-                               install_path=/${i#${D}}
+                               install_path=/${i#${ED}}
                                if grep -q "^${install_path}\$" "${sfconf}" ; then
-                                       vecho "- ${install_path} is an approved suid file"
+                                       __vecho "- ${install_path} is an approved suid file"
                                else
-                                       vecho ">>> Removing sbit on non registered ${install_path}"
+                                       __vecho ">>> Removing sbit on non registered ${install_path}"
                                        for x in 5 4 3 2 1 0; do sleep 0.25 ; done
                                        ls_ret=$(ls -ldh "${i}")
                                        chmod ugo-s "${i}"
                                        grep "^#${install_path}$" "${sfconf}" > /dev/null || {
-                                               vecho ">>> Appending commented out entry to ${sfconf} for ${PF}"
-                                               echo "## ${ls_ret%${D}*}${install_path}" >> "${sfconf}"
+                                               __vecho ">>> Appending commented out entry to ${sfconf} for ${PF}"
+                                               echo "## ${ls_ret%${ED}*}${install_path}" >> "${sfconf}"
                                                echo "#${install_path}" >> "${sfconf}"
                                                # no delwrite() eh?
                                                # delwrite ${sconf}
                                        }
                                fi
                        else
-                               vecho "suidctl feature set but you are lacking a ${sfconf}"
+                               __vecho "suidctl feature set but you are lacking a ${sfconf}"
                        fi
                done
        fi
@@ -846,33 +1068,55 @@ preinst_selinux_labels() {
                 eerror "${FUNCNAME}: D is unset"
                 return 1
        fi
-       if hasq selinux ${FEATURES}; then
-               # SELinux file labeling (needs to always be last in dyn_preinst)
+       if has selinux ${FEATURES}; then
+               # SELinux file labeling (needs to execute after preinst)
                # only attempt to label if setfiles is executable
                # and 'context' is available on selinuxfs.
-               if [ -f /selinux/context -a -x /usr/sbin/setfiles -a -x /usr/sbin/selinuxconfig ]; then
-                       vecho ">>> Setting SELinux security labels"
+               if [ -f /selinux/context -o -f /sys/fs/selinux/context ] && \
+                       [ -x /usr/sbin/setfiles -a -x /usr/sbin/selinuxconfig ]; then
+                       __vecho ">>> Setting SELinux security labels"
                        (
                                eval "$(/usr/sbin/selinuxconfig)" || \
                                        die "Failed to determine SELinux policy paths.";
        
-                               addwrite /selinux/context;
+                               addwrite /selinux/context
+                               addwrite /sys/fs/selinux/context
        
                                /usr/sbin/setfiles "${file_contexts_path}" -r "${D}" "${D}"
                        ) || die "Failed to set SELinux security labels."
                else
                        # nonfatal, since merging can happen outside a SE kernel
                        # like during a recovery situation
-                       vecho "!!! Unable to set SELinux security labels"
+                       __vecho "!!! Unable to set SELinux security labels"
                fi
        fi
 }
 
-dyn_package() {
+__dyn_package() {
+       local PROOT
+
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local EPREFIX= ED=${D} ;; esac
+
        # Make sure $PWD is not ${D} so that we don't leave gmon.out files
        # in there in case any tools were built with -pg in CFLAGS.
+
        cd "${T}"
-       install_mask "${PORTAGE_BUILDDIR}/image" "${PKG_INSTALL_MASK}"
+
+       if [[ -n ${PKG_INSTALL_MASK} ]] ; then
+               PROOT=${T}/packaging/
+               # make a temporary copy of ${D} so that any modifications we do that
+               # are binpkg specific, do not influence the actual installed image.
+               rm -rf "${PROOT}" || die "failed removing stale package tree"
+               cp -pPR $(cp --help | grep -qs -e-l && echo -l) \
+                       "${D}" "${PROOT}" \
+                       || die "failed creating packaging tree"
+
+               install_mask "${PROOT%/}${EPREFIX}/" "${PKG_INSTALL_MASK}"
+       else
+               PROOT=${D}
+       fi
+
        local tar_options=""
        [[ $PORTAGE_VERBOSE = 1 ]] && tar_options+=" -v"
        # Sandbox is disabled in case the user wants to use a symlink
@@ -881,7 +1125,7 @@ dyn_package() {
        [ -z "${PORTAGE_BINPKG_TMPFILE}" ] && \
                die "PORTAGE_BINPKG_TMPFILE is unset"
        mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed"
-       tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${D}" . | \
+       tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${PROOT}" . | \
                $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
        assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'"
        PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
@@ -901,13 +1145,16 @@ dyn_package() {
        fi
        [ -n "${md5_hash}" ] && \
                echo ${md5_hash} > "${PORTAGE_BUILDDIR}"/build-info/BINPKGMD5
-       vecho ">>> Done."
+       __vecho ">>> Done."
+
+       # cleanup our temp tree
+       [[ -n ${PKG_INSTALL_MASK} ]] && rm -rf "${PROOT}"
        cd "${PORTAGE_BUILDDIR}"
        >> "$PORTAGE_BUILDDIR/.packaged" || \
                die "Failed to create $PORTAGE_BUILDDIR/.packaged"
 }
 
-dyn_spec() {
+__dyn_spec() {
        local sources_dir=/usr/src/rpm/SOURCES
        mkdir -p "${sources_dir}"
        declare -a tar_args=("${EBUILD}")
@@ -945,13 +1192,17 @@ __END1__
 
 }
 
-dyn_rpm() {
+__dyn_rpm() {
+
+       [[ " ${FEATURES} " == *" force-prefix "* ]] || \
+               case "$EAPI" in 0|1|2) local EPREFIX= ;; esac
+
        cd "${T}" || die "cd failed"
        local machine_name=$(uname -m)
-       local dest_dir=/usr/src/rpm/RPMS/${machine_name}
-       addwrite /usr/src/rpm
+       local dest_dir=${EPREFIX}/usr/src/rpm/RPMS/${machine_name}
+       addwrite ${EPREFIX}/usr/src/rpm
        addwrite "${RPMDIR}"
-       dyn_spec
+       __dyn_spec
        rpmbuild -bb --clean --rmsource "${PF}.spec" || die "Failed to integrate rpm spec file"
        install -D "${dest_dir}/${PN}-${PV}-${PR}.${machine_name}.rpm" \
                "${RPMDIR}/${CATEGORY}/${PN}-${PV}-${PR}.rpm" || \
@@ -974,8 +1225,23 @@ success_hooks() {
        done
 }
 
+install_hooks() {
+       local hooks_dir="${PORTAGE_CONFIGROOT}etc/portage/hooks/install"
+       local fp
+       local ret=0
+       shopt -s nullglob
+       for fp in "${hooks_dir}"/*; do
+               if [ -x "$fp" ]; then
+                       "$fp"
+                       ret=$(( $ret | $? ))
+               fi
+       done
+       shopt -u nullglob
+       return $ret
+}
+
 if [ -n "${MISC_FUNCTIONS_ARGS}" ]; then
-       source_all_bashrcs
+       __source_all_bashrcs
        [ "$PORTAGE_DEBUG" == "1" ] && set -x
        for x in ${MISC_FUNCTIONS_ARGS}; do
                ${x}