This patch includes the essential parts of the dostrip implementation
from portage-mgorny. It also bans the non-standard prepstrip and
prepallstrip helpers in EAPI 7, with a die message suggesting to
use 'dostrip' instead. All of the prepstrip code has moved to
bin/estrip, without any changes except the addition of argument
parsing for estrip --ignore, --queue, and --deque modes which are
equivalent to the corresponding ecompressdir modes.

Bug: https://bugs.gentoo.org/203891
---
 bin/eapi.sh                     |   4 +
 bin/ebuild-helpers/prepall      |   2 +-
 bin/ebuild-helpers/prepallstrip |   4 +
 bin/ebuild-helpers/prepstrip    | 400 +----------------------------------
 bin/ebuild.sh                   |   2 +-
 bin/estrip                      | 458 ++++++++++++++++++++++++++++++++++++++++
 bin/misc-functions.sh           |   6 +
 bin/phase-helpers.sh            |  29 +++
 bin/save-ebuild-env.sh          |   4 +-
 9 files changed, 509 insertions(+), 400 deletions(-)
 create mode 100755 bin/estrip

diff --git a/bin/eapi.sh b/bin/eapi.sh
index 326eb387e..f9a4744e9 100644
--- a/bin/eapi.sh
+++ b/bin/eapi.sh
@@ -76,6 +76,10 @@ ___eapi_has_docompress() {
        [[ ! ${1-${EAPI-0}} =~ ^(0|1|2|3)$ ]]
 }
 
+___eapi_has_dostrip() {
+       [[ ${1-${EAPI-0}} =~ 
^(0|1|2|3|4|4-python|4-slot-abi|5|5-hdepend|5-progress|6)$ ]]
+}
+
 ___eapi_has_nonfatal() {
        [[ ! ${1-${EAPI-0}} =~ ^(0|1|2|3)$ ]]
 }
diff --git a/bin/ebuild-helpers/prepall b/bin/ebuild-helpers/prepall
index 44643bb58..bc77af4a1 100755
--- a/bin/ebuild-helpers/prepall
+++ b/bin/ebuild-helpers/prepall
@@ -19,7 +19,7 @@ fi
 prepallman
 prepallinfo
 
-prepallstrip
+___eapi_has_dostrip || prepallstrip
 
 if has chflags $FEATURES ; then
        # Restore all the file flags that were saved at the beginning of 
prepall.
diff --git a/bin/ebuild-helpers/prepallstrip b/bin/ebuild-helpers/prepallstrip
index 59fa7cc61..4bde1f4b2 100755
--- a/bin/ebuild-helpers/prepallstrip
+++ b/bin/ebuild-helpers/prepallstrip
@@ -4,6 +4,10 @@
 
 source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1
 
+if ___eapi_has_dostrip; then
+       die "${0##*/}: ${0##*/} has been banned for EAPI '$EAPI'; use 'dostrip' 
instead"
+fi
+
 if ! ___eapi_has_prefix_variables; then
        ED=${D}
 fi
diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip
index 2136e0d4d..9db06284d 100755
--- a/bin/ebuild-helpers/prepstrip
+++ b/bin/ebuild-helpers/prepstrip
@@ -2,402 +2,10 @@
 # Copyright 1999-2018 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-source "${PORTAGE_BIN_PATH}"/helper-functions.sh || exit 1
+source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1
 
-# avoid multiple calls to `has`.  this creates things like:
-#   FEATURES_foo=false
-# if "foo" is not in $FEATURES
-tf() { "$@" && echo true || echo false ; }
-exp_tf() {
-       local flag var=$1
-       shift
-       for flag in "$@" ; do
-               eval ${var}_${flag}=$(tf has ${flag} ${!var})
-       done
-}
-exp_tf FEATURES compressdebug installsources nostrip splitdebug xattr
-exp_tf RESTRICT binchecks installsources splitdebug strip
-
-if ! ___eapi_has_prefix_variables; then
-       EPREFIX= ED=${D}
-fi
-
-banner=false
-SKIP_STRIP=false
-if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
-       SKIP_STRIP=true
-       banner=true
-       ${FEATURES_installsources} || exit 0
-fi
-
-PRESERVE_XATTR=false
-if [[ ${KERNEL} == linux ]] && ${FEATURES_xattr} ; then
-       PRESERVE_XATTR=true
-       if type -P getfattr >/dev/null && type -P setfattr >/dev/null ; then
-               dump_xattrs() {
-                       getfattr -d -m - --absolute-names "$1"
-               }
-               restore_xattrs() {
-                       setfattr --restore=-
-               }
-       else
-               dump_xattrs() {
-                       PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
-                       "${PORTAGE_PYTHON:-/usr/bin/python}" \
-                       "${PORTAGE_BIN_PATH}/xattr-helper.py" --dump < <(echo 
-n "$1")
-               }
-               restore_xattrs() {
-                       PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
-                       "${PORTAGE_PYTHON:-/usr/bin/python}" \
-                       "${PORTAGE_BIN_PATH}/xattr-helper.py" --restore
-               }
-       fi
-fi
-
-# look up the tools we might be using
-for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
-       v=${t%:*} # STRIP
-       t=${t#*:} # strip
-       eval ${v}=\"${!v:-${CHOST}-${t}}\"
-       type -P -- ${!v} >/dev/null || eval ${v}=${t}
-done
-
-# Figure out what tool set we're using to strip stuff
-unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS
-case $(${STRIP} --version 2>/dev/null) in
-*elfutils*) # dev-libs/elfutils
-       # elfutils default behavior is always safe, so don't need to specify
-       # any flags at all
-       SAFE_STRIP_FLAGS=""
-       DEF_STRIP_FLAGS="--remove-comment"
-       SPLIT_STRIP_FLAGS="-f"
-       ;;
-*GNU*) # sys-devel/binutils
-       # We'll leave out -R .note for now until we can check out the relevance
-       # of the section when it has the ALLOC flag set on it ...
-       SAFE_STRIP_FLAGS="--strip-unneeded"
-       DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line -R 
.note.gnu.gold-version"
-       SPLIT_STRIP_FLAGS=
-       ;;
-esac
-: ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}}
-
-prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF}
-
-debugedit=$(type -P debugedit)
-if [[ -z ${debugedit} ]]; then
-       debugedit_paths=(
-               "${EPREFIX}/usr/libexec/rpm/debugedit"
-       )
-       for x in "${debugedit_paths[@]}"; do
-               if [[ -x ${x} ]]; then
-                       debugedit=${x}
-                       break
-               fi
-       done
-fi
-[[ ${debugedit} ]] && debugedit_found=true || debugedit_found=false
-debugedit_warned=false
-
-__multijob_init
-
-# Setup $T filesystem layout that we care about.
-tmpdir="${T}/prepstrip"
-rm -rf "${tmpdir}"
-mkdir -p "${tmpdir}"/{inodes,splitdebug,sources}
-
-# Usage: save_elf_sources <elf>
-save_elf_sources() {
-       ${FEATURES_installsources} || return 0
-       ${RESTRICT_installsources} && return 0
-       if ! ${debugedit_found} ; then
-               if ! ${debugedit_warned} ; then
-                       debugedit_warned=true
-                       ewarn "FEATURES=installsources is enabled but the 
debugedit binary could not be"
-                       ewarn "found. This feature will not work unless 
debugedit or rpm is installed!"
-               fi
-               return 0
-       fi
-
-       local x=$1
-
-       # since we're editing the ELF here, we should recompute the build-id
-       # (the -i flag below).  save that output so we don't need to recompute
-       # it later on in the save_elf_debug step.
-       buildid=$("${debugedit}" -i \
-               -b "${WORKDIR}" \
-               -d "${prepstrip_sources_dir}" \
-               -l "${tmpdir}/sources/${x##*/}.${BASHPID:-$(__bashpid)}" \
-               "${x}")
-}
-
-# Usage: save_elf_debug <elf> [splitdebug file]
-save_elf_debug() {
-       ${FEATURES_splitdebug} || return 0
-       ${RESTRICT_splitdebug} && return 0
-
-       # NOTE: Debug files must be installed in
-       # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs
-       # twice in this path) in order for gdb's debug-file-directory
-       # lookup to work correctly.
-       local x=$1
-       local inode_debug=$2
-       local splitdebug=$3
-       local d_noslash=${D%/}
-       local y=${ED%/}/usr/lib/debug/${x:${#d_noslash}}.debug
-
-       # dont save debug info twice
-       [[ ${x} == *".debug" ]] && return 0
-
-       mkdir -p "${y%/*}"
-
-       if [ -f "${inode_debug}" ] ; then
-               ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
-       else
-               if [[ -n ${splitdebug} ]] ; then
-                       mv "${splitdebug}" "${y}"
-               else
-                       local objcopy_flags="--only-keep-debug"
-                       ${FEATURES_compressdebug} && objcopy_flags+=" 
--compress-debug-sections"
-                       ${OBJCOPY} ${objcopy_flags} "${x}" "${y}"
-                       ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
-               fi
-               # Only do the following if the debug file was
-               # successfully created (see bug #446774).
-               if [ $? -eq 0 ] ; then
-                       local args="a-x,o-w"
-                       [[ -g ${x} || -u ${x} ]] && args+=",go-r"
-                       chmod ${args} "${y}"
-                       ln "${y}" "${inode_debug}" || die "ln failed 
unexpectedly"
-               fi
-       fi
-
-       # if we don't already have build-id from debugedit, look it up
-       if [[ -z ${buildid} ]] ; then
-               # convert the readelf output to something useful
-               buildid=$(${READELF} -n "${x}" 2>/dev/null | awk '/Build ID:/{ 
print $NF; exit }')
-       fi
-       if [[ -n ${buildid} ]] ; then
-               local 
buildid_dir="${ED%/}/usr/lib/debug/.build-id/${buildid:0:2}"
-               local buildid_file="${buildid_dir}/${buildid:2}"
-               mkdir -p "${buildid_dir}"
-               [ -L "${buildid_file}".debug ] || ln -s 
"../../${x:${#D}}.debug" "${buildid_file}.debug"
-               [ -L "${buildid_file}" ] || ln -s "/${x:${#D}}" 
"${buildid_file}"
-       fi
-}
-
-# Usage: process_elf <elf>
-process_elf() {
-       local x=$1 inode_link=$2 strip_flags=${*:3}
-       local already_stripped lockfile xt_data
-
-       __vecho "   ${x:${#ED}}"
-
-       # If two processes try to debugedit or strip the same hardlink at the
-       # same time, it may corrupt files or cause loss of splitdebug info.
-       # So, use a lockfile to prevent interference (easily observed with
-       # dev-vcs/git which creates ~111 hardlinks to one file in
-       # /usr/libexec/git-core).
-       lockfile=${inode_link}_lockfile
-       if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then
-               while [[ -f ${lockfile} ]] ; do
-                       sleep 1
-               done
-               unset lockfile
-       fi
-
-       [ -f "${inode_link}_stripped" ] && already_stripped=true || 
already_stripped=false
-
-       if ! ${already_stripped} ; then
-               if ${PRESERVE_XATTR} ; then
-                       xt_data=$(dump_xattrs "${x}")
-               fi
-               save_elf_sources "${x}"
-       fi
-
-       if ${strip_this} ; then
-
-               # see if we can split & strip at the same time
-               if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then
-                       local shortname="${x##*/}.debug"
-                       local 
splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID:-$(__bashpid)}"
-                       ${already_stripped} || \
-                       ${STRIP} ${strip_flags} \
-                               -f "${splitdebug}" \
-                               -F "${shortname}" \
-                               "${x}"
-                       save_elf_debug "${x}" "${inode_link}_debug" 
"${splitdebug}"
-               else
-                       save_elf_debug "${x}" "${inode_link}_debug"
-                       ${already_stripped} || \
-                       ${STRIP} ${strip_flags} "${x}"
-               fi
-       fi
-
-       if ${already_stripped} ; then
-               rm -f "${x}" || die "rm failed unexpectedly"
-               ln "${inode_link}_stripped" "${x}" || die "ln failed 
unexpectedly"
-       else
-               ln "${x}" "${inode_link}_stripped" || die "ln failed 
unexpectedly"
-               if [[ ${xt_data} ]] ; then
-                       restore_xattrs <<< "${xt_data}"
-               fi
-       fi
-
-       [[ -n ${lockfile} ]] && rm -f "${lockfile}"
-}
-
-# The existance of the section .symtab tells us that a binary is stripped.
-# We want to log already stripped binaries, as this may be a QA violation.
-# They prevent us from getting the splitdebug data.
-if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then
-       # We need to do the non-stripped scan serially first before we turn 
around
-       # and start stripping the files ourselves.  The log parsing can be done 
in
-       # parallel though.
-       log=${tmpdir}/scanelf-already-stripped.log
-       scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED%/}/##" > 
"${log}"
-       (
-       __multijob_child_init
-       qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
-       [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
-       if [[ -n ${QA_PRESTRIPPED} && -s ${log} && \
-               ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
-               shopts=$-
-               set -o noglob
-               for x in ${QA_PRESTRIPPED} ; do
-                       sed -e "s#^${x#/}\$##" -i "${log}"
-               done
-               set +o noglob
-               set -${shopts}
-       fi
-       sed -e "/^\$/d" -e "s#^#/#" -i "${log}"
-       if [[ -s ${log} ]] ; then
-               __vecho -e "\n"
-               eqawarn "QA Notice: Pre-stripped files found:"
-               eqawarn "$(<"${log}")"
-       else
-               rm -f "${log}"
-       fi
-       ) &
-       __multijob_post_fork
-fi
-
-# Since strip creates a new inode, we need to know the initial set of
-# inodes in advance, so that we can avoid interference due to trying
-# to strip the same (hardlinked) file multiple times in parallel.
-# See bug #421099.
-if  [[ ${USERLAND} == BSD ]] ; then
-       get_inode_number() { stat -f '%i' "$1"; }
-else
-       get_inode_number() { stat -c '%i' "$1"; }
-fi
-cd "${tmpdir}/inodes" || die "cd failed unexpectedly"
-while read -r x ; do
-       inode_link=$(get_inode_number "${x}") || die "stat failed unexpectedly"
-       echo "${x}" >> "${inode_link}" || die "echo failed unexpectedly"
-done < <(
-       # Use sort -u to eliminate duplicates for bug #445336.
-       (
-               scanelf -yqRBF '#k%F' -k '.symtab' "$@"
-               find "$@" -type f ! -type l -name '*.a'
-       ) | LC_ALL=C sort -u
-)
-
-# Now we look for unstripped binaries.
-for inode_link in $(shopt -s nullglob; echo *) ; do
-while read -r x
-do
-
-       if ! ${banner} ; then
-               __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
-               banner=true
-       fi
-
-       (
-       __multijob_child_init
-       f=$(file "${x}") || exit 0
-       [[ -z ${f} ]] && exit 0
-
-       if ! ${SKIP_STRIP} ; then
-               # The noglob funk is to support STRIP_MASK="/*/booga" and to 
keep
-               #  the for loop from expanding the globs.
-               # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
-               set -o noglob
-               strip_this=true
-               for m in $(eval echo ${STRIP_MASK}) ; do
-                       [[ /${x#${ED%/}} == ${m} ]] && strip_this=false && break
-               done
-               set +o noglob
-       else
-               strip_this=false
-       fi
-
-       # In Prefix we are usually an unprivileged user, so we can't strip
-       # unwritable objects.  Make them temporarily writable for the
-       # stripping.
-       was_not_writable=false
-       if [[ ! -w ${x} ]] ; then
-               was_not_writable=true
-               chmod u+w "${x}"
-       fi
-
-       # only split debug info for final linked objects
-       # or kernel modules as debuginfo for intermediatary
-       # files (think crt*.o from gcc/glibc) is useless and
-       # actually causes problems.  install sources for all
-       # elf types though cause that stuff is good.
-
-       buildid=
-       if [[ ${f} == *"current ar archive"* ]] ; then
-               __vecho "   ${x:${#ED}}"
-               if ${strip_this} ; then
-                       # If we have split debug enabled, then do not strip 
this.
-                       # There is no concept of splitdebug for objects not yet
-                       # linked in (only for finally linked ELFs), so we have 
to
-                       # retain the debug info in the archive itself.
-                       if ! ${FEATURES_splitdebug} || ${RESTRICT_splitdebug} ; 
then
-                               ${STRIP} -g "${x}"
-                       fi
-               fi
-       elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; 
then
-               process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS}
-       elif [[ ${f} == *"SB relocatable"* ]] ; then
-               process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS}
-       fi
-
-       if ${was_not_writable} ; then
-               chmod u-w "${x}"
-       fi
-       ) &
-       __multijob_post_fork
-
-done < "${inode_link}"
-done
-
-# With a bit more work, we could run the rsync processes below in
-# parallel, but not sure that'd be an overall improvement.
-__multijob_finish
-
-cd "${tmpdir}"/sources/ && cat * > "${tmpdir}/debug.sources" 2>/dev/null
-if [[ -s ${tmpdir}/debug.sources ]] && \
-   ${FEATURES_installsources} && \
-   ! ${RESTRICT_installsources} && \
-   ${debugedit_found}
-then
-       __vecho "installsources: rsyncing source files"
-       [[ -d ${D%/}/${prepstrip_sources_dir#/} ]] || mkdir -p 
"${D%/}/${prepstrip_sources_dir#/}"
-       grep -zv '/<[^/>]*>$' "${tmpdir}"/debug.sources | \
-               (cd "${WORKDIR}"; LANG=C sort -z -u | \
-               rsync -tL0 --chmod=ugo-st,a+r,go-w,Da+x,Fa-x --files-from=- 
"${WORKDIR}/" "${D%/}/${prepstrip_sources_dir#/}/" )
-
-       # Preserve directory structure.
-       # Needed after running save_elf_sources.
-       # https://bugzilla.redhat.com/show_bug.cgi?id=444310
-       while read -r -d $'\0' emptydir
-       do
-               >> "${emptydir}"/.keepdir
-       done < <(find "${D%/}/${prepstrip_sources_dir#/}/" -type d -empty 
-print0)
+if ___eapi_has_dostrip; then
+       die "${0##*/}: ${0##*/} has been banned for EAPI '$EAPI'; use 'dostrip' 
instead"
 fi
 
-cd "${T}"
-rm -rf "${tmpdir}"
+exec -a "${0}" "${PORTAGE_BIN_PATH}"/estrip "${@}"
diff --git a/bin/ebuild.sh b/bin/ebuild.sh
index 061b1aff4..11441bfb2 100755
--- a/bin/ebuild.sh
+++ b/bin/ebuild.sh
@@ -59,7 +59,7 @@ else
        # These dummy functions are for things that are likely to be called
        # in global scope, even though they are completely useless during
        # the "depend" phase.
-       funcs="diropts docompress exeopts get_KV insopts
+       funcs="diropts docompress dostrip exeopts get_KV insopts
                KV_major KV_micro KV_minor KV_to_int
                libopts register_die_hook register_success_hook
                __strip_duplicate_slashes
diff --git a/bin/estrip b/bin/estrip
new file mode 100755
index 000000000..cc3450b78
--- /dev/null
+++ b/bin/estrip
@@ -0,0 +1,458 @@
+#!/bin/bash
+# Copyright 1999-2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH}"/helper-functions.sh || exit 1
+
+# avoid multiple calls to `has`.  this creates things like:
+#   FEATURES_foo=false
+# if "foo" is not in $FEATURES
+tf() { "$@" && echo true || echo false ; }
+exp_tf() {
+       local flag var=$1
+       shift
+       for flag in "$@" ; do
+               eval ${var}_${flag}=$(tf has ${flag} ${!var})
+       done
+}
+exp_tf FEATURES compressdebug installsources nostrip splitdebug xattr
+exp_tf RESTRICT binchecks installsources splitdebug strip
+
+if ! ___eapi_has_prefix_variables; then
+       EPREFIX= ED=${D}
+fi
+
+banner=false
+SKIP_STRIP=false
+if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
+       SKIP_STRIP=true
+       banner=true
+       ${FEATURES_installsources} || exit 0
+fi
+
+if [[ ${0##*/} != prepstrip ]]; then
+while [[ $# -gt 0 ]] ; do
+       case $1 in
+       --ignore)
+               shift
+
+               skip_dirs=()
+               for skip; do
+                       if [[ -d ${ED%/}/${skip#/} ]]; then
+                               skip_dirs+=( "${ED%/}/${skip#/}" )
+                       else
+                               rm -f "${ED%/}/${skip#/}.estrip" || die
+                       fi
+               done
+
+               if [[ ${skip_dirs[@]} ]]; then
+                       find "${skip_dirs[@]}" -name '*.estrip' -delete || die
+               fi
+
+               exit 0
+               ;;
+       --queue)
+               shift
+
+               find_paths=()
+               for path; do
+                       if [[ -e ${ED%/}/${path#/} ]]; then
+                               find_paths+=( "${ED%/}/${path#/}" )
+                       fi
+               done
+
+               if [[ ${find_paths[@]} ]]; then
+                       while IFS= read -r path; do
+                               >> "${path}.estrip" || die
+                       done < <(
+                               scanelf -yqRBF '#k%F' -k '.symtab' 
"${find_paths[@]}"
+                               find "${find_paths[@]}" -type f ! -type l -name 
'*.a'
+                       )
+               fi
+
+               exit 0
+               ;;
+       --dequeue)
+               [[ -n ${2} ]] && die "${0##*/}: --dequeue takes no additional 
arguments"
+               break
+               ;;
+       *)
+               die "${0##*/}: unknown arguments '$*'"
+               exit 1
+               ;;
+       esac
+       shift
+done
+fi
+
+PRESERVE_XATTR=false
+if [[ ${KERNEL} == linux ]] && ${FEATURES_xattr} ; then
+       PRESERVE_XATTR=true
+       if type -P getfattr >/dev/null && type -P setfattr >/dev/null ; then
+               dump_xattrs() {
+                       getfattr -d -m - --absolute-names "$1"
+               }
+               restore_xattrs() {
+                       setfattr --restore=-
+               }
+       else
+               dump_xattrs() {
+                       PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
+                       "${PORTAGE_PYTHON:-/usr/bin/python}" \
+                       "${PORTAGE_BIN_PATH}/xattr-helper.py" --dump < <(echo 
-n "$1")
+               }
+               restore_xattrs() {
+                       PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
+                       "${PORTAGE_PYTHON:-/usr/bin/python}" \
+                       "${PORTAGE_BIN_PATH}/xattr-helper.py" --restore
+               }
+       fi
+fi
+
+# look up the tools we might be using
+for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
+       v=${t%:*} # STRIP
+       t=${t#*:} # strip
+       eval ${v}=\"${!v:-${CHOST}-${t}}\"
+       type -P -- ${!v} >/dev/null || eval ${v}=${t}
+done
+
+# Figure out what tool set we're using to strip stuff
+unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS
+case $(${STRIP} --version 2>/dev/null) in
+*elfutils*) # dev-libs/elfutils
+       # elfutils default behavior is always safe, so don't need to specify
+       # any flags at all
+       SAFE_STRIP_FLAGS=""
+       DEF_STRIP_FLAGS="--remove-comment"
+       SPLIT_STRIP_FLAGS="-f"
+       ;;
+*GNU*) # sys-devel/binutils
+       # We'll leave out -R .note for now until we can check out the relevance
+       # of the section when it has the ALLOC flag set on it ...
+       SAFE_STRIP_FLAGS="--strip-unneeded"
+       DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line -R 
.note.gnu.gold-version"
+       SPLIT_STRIP_FLAGS=
+       ;;
+esac
+: ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}}
+
+prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF}
+
+debugedit=$(type -P debugedit)
+if [[ -z ${debugedit} ]]; then
+       debugedit_paths=(
+               "${EPREFIX}/usr/libexec/rpm/debugedit"
+       )
+       for x in "${debugedit_paths[@]}"; do
+               if [[ -x ${x} ]]; then
+                       debugedit=${x}
+                       break
+               fi
+       done
+fi
+[[ ${debugedit} ]] && debugedit_found=true || debugedit_found=false
+debugedit_warned=false
+
+__multijob_init
+
+# Setup $T filesystem layout that we care about.
+tmpdir="${T}/prepstrip"
+rm -rf "${tmpdir}"
+mkdir -p "${tmpdir}"/{inodes,splitdebug,sources}
+
+# Usage: save_elf_sources <elf>
+save_elf_sources() {
+       ${FEATURES_installsources} || return 0
+       ${RESTRICT_installsources} && return 0
+       if ! ${debugedit_found} ; then
+               if ! ${debugedit_warned} ; then
+                       debugedit_warned=true
+                       ewarn "FEATURES=installsources is enabled but the 
debugedit binary could not be"
+                       ewarn "found. This feature will not work unless 
debugedit or rpm is installed!"
+               fi
+               return 0
+       fi
+
+       local x=$1
+
+       # since we're editing the ELF here, we should recompute the build-id
+       # (the -i flag below).  save that output so we don't need to recompute
+       # it later on in the save_elf_debug step.
+       buildid=$("${debugedit}" -i \
+               -b "${WORKDIR}" \
+               -d "${prepstrip_sources_dir}" \
+               -l "${tmpdir}/sources/${x##*/}.${BASHPID:-$(__bashpid)}" \
+               "${x}")
+}
+
+# Usage: save_elf_debug <elf> [splitdebug file]
+save_elf_debug() {
+       ${FEATURES_splitdebug} || return 0
+       ${RESTRICT_splitdebug} && return 0
+
+       # NOTE: Debug files must be installed in
+       # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs
+       # twice in this path) in order for gdb's debug-file-directory
+       # lookup to work correctly.
+       local x=$1
+       local inode_debug=$2
+       local splitdebug=$3
+       local d_noslash=${D%/}
+       local y=${ED%/}/usr/lib/debug/${x:${#d_noslash}}.debug
+
+       # dont save debug info twice
+       [[ ${x} == *".debug" ]] && return 0
+
+       mkdir -p "${y%/*}"
+
+       if [ -f "${inode_debug}" ] ; then
+               ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
+       else
+               if [[ -n ${splitdebug} ]] ; then
+                       mv "${splitdebug}" "${y}"
+               else
+                       local objcopy_flags="--only-keep-debug"
+                       ${FEATURES_compressdebug} && objcopy_flags+=" 
--compress-debug-sections"
+                       ${OBJCOPY} ${objcopy_flags} "${x}" "${y}"
+                       ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
+               fi
+               # Only do the following if the debug file was
+               # successfully created (see bug #446774).
+               if [ $? -eq 0 ] ; then
+                       local args="a-x,o-w"
+                       [[ -g ${x} || -u ${x} ]] && args+=",go-r"
+                       chmod ${args} "${y}"
+                       ln "${y}" "${inode_debug}" || die "ln failed 
unexpectedly"
+               fi
+       fi
+
+       # if we don't already have build-id from debugedit, look it up
+       if [[ -z ${buildid} ]] ; then
+               # convert the readelf output to something useful
+               buildid=$(${READELF} -n "${x}" 2>/dev/null | awk '/Build ID:/{ 
print $NF; exit }')
+       fi
+       if [[ -n ${buildid} ]] ; then
+               local 
buildid_dir="${ED%/}/usr/lib/debug/.build-id/${buildid:0:2}"
+               local buildid_file="${buildid_dir}/${buildid:2}"
+               mkdir -p "${buildid_dir}"
+               [ -L "${buildid_file}".debug ] || ln -s 
"../../${x:${#D}}.debug" "${buildid_file}.debug"
+               [ -L "${buildid_file}" ] || ln -s "/${x:${#D}}" 
"${buildid_file}"
+       fi
+}
+
+# Usage: process_elf <elf>
+process_elf() {
+       local x=$1 inode_link=$2 strip_flags=${*:3}
+       local already_stripped lockfile xt_data
+
+       __vecho "   ${x:${#ED}}"
+
+       # If two processes try to debugedit or strip the same hardlink at the
+       # same time, it may corrupt files or cause loss of splitdebug info.
+       # So, use a lockfile to prevent interference (easily observed with
+       # dev-vcs/git which creates ~111 hardlinks to one file in
+       # /usr/libexec/git-core).
+       lockfile=${inode_link}_lockfile
+       if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then
+               while [[ -f ${lockfile} ]] ; do
+                       sleep 1
+               done
+               unset lockfile
+       fi
+
+       [ -f "${inode_link}_stripped" ] && already_stripped=true || 
already_stripped=false
+
+       if ! ${already_stripped} ; then
+               if ${PRESERVE_XATTR} ; then
+                       xt_data=$(dump_xattrs "${x}")
+               fi
+               save_elf_sources "${x}"
+       fi
+
+       if ${strip_this} ; then
+
+               # see if we can split & strip at the same time
+               if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then
+                       local shortname="${x##*/}.debug"
+                       local 
splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID:-$(__bashpid)}"
+                       ${already_stripped} || \
+                       ${STRIP} ${strip_flags} \
+                               -f "${splitdebug}" \
+                               -F "${shortname}" \
+                               "${x}"
+                       save_elf_debug "${x}" "${inode_link}_debug" 
"${splitdebug}"
+               else
+                       save_elf_debug "${x}" "${inode_link}_debug"
+                       ${already_stripped} || \
+                       ${STRIP} ${strip_flags} "${x}"
+               fi
+       fi
+
+       if ${already_stripped} ; then
+               rm -f "${x}" || die "rm failed unexpectedly"
+               ln "${inode_link}_stripped" "${x}" || die "ln failed 
unexpectedly"
+       else
+               ln "${x}" "${inode_link}_stripped" || die "ln failed 
unexpectedly"
+               if [[ ${xt_data} ]] ; then
+                       restore_xattrs <<< "${xt_data}"
+               fi
+       fi
+
+       [[ -n ${lockfile} ]] && rm -f "${lockfile}"
+}
+
+# The existance of the section .symtab tells us that a binary is stripped.
+# We want to log already stripped binaries, as this may be a QA violation.
+# They prevent us from getting the splitdebug data.
+if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then
+       # We need to do the non-stripped scan serially first before we turn 
around
+       # and start stripping the files ourselves.  The log parsing can be done 
in
+       # parallel though.
+       log=${tmpdir}/scanelf-already-stripped.log
+       scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED%/}/##" > 
"${log}"
+       (
+       __multijob_child_init
+       qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
+       [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
+       if [[ -n ${QA_PRESTRIPPED} && -s ${log} && \
+               ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
+               shopts=$-
+               set -o noglob
+               for x in ${QA_PRESTRIPPED} ; do
+                       sed -e "s#^${x#/}\$##" -i "${log}"
+               done
+               set +o noglob
+               set -${shopts}
+       fi
+       sed -e "/^\$/d" -e "s#^#/#" -i "${log}"
+       if [[ -s ${log} ]] ; then
+               __vecho -e "\n"
+               eqawarn "QA Notice: Pre-stripped files found:"
+               eqawarn "$(<"${log}")"
+       else
+               rm -f "${log}"
+       fi
+       ) &
+       __multijob_post_fork
+fi
+
+# Since strip creates a new inode, we need to know the initial set of
+# inodes in advance, so that we can avoid interference due to trying
+# to strip the same (hardlinked) file multiple times in parallel.
+# See bug #421099.
+if  [[ ${USERLAND} == BSD ]] ; then
+       get_inode_number() { stat -f '%i' "$1"; }
+else
+       get_inode_number() { stat -c '%i' "$1"; }
+fi
+cd "${tmpdir}/inodes" || die "cd failed unexpectedly"
+while read -r x ; do
+       inode_link=$(get_inode_number "${x}") || die "stat failed unexpectedly"
+       echo "${x}" >> "${inode_link}" || die "echo failed unexpectedly"
+done < <(
+       # Use sort -u to eliminate duplicates for bug #445336.
+       (
+               scanelf -yqRBF '#k%F' -k '.symtab' "$@"
+               find "$@" -type f ! -type l -name '*.a'
+       ) | LC_ALL=C sort -u
+)
+
+# Now we look for unstripped binaries.
+for inode_link in $(shopt -s nullglob; echo *) ; do
+while read -r x
+do
+
+       if ! ${banner} ; then
+               __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
+               banner=true
+       fi
+
+       (
+       __multijob_child_init
+       f=$(file "${x}") || exit 0
+       [[ -z ${f} ]] && exit 0
+
+       if ! ${SKIP_STRIP} ; then
+               # The noglob funk is to support STRIP_MASK="/*/booga" and to 
keep
+               #  the for loop from expanding the globs.
+               # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
+               set -o noglob
+               strip_this=true
+               for m in $(eval echo ${STRIP_MASK}) ; do
+                       [[ /${x#${ED%/}} == ${m} ]] && strip_this=false && break
+               done
+               set +o noglob
+       else
+               strip_this=false
+       fi
+
+       # In Prefix we are usually an unprivileged user, so we can't strip
+       # unwritable objects.  Make them temporarily writable for the
+       # stripping.
+       was_not_writable=false
+       if [[ ! -w ${x} ]] ; then
+               was_not_writable=true
+               chmod u+w "${x}"
+       fi
+
+       # only split debug info for final linked objects
+       # or kernel modules as debuginfo for intermediatary
+       # files (think crt*.o from gcc/glibc) is useless and
+       # actually causes problems.  install sources for all
+       # elf types though cause that stuff is good.
+
+       buildid=
+       if [[ ${f} == *"current ar archive"* ]] ; then
+               __vecho "   ${x:${#ED}}"
+               if ${strip_this} ; then
+                       # If we have split debug enabled, then do not strip 
this.
+                       # There is no concept of splitdebug for objects not yet
+                       # linked in (only for finally linked ELFs), so we have 
to
+                       # retain the debug info in the archive itself.
+                       if ! ${FEATURES_splitdebug} || ${RESTRICT_splitdebug} ; 
then
+                               ${STRIP} -g "${x}"
+                       fi
+               fi
+       elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; 
then
+               process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS}
+       elif [[ ${f} == *"SB relocatable"* ]] ; then
+               process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS}
+       fi
+
+       if ${was_not_writable} ; then
+               chmod u-w "${x}"
+       fi
+       ) &
+       __multijob_post_fork
+
+done < "${inode_link}"
+done
+
+# With a bit more work, we could run the rsync processes below in
+# parallel, but not sure that'd be an overall improvement.
+__multijob_finish
+
+cd "${tmpdir}"/sources/ && cat * > "${tmpdir}/debug.sources" 2>/dev/null
+if [[ -s ${tmpdir}/debug.sources ]] && \
+   ${FEATURES_installsources} && \
+   ! ${RESTRICT_installsources} && \
+   ${debugedit_found}
+then
+       __vecho "installsources: rsyncing source files"
+       [[ -d ${D%/}/${prepstrip_sources_dir#/} ]] || mkdir -p 
"${D%/}/${prepstrip_sources_dir#/}"
+       grep -zv '/<[^/>]*>$' "${tmpdir}"/debug.sources | \
+               (cd "${WORKDIR}"; LANG=C sort -z -u | \
+               rsync -tL0 --chmod=ugo-st,a+r,go-w,Da+x,Fa-x --files-from=- 
"${WORKDIR}/" "${D%/}/${prepstrip_sources_dir#/}/" )
+
+       # Preserve directory structure.
+       # Needed after running save_elf_sources.
+       # https://bugzilla.redhat.com/show_bug.cgi?id=444310
+       while read -r -d $'\0' emptydir
+       do
+               >> "${emptydir}"/.keepdir
+       done < <(find "${D%/}/${prepstrip_sources_dir#/}/" -type d -empty 
-print0)
+fi
+
+cd "${T}"
+rm -rf "${tmpdir}"
diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh
index 7643af7b5..df8361036 100755
--- a/bin/misc-functions.sh
+++ b/bin/misc-functions.sh
@@ -224,6 +224,12 @@ install_qa_check() {
        ecompressdir --dequeue
        ecompress --dequeue
 
+       if ___eapi_has_dostrip; then
+               "${PORTAGE_BIN_PATH}"/estrip --queue "${PORTAGE_DOSTRIP[@]}"
+               "${PORTAGE_BIN_PATH}"/estrip --ignore 
"${PORTAGE_DOSTRIP_SKIP[@]}"
+               "${PORTAGE_BIN_PATH}"/estrip --dequeue
+       fi
+
        # 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
diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
index 5eeecfef7..556d089b5 100644
--- a/bin/phase-helpers.sh
+++ b/bin/phase-helpers.sh
@@ -20,6 +20,9 @@ export MOPREFIX=${PN}
 export PORTAGE_DOCOMPRESS_SIZE_LIMIT="128"
 declare -a PORTAGE_DOCOMPRESS=( /usr/share/{doc,info,man} )
 declare -a PORTAGE_DOCOMPRESS_SKIP=( /usr/share/doc/${PF}/html )
+declare -a PORTAGE_DOSTRIP=( / )
+has strip ${RESTRICT} && PORTAGE_DOSTRIP=()
+declare -a PORTAGE_DOSTRIP_SKIP=()
 
 into() {
        if [ "$1" == "/" ]; then
@@ -160,6 +163,32 @@ docompress() {
        fi
 }
 
+dostrip() {
+       ___eapi_has_dostrip || die "'${FUNCNAME}' not supported in this EAPI"
+
+       local f g
+       if [[ $1 = "-x" ]]; then
+               shift
+               for f; do
+                       f=$(__strip_duplicate_slashes "${f}"); f=${f%/}
+                       [[ ${f:0:1} = / ]] || f="/${f}"
+                       for g in "${PORTAGE_DOSTRIP_SKIP[@]}"; do
+                               [[ ${f} = "${g}" ]] && continue 2
+                       done
+                       PORTAGE_DOSTRIP_SKIP+=( "${f}" )
+               done
+       else
+               for f; do
+                       f=$(__strip_duplicate_slashes "${f}"); f=${f%/}
+                       [[ ${f:0:1} = / ]] || f="/${f}"
+                       for g in "${PORTAGE_DOSTRIP[@]}"; do
+                               [[ ${f} = "${g}" ]] && continue 2
+                       done
+                       PORTAGE_DOSTRIP+=( "${f}" )
+               done
+       fi
+}
+
 useq() {
        has $EBUILD_PHASE prerm postrm || eqawarn \
                "QA Notice: The 'useq' function is deprecated (replaced by 
'use')"
diff --git a/bin/save-ebuild-env.sh b/bin/save-ebuild-env.sh
index e5ae8af88..947ac79d5 100644
--- a/bin/save-ebuild-env.sh
+++ b/bin/save-ebuild-env.sh
@@ -15,7 +15,7 @@ __save_ebuild_env() {
        if has --exclude-init-phases $* ; then
                unset S _E_DESTTREE _E_INSDESTTREE _E_DOCDESTTREE_ 
_E_EXEDESTTREE_ \
                        PORTAGE_DOCOMPRESS_SIZE_LIMIT PORTAGE_DOCOMPRESS \
-                       PORTAGE_DOCOMPRESS_SKIP
+                       PORTAGE_DOCOMPRESS_SKIP PORTAGE_DOSTRIP 
PORTAGE_DOSTRIP_SKIP
                if [[ -n $PYTHONPATH &&
                        ${PYTHONPATH%%:*} -ef $PORTAGE_PYM_PATH ]] ; then
                        if [[ $PYTHONPATH == *:* ]] ; then
@@ -60,7 +60,7 @@ __save_ebuild_env() {
                unpack __strip_duplicate_slashes econf einstall \
                __dyn_setup __dyn_unpack __dyn_clean \
                into insinto exeinto docinto \
-               insopts diropts exeopts libopts docompress \
+               insopts diropts exeopts libopts docompress dostrip \
                __abort_handler __abort_prepare __abort_configure 
__abort_compile \
                __abort_test __abort_install __dyn_prepare __dyn_configure \
                __dyn_compile __dyn_test __dyn_install \
-- 
2.13.6


Reply via email to