diff options
author | Fabian Groffen <grobian@gentoo.org> | 2014-09-28 19:52:16 +0200 |
---|---|---|
committer | Fabian Groffen <grobian@gentoo.org> | 2014-09-28 19:52:16 +0200 |
commit | 990c5f4896b309fdcaf1dbbb5779177ecfcf6e74 (patch) | |
tree | f54ebb8d5bcbfea1986b9c73eee0ec3c5b390577 /bin | |
parent | install_qa_check_macho: introduce QA_IGNORE_INSTALL_NAME_FILES (diff) | |
parent | Use a single grep call for gcc warning checks (diff) | |
download | portage-990c5f4896b309fdcaf1dbbb5779177ecfcf6e74.tar.gz portage-990c5f4896b309fdcaf1dbbb5779177ecfcf6e74.tar.bz2 portage-990c5f4896b309fdcaf1dbbb5779177ecfcf6e74.zip |
Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix
Conflicts:
bin/ebuild-helpers/emake
bin/misc-functions.sh
bin/portageq
doc/Makefile
pym/_emerge/EbuildBuild.py
pym/portage/const.py
pym/portage/dbapi/vartree.py
pym/portage/package/ebuild/doebuild.py
Diffstat (limited to 'bin')
43 files changed, 1630 insertions, 1127 deletions
diff --git a/bin/archive-conf b/bin/archive-conf index 599e5693b..b427b8803 100755 --- a/bin/archive-conf +++ b/bin/archive-conf @@ -14,8 +14,8 @@ from __future__ import print_function import sys from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True diff --git a/bin/binhost-snapshot b/bin/binhost-snapshot index ce156a422..f289394ab 100755 --- a/bin/binhost-snapshot +++ b/bin/binhost-snapshot @@ -13,8 +13,8 @@ except ImportError: from urlparse import urlparse from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage.util._argparse import ArgumentParser diff --git a/bin/chpathtool.py b/bin/chpathtool.py index 7e9f26042..c4716d97d 100755 --- a/bin/chpathtool.py +++ b/bin/chpathtool.py @@ -2,9 +2,11 @@ # Copyright 2011-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -"""Helper tool for converting installed files to custom prefixes. +doc = """Helper tool for converting installed files to custom prefixes. In other words, eprefixy $D for Gentoo/Prefix.""" +__doc__ = doc + import io import os @@ -152,7 +154,7 @@ def chpath_inplace_symlink(filename, st, old, new): def main(argv): - parser = ArgumentParser(description=__doc__) + parser = ArgumentParser(description=doc) try: parser.add_argument('location', default=None, help='root directory (e.g. $D)') @@ -166,7 +168,7 @@ def main(argv): except OptionError: # Argument parsing compatibility for Python 2.6 using optparse. if sys.hexversion < 0x2070000: - parser = OptionParser(description=__doc__, + parser = OptionParser(description=doc, usage="usage: %prog [-h] location old new\n\n" + \ " location: root directory (e.g. $D)\n" + \ " old: original build prefix (e.g. /)\n" + \ diff --git a/bin/clean_locks b/bin/clean_locks index 73213b52b..d44162075 100755 --- a/bin/clean_locks +++ b/bin/clean_locks @@ -6,8 +6,8 @@ from __future__ import print_function import sys, errno from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True diff --git a/bin/deprecated-path b/bin/deprecated-path new file mode 100755 index 000000000..b8aaadbda --- /dev/null +++ b/bin/deprecated-path @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2014 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# Author: +# + +source /lib/gentoo/functions.sh + +scriptpath=${BASH_SOURCE[0]} +scriptname=${scriptpath##*/} + +IFS=':' + +for path in ${PATH}; do + [[ -x ${path}/${scriptname} ]] || continue + [[ ${path}/${scriptname} -ef ${scriptpath} ]] && continue + + unset IFS + eerror "Deprecation warning: Calling ${scriptname} from wrong path: '${scriptpath}'" + eerror "Correct path should be '${path}/${scriptname}', Please correct your scripts or file a bug with the maintainer..." + exec "${path}/${scriptname}" "$@" +done + +unset IFS + +eerror "ERROR: portage file: deprecated-path: Failed to locate ${scriptname} in PATH" +eerror "PATH: ${PATH}" +exit 1 diff --git a/bin/dispatch-conf b/bin/dispatch-conf index a1fe2061c..6f06b35a0 100755 --- a/bin/dispatch-conf +++ b/bin/dispatch-conf @@ -17,8 +17,8 @@ from stat import ST_GID, ST_MODE, ST_UID from random import random import atexit, re, shutil, stat, sys from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os diff --git a/bin/ebuild b/bin/ebuild index bb0d79a75..aa35bb620 100755 --- a/bin/ebuild +++ b/bin/ebuild @@ -38,8 +38,8 @@ signal.signal(debug_signum, debug_signal) import io import os from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os diff --git a/bin/ebuild-helpers/emake b/bin/ebuild-helpers/emake index 60286ec9d..dcb64a399 100755 --- a/bin/ebuild-helpers/emake +++ b/bin/ebuild-helpers/emake @@ -13,7 +13,7 @@ source "${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"/isolated-functions.sh if [[ $PORTAGE_QUIET != 1 ]] ; then ( - for arg in ${MAKE:-make} $MAKEOPTS $EXTRA_EMAKE "$@" ; do + for arg in ${MAKE:-make} $MAKEOPTS "$@" $EXTRA_EMAKE ; do [[ ${arg} == *" "* ]] \ && printf "'%s' " "${arg}" \ || printf "%s " "${arg}" @@ -22,7 +22,7 @@ if [[ $PORTAGE_QUIET != 1 ]] ; then ) >&2 fi -${MAKE:-make} SHELL="${BASH:-/bin/bash}" ${MAKEOPTS} ${EXTRA_EMAKE} "$@" +${MAKE:-make} SHELL="${BASH:-/bin/bash}" ${MAKEOPTS} "$@" ${EXTRA_EMAKE} ret=$? [[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/bin/ebuild-helpers/xattr/install b/bin/ebuild-helpers/xattr/install index b1d23159a..233459fcc 100755 --- a/bin/ebuild-helpers/xattr/install +++ b/bin/ebuild-helpers/xattr/install @@ -4,9 +4,32 @@ PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin} PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym} +INSTALL_XATTR=${EPREFIX}/usr/bin/install-xattr # Use safe cwd, avoiding unsafe import for bug #469338. export __PORTAGE_HELPER_CWD=${PWD} cd "${PORTAGE_PYM_PATH}" export __PORTAGE_HELPER_PATH=${BASH_SOURCE[0]} -PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ - exec "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/install.py" "$@" + +if [[ ${PORTAGE_INSTALL_XATTR_IMPLEMENTATION} == "c" ]]; then + implementation="c" +elif [[ ${PORTAGE_INSTALL_XATTR_IMPLEMENTATION} == "python" ]]; then + implementation="python" +else + # If PORTAGE_INSTALL_XATTR_IMPLEMENTATION is unset or not set to "c" or "python" + # then we'll autodetect, preferring "c" but falling back on "python" + if [[ -x "${INSTALL_XATTR}" ]]; then + implementation="c" + else + implementation="python" + fi +fi + +if [[ "${implementation}" == "c" ]]; then + exec "${INSTALL_XATTR}" "$@" +elif [[ "${implementation}" == "python" ]]; then + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ + exec "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/install.py" "$@" +else + echo "Unknown implementation for PORTAGE_INSTALL_XATTR_IMPLEMENTATION" + exit -1 +fi diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py index 1c7290fd3..5a702417e 100755 --- a/bin/ebuild-ipc.py +++ b/bin/ebuild-ipc.py @@ -24,15 +24,21 @@ else: signal.signal(debug_signum, debug_signal) -# Avoid sandbox violations after python upgrade. -pym_path = os.path.join(os.path.dirname( - os.path.dirname(os.path.realpath(__file__))), "pym") +if os.path.isfile(os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), ".portage_not_installed")): + pym_paths = [os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym")] + sys.path.insert(0, pym_paths[0]) +else: + import distutils.sysconfig + pym_paths = [os.path.join(distutils.sysconfig.get_python_lib(), x) for x in ("_emerge", "portage")] +# Avoid sandbox violations after Python upgrade. if os.environ.get("SANDBOX_ON") == "1": sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":") - if pym_path not in sandbox_write: - sandbox_write.append(pym_path) - os.environ["SANDBOX_WRITE"] = \ - ":".join(filter(None, sandbox_write)) + for pym_path in pym_paths: + if pym_path not in sandbox_write: + sandbox_write.append(pym_path) + os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write)) + del pym_path, sandbox_write +del pym_paths import portage portage._internal_caller = True diff --git a/bin/ebuild.sh b/bin/ebuild.sh index ef19e5ec7..103caee1b 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -230,10 +230,10 @@ inherit() { __export_funcs_var=__export_functions_$ECLASS_DEPTH unset $__export_funcs_var - if [ "${EBUILD_PHASE}" != "depend" ] && \ - [ "${EBUILD_PHASE}" != "nofetch" ] && \ - [[ ${EBUILD_PHASE} != *rm ]] && \ - [[ ${EMERGE_FROM} != "binary" ]] ; then + if [[ ${EBUILD_PHASE} != depend && ${EBUILD_PHASE} != nofetch && \ + ${EBUILD_PHASE} != *rm && ${EMERGE_FROM} != "binary" && \ + -z ${_IN_INSTALL_QA_CHECK} ]] + then # This is disabled in the *rm phases because they frequently give # false alarms due to INHERITED in /var/db/pkg being outdated # in comparison the the eclasses from the portage tree. It's @@ -256,70 +256,75 @@ inherit() { debug-print "inherit: $1 -> $location" [[ -z ${location} ]] && die "${1}.eclass could not be found by inherit()" - #We need to back up the values of *DEPEND to B_*DEPEND - #(if set).. and then restore them after the inherit call. - - #turn off glob expansion - set -f - - # Retain the old data and restore it later. - unset B_IUSE B_REQUIRED_USE B_DEPEND B_RDEPEND B_PDEPEND B_HDEPEND - [ "${IUSE+set}" = set ] && B_IUSE="${IUSE}" - [ "${REQUIRED_USE+set}" = set ] && B_REQUIRED_USE="${REQUIRED_USE}" - [ "${DEPEND+set}" = set ] && B_DEPEND="${DEPEND}" - [ "${RDEPEND+set}" = set ] && B_RDEPEND="${RDEPEND}" - [ "${PDEPEND+set}" = set ] && B_PDEPEND="${PDEPEND}" - [ "${HDEPEND+set}" = set ] && B_HDEPEND="${HDEPEND}" - unset IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND HDEPEND - #turn on glob expansion - set +f + # inherits in QA checks can't handle metadata assignments + if [[ -z ${_IN_INSTALL_QA_CHECK} ]]; then + #We need to back up the values of *DEPEND to B_*DEPEND + #(if set).. and then restore them after the inherit call. + + #turn off glob expansion + set -f + + # Retain the old data and restore it later. + unset B_IUSE B_REQUIRED_USE B_DEPEND B_RDEPEND B_PDEPEND B_HDEPEND + [ "${IUSE+set}" = set ] && B_IUSE="${IUSE}" + [ "${REQUIRED_USE+set}" = set ] && B_REQUIRED_USE="${REQUIRED_USE}" + [ "${DEPEND+set}" = set ] && B_DEPEND="${DEPEND}" + [ "${RDEPEND+set}" = set ] && B_RDEPEND="${RDEPEND}" + [ "${PDEPEND+set}" = set ] && B_PDEPEND="${PDEPEND}" + [ "${HDEPEND+set}" = set ] && B_HDEPEND="${HDEPEND}" + unset IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND HDEPEND + #turn on glob expansion + set +f + fi __qa_source "$location" || die "died sourcing $location in inherit()" - #turn off glob expansion - set -f - - # If each var has a value, append it to the global variable E_* to - # be applied after everything is finished. New incremental behavior. - [ "${IUSE+set}" = set ] && E_IUSE+="${E_IUSE:+ }${IUSE}" - [ "${REQUIRED_USE+set}" = set ] && E_REQUIRED_USE+="${E_REQUIRED_USE:+ }${REQUIRED_USE}" - [ "${DEPEND+set}" = set ] && E_DEPEND+="${E_DEPEND:+ }${DEPEND}" - [ "${RDEPEND+set}" = set ] && E_RDEPEND+="${E_RDEPEND:+ }${RDEPEND}" - [ "${PDEPEND+set}" = set ] && E_PDEPEND+="${E_PDEPEND:+ }${PDEPEND}" - [ "${HDEPEND+set}" = set ] && E_HDEPEND+="${E_HDEPEND:+ }${HDEPEND}" - - [ "${B_IUSE+set}" = set ] && IUSE="${B_IUSE}" - [ "${B_IUSE+set}" = set ] || unset IUSE - - [ "${B_REQUIRED_USE+set}" = set ] && REQUIRED_USE="${B_REQUIRED_USE}" - [ "${B_REQUIRED_USE+set}" = set ] || unset REQUIRED_USE - - [ "${B_DEPEND+set}" = set ] && DEPEND="${B_DEPEND}" - [ "${B_DEPEND+set}" = set ] || unset DEPEND - - [ "${B_RDEPEND+set}" = set ] && RDEPEND="${B_RDEPEND}" - [ "${B_RDEPEND+set}" = set ] || unset RDEPEND - - [ "${B_PDEPEND+set}" = set ] && PDEPEND="${B_PDEPEND}" - [ "${B_PDEPEND+set}" = set ] || unset PDEPEND - - [ "${B_HDEPEND+set}" = set ] && HDEPEND="${B_HDEPEND}" - [ "${B_HDEPEND+set}" = set ] || unset HDEPEND - - #turn on glob expansion - set +f + if [[ -z ${_IN_INSTALL_QA_CHECK} ]]; then + #turn off glob expansion + set -f + + # If each var has a value, append it to the global variable E_* to + # be applied after everything is finished. New incremental behavior. + [ "${IUSE+set}" = set ] && E_IUSE+="${E_IUSE:+ }${IUSE}" + [ "${REQUIRED_USE+set}" = set ] && E_REQUIRED_USE+="${E_REQUIRED_USE:+ }${REQUIRED_USE}" + [ "${DEPEND+set}" = set ] && E_DEPEND+="${E_DEPEND:+ }${DEPEND}" + [ "${RDEPEND+set}" = set ] && E_RDEPEND+="${E_RDEPEND:+ }${RDEPEND}" + [ "${PDEPEND+set}" = set ] && E_PDEPEND+="${E_PDEPEND:+ }${PDEPEND}" + [ "${HDEPEND+set}" = set ] && E_HDEPEND+="${E_HDEPEND:+ }${HDEPEND}" + + [ "${B_IUSE+set}" = set ] && IUSE="${B_IUSE}" + [ "${B_IUSE+set}" = set ] || unset IUSE + + [ "${B_REQUIRED_USE+set}" = set ] && REQUIRED_USE="${B_REQUIRED_USE}" + [ "${B_REQUIRED_USE+set}" = set ] || unset REQUIRED_USE + + [ "${B_DEPEND+set}" = set ] && DEPEND="${B_DEPEND}" + [ "${B_DEPEND+set}" = set ] || unset DEPEND + + [ "${B_RDEPEND+set}" = set ] && RDEPEND="${B_RDEPEND}" + [ "${B_RDEPEND+set}" = set ] || unset RDEPEND + + [ "${B_PDEPEND+set}" = set ] && PDEPEND="${B_PDEPEND}" + [ "${B_PDEPEND+set}" = set ] || unset PDEPEND + + [ "${B_HDEPEND+set}" = set ] && HDEPEND="${B_HDEPEND}" + [ "${B_HDEPEND+set}" = set ] || unset HDEPEND + + #turn on glob expansion + set +f + + if [[ -n ${!__export_funcs_var} ]] ; then + for x in ${!__export_funcs_var} ; do + debug-print "EXPORT_FUNCTIONS: $x -> ${ECLASS}_$x" + declare -F "${ECLASS}_$x" >/dev/null || \ + die "EXPORT_FUNCTIONS: ${ECLASS}_$x is not defined" + eval "$x() { ${ECLASS}_$x \"\$@\" ; }" > /dev/null + done + fi + unset $__export_funcs_var - if [[ -n ${!__export_funcs_var} ]] ; then - for x in ${!__export_funcs_var} ; do - debug-print "EXPORT_FUNCTIONS: $x -> ${ECLASS}_$x" - declare -F "${ECLASS}_$x" >/dev/null || \ - die "EXPORT_FUNCTIONS: ${ECLASS}_$x is not defined" - eval "$x() { ${ECLASS}_$x \"\$@\" ; }" > /dev/null - done + has $1 $INHERITED || export INHERITED="$INHERITED $1" fi - unset $__export_funcs_var - - has $1 $INHERITED || export INHERITED="$INHERITED $1" shift done diff --git a/bin/egencache b/bin/egencache index 4ec4108e8..e2f57a58a 100755 --- a/bin/egencache +++ b/bin/egencache @@ -41,8 +41,8 @@ import textwrap import re from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os, _encodings, _unicode_encode, _unicode_decode diff --git a/bin/emaint b/bin/emaint index 00711aa81..784d8613e 100755 --- a/bin/emaint +++ b/bin/emaint @@ -26,8 +26,8 @@ except KeyboardInterrupt: sys.exit(1) from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage.emaint.main import emaint_main diff --git a/bin/emerge b/bin/emerge index 273c0db04..ae6b1c131 100755 --- a/bin/emerge +++ b/bin/emerge @@ -36,21 +36,27 @@ try: signal.signal(debug_signum, debug_signal) from os import path as osp - pym_path = osp.join(osp.dirname(osp.dirname( - osp.realpath(__file__))), "pym") - sys.path.insert(0, pym_path) + if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True portage._disable_legacy_globals() from _emerge.main import emerge_main if __name__ == "__main__": - from portage.exception import ParseError, PermissionDenied + from portage.exception import IsADirectory, ParseError, \ + PermissionDenied try: retval = emerge_main() except PermissionDenied as e: sys.stderr.write("Permission denied: '%s'\n" % str(e)) sys.exit(e.errno) + except IsADirectory as e: + sys.stderr.write("'%s' is a directory, but should be a file!\n" + "See portage man page for information on " + "which files may be directories.\n" % + str(e)) + sys.exit(e.errno) except ParseError as e: sys.stderr.write("%s\n" % str(e)) sys.exit(1) diff --git a/bin/emerge-webrsync b/bin/emerge-webrsync index 340c35915..dbcc294cf 100755 --- a/bin/emerge-webrsync +++ b/bin/emerge-webrsync @@ -257,12 +257,12 @@ sync_local() { if has metadata-transfer ${FEATURES} ; then __vecho "Updating cache ..." - "${PORTAGE_BIN_PATH}/emerge" --metadata + emerge --metadata fi local post_sync=${PORTAGE_CONFIGROOT}etc/portage/bin/post_sync [ -x "${post_sync}" ] && "${post_sync}" # --quiet suppresses output if there are no relevant news items - has news ${FEATURES} && "${PORTAGE_BIN_PATH}/emerge" --check-news --quiet + has news ${FEATURES} && emerge --check-news --quiet return 0 } diff --git a/bin/env-update b/bin/env-update index aefbf21b6..5b99e66dd 100755 --- a/bin/env-update +++ b/bin/env-update @@ -26,8 +26,8 @@ if len(sys.argv) > 1: usage(1) from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True diff --git a/bin/fixpackages b/bin/fixpackages index a4e411da5..bc242b794 100755 --- a/bin/fixpackages +++ b/bin/fixpackages @@ -8,8 +8,8 @@ import os import sys from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os diff --git a/bin/glsa-check b/bin/glsa-check index 85d4c4149..78728d43c 100755 --- a/bin/glsa-check +++ b/bin/glsa-check @@ -8,8 +8,8 @@ import sys import codecs from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os diff --git a/bin/install-qa-check.d/05double-D b/bin/install-qa-check.d/05double-D new file mode 100644 index 000000000..1634afd78 --- /dev/null +++ b/bin/install-qa-check.d/05double-D @@ -0,0 +1,17 @@ +# Check for accidential install into ${D}/${D} + +DD_check() { + if [[ -d ${D%/}${D} ]] ; then + local -i INSTALLTOD=0 + while read -r -d $'\0' i ; do + eqawarn "QA Notice: /${i##${D%/}${D}} installed in \${D}/\${D}" + ((INSTALLTOD++)) + done < <(find "${D%/}${D}" -print0) + die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D%/}${D}" + fi +} + +DD_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix new file mode 100644 index 000000000..32561e263 --- /dev/null +++ b/bin/install-qa-check.d/05prefix @@ -0,0 +1,118 @@ +# Prefix specific QA checks + +install_qa_check_prefix() { + [[ ${ED} == ${D} ]] && return + + 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 + + # 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 or an init + # script? + if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${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_qa_check_prefix +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/10executable-issues b/bin/install-qa-check.d/10executable-issues new file mode 100644 index 000000000..f765749b6 --- /dev/null +++ b/bin/install-qa-check.d/10executable-issues @@ -0,0 +1,140 @@ +# Check for major issues with built executables: insecure RPATHs, +# text relocations, executable stacks + +elf_check() { + if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then + local insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET} + local f x + + # display warnings when using stricter because we die afterwards + if has stricter ${FEATURES} ; then + local PORTAGE_QUIET + fi + + # Make sure we disallow insecure RUNPATH/RPATHs. + # 1) References to PORTAGE_BUILDDIR are banned because it's a + # security risk. We don't want to load files from a + # temporary directory. + # 2) If ROOT != "/", references to ROOT are banned because + # that directory won't exist on the target system. + # 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+=" ${ROOT}" + fi + 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%%:*}" + TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null + fi + done + done + + # Reject set*id binaries with $ORIGIN in RPATH #260331 + x=$( + 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' + 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' + if [[ -n ${x} ]] || has stricter ${FEATURES} ; then + insecure_rpath=1 + fi + fi + + # TEXTRELs are baaaaaaaad + # Allow devs to mark things as ignorable ... e.g. things that are + # binary-only and upstream isn't cooperating (nvidia-glx) ... we + # allow ebuild authors to set QA_TEXTRELS_arch and QA_TEXTRELS ... + # the former overrides the latter ... regexes allowed ! :) + local qa_var="QA_TEXTRELS_${ARCH/-/_}" + [[ -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' "${ED}" | grep -v 'usr/lib/debug/') + if [[ -n ${f} ]] ; then + scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log + __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" + eqawarn " risk. On some architectures, the code may not even function" + eqawarn " properly, if at all." + 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' + die_msg="${die_msg} textrels," + sleep 1 + fi + + # Also, executable stacks only matter on linux (and just glibc atm ...) + f="" + case ${CTARGET:-${CHOST}} in + *-linux-gnu*) + # Check for files with executable stacks, but only on arches which + # are supported at the moment. Keep this list in sync with + # http://www.gentoo.org/proj/en/hardened/gnu-stack.xml (Arch Status) + case ${CTARGET:-${CHOST}} in + arm*|i?86*|ia64*|m68k*|s390*|sh*|x86_64*) + # Allow devs to mark things as ignorable ... e.g. things + # that are binary-only and upstream isn't cooperating ... + # we allow ebuild authors to set QA_EXECSTACK_arch and + # QA_EXECSTACK ... the former overrides the latter ... + # regexes allowed ! :) + + qa_var="QA_EXECSTACK_${ARCH/-/_}" + [[ -n ${!qa_var} ]] && QA_EXECSTACK=${!qa_var} + [[ -n ${QA_STRICT_EXECSTACK} ]] && QA_EXECSTACK="" + qa_var="QA_WX_LOAD_${ARCH/-/_}" + [[ -n ${!qa_var} ]] && QA_WX_LOAD=${!qa_var} + [[ -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' "${ED}" | grep -v 'usr/lib/debug/') + ;; + esac + ;; + esac + 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' + 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" + eqawarn " http://bugs.gentoo.org/ to make sure the issue is fixed." + eqawarn " For more information, see http://hardened.gentoo.org/gnu-stack.xml" + eqawarn " Please include the following list of files in your report:" + 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' + die_msg="${die_msg} execstacks" + sleep 1 + fi + + if [[ ${insecure_rpath} -eq 1 ]] ; then + die "Aborting due to serious QA concerns with RUNPATH/RPATH" + elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then + die "Aborting due to QA concerns: ${die_msg}" + fi + fi +} + +elf_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/10ignored-flags b/bin/install-qa-check.d/10ignored-flags new file mode 100644 index 000000000..7aa9eb695 --- /dev/null +++ b/bin/install-qa-check.d/10ignored-flags @@ -0,0 +1,99 @@ +# QA checks for ignored *FLAGS. + +ignored_flag_check() { + type -P scanelf > /dev/null || return + has binchecks ${RESTRICT} && return + + local 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 + + local f x + + # 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 [[ "${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}") ; 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 + + # Check for files built without respecting LDFLAGS + if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \ + ! has binchecks ${RESTRICT} ; then + f=$(scanelf -qyRF '#k%p' -k .hash "${ED}") + if [[ -n ${f} ]] ; then + echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log + 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. + sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \ + -i "${T}"/scanelf-ignored-LDFLAGS.log + f=$(<"${T}"/scanelf-ignored-LDFLAGS.log) + if [[ -n ${f} ]] ; then + __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' + sleep 1 + else + rm -f "${T}"/scanelf-ignored-LDFLAGS.log + fi + fi + fi +} + +ignored_flag_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/20deprecated-directories b/bin/install-qa-check.d/20deprecated-directories new file mode 100644 index 000000000..fb82bfe7a --- /dev/null +++ b/bin/install-qa-check.d/20deprecated-directories @@ -0,0 +1,18 @@ +# Check for deprecated directories + +deprecated_dir_check() { + local x f= + for x in etc/app-defaults usr/man usr/info usr/X11R6 usr/doc usr/locale ; do + [[ -d ${ED}/$x ]] && f+=" $x\n" + done + if [[ -n $f ]] ; then + eqawarn "QA Notice: This ebuild installs into the following deprecated directories:" + eqawarn + eqawarn "$f" + fi +} + +deprecated_dir_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/20runtime-directories b/bin/install-qa-check.d/20runtime-directories new file mode 100644 index 000000000..2e21d6d04 --- /dev/null +++ b/bin/install-qa-check.d/20runtime-directories @@ -0,0 +1,26 @@ +# Check for directories that need to be created at runtime + +runtime_dir_check() { + # It's ok create these directories, but not to install into them. #493154 + # TODO: We should add var/lib to this list. + local x f= + for x in var/cache var/lock var/run run ; do + if [[ ! -L ${ED}/${x} && -d ${ED}/${x} ]] ; then + if [[ -z $(find "${ED}/${x}" -prune -empty) ]] ; then + f+=$(cd "${ED}"; find "${x}" -printf ' %p\n') + fi + fi + done + if [[ -n ${f} ]] ; then + eqawarn "QA Notice: This ebuild installs into paths that should be created at runtime." + eqawarn " To fix, simply do not install into these directories. Instead, your package" + eqawarn " should create dirs on the fly at runtime as needed via init scripts/etc..." + eqawarn + eqawarn "${f}" + fi +} + +runtime_dir_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60bash-completion b/bin/install-qa-check.d/60bash-completion new file mode 100644 index 000000000..c1547619a --- /dev/null +++ b/bin/install-qa-check.d/60bash-completion @@ -0,0 +1,130 @@ +# QA checks for bash-completion files + +bashcomp_check() { + # Check for correct bash-completion install path. + local syscompdir=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null) + : ${syscompdir:=${EPREFIX}/usr/share/bash-completion/completions} + + local instcompdir + if [[ -d ${ED}/usr/share/bash-completion/completions ]]; then + instcompdir=${ED}/usr/share/bash-completion/completions + elif [[ -d ${ED}/usr/share/bash-completion ]]; then + if [[ ${syscompdir} != ${EPREFIX}/usr/share/bash-completion ]]; then + eqawarn "Bash completions were installed in legacy location. Please update" + eqawarn "the ebuild to get the install paths using bash-completion-r1.eclass." + eqawarn + fi + + instcompdir=${ED}/usr/share/bash-completion + fi + + # Do a few QA tests on bash completions. + if [[ -n ${instcompdir} && -f ${EROOT}/usr/share/bash-completion/bash_completion ]]; then + _get_completions() { + # source the file + source "${1}" &>/dev/null + + [[ ${USED_HAVE} == yes ]] && echo '__HAVE_USED__' + + # print the completed commands + while read -a args; do + [[ ${args[0]} == complete ]] || continue + # command always comes last, one per line + echo "${args[$(( ${#args[@]} - 1))]}" + done < <(complete -p) + } + + # load the global helpers + source "${EROOT}"/usr/share/bash-completion/bash_completion + + # clean up predefined completions + complete -r + + # force all completions on + _have() { + return 0 + } + + local USED_HAVE=no + # add a replacement for have() + have() { + USED_HAVE=yes + + unset -v have + _have ${1} && have=yes + } + + local f c completions + local all_compls=() + local all_files=() + local qa_warnings=() + + for f in "${instcompdir}"/*; do + # ignore directories and other non-files + [[ ! -f ${f} ]] && continue + + # skip the common code file + # (in case we're run in /usr/share/bash-completion) + [[ ${f##*/} == bash_completion ]] && continue + + completions=( $(_get_completions "${f}") ) + + if [[ ${completions[0]} == __HAVE_USED__ ]]; then + qa_warnings+=( + "${f##*/}: 'have' command is deprecated and must not be used." + ) + unset 'completions[0]' + fi + + if [[ -z ${completions[@]} ]]; then + qa_warnings+=( + "${f##*/}: does not define any completions (failed to source?)." + ) + continue + fi + + for c in "${completions[@]}"; do + if [[ ${c} == /* ]]; then + qa_warnings+=( + "${f##*/}: absolute paths can not be used for completions (on '${c}')." + ) + else + all_compls+=( "${c}" ) + fi + done + + if ! has "${f##*/}" "${all_compls[@]}"; then + qa_warnings+=( + "${f##*/}: incorrect name, no completions for '${f##*/}' command defined." + ) + fi + + all_files+=( "${f##*/}" ) + done + + for c in "${all_compls[@]}"; do + if ! has "${c}" "${all_files[@]}"; then + qa_warnings+=( + "${c}: missing alias (symlink) for completed command." + ) + fi + done + + if [[ -n ${qa_warnings[@]} ]]; then + eqawarn "Problems with installed bash completions were found:" + eqawarn + for c in "${qa_warnings[@]}"; do + eqawarn " ${c}" + done + eqawarn + eqawarn "For more details on installing bash-completions, please see:" + eqawarn "https://wiki.gentoo.org/wiki/Bash/Installing_completion_files" + eqawarn + fi + fi +} + +bashcomp_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60openrc b/bin/install-qa-check.d/60openrc new file mode 100644 index 000000000..9b7fc6d99 --- /dev/null +++ b/bin/install-qa-check.d/60openrc @@ -0,0 +1,41 @@ +# QA checks for OpenRC init.d files. + +openrc_check() { + # Sanity check syntax errors in init.d scripts + local d i + for d in /etc/conf.d /etc/init.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 + if [[ ${d} == /etc/init.d && ${i} != *.sh ]] ; then + # skip non-shell-script for bug #451386 + [[ $(head -n1 "${i}") =~ ^#!.*[[:space:]/](runscript|sh)$ ]] || continue + fi + bash -n "${i}" || die "The init.d file has syntax errors: ${i}" + done + done + + local checkbashisms=$(type -P checkbashisms) + if [[ -n ${checkbashisms} ]] ; then + for d in /etc/init.d ; do + [[ -d ${ED}${d} ]] || continue + for i in "${ED}${d}"/* ; do + [[ -e ${i} ]] || continue + [[ -L ${i} ]] && continue + f=$("${checkbashisms}" -f "${i}" 2>&1) + [[ $? != 0 && -n ${f} ]] || continue + eqawarn "QA Notice: shell script appears to use non-POSIX feature(s):" + while read -r ; + do eqawarn " ${REPLY}" + done <<< "${f//${ED}}" + done + done + fi +} + +openrc_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60pkgconfig b/bin/install-qa-check.d/60pkgconfig new file mode 100644 index 000000000..1b34c04db --- /dev/null +++ b/bin/install-qa-check.d/60pkgconfig @@ -0,0 +1,15 @@ +# Check for pkg-config file issues + +pkgconfig_check() { + # Look for leaking LDFLAGS into pkg-config files + local 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 +} + +pkgconfig_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60pngfix b/bin/install-qa-check.d/60pngfix new file mode 100644 index 000000000..8d53040b6 --- /dev/null +++ b/bin/install-qa-check.d/60pngfix @@ -0,0 +1,35 @@ +# Check for issues with PNG files + +pngfix_check() { + local pngfix=$(type -P pngfix) + if [[ -n ${pngfix} ]] ; then + local pngout=() + local next + + while read -r -a pngout ; do + local error="" + + case "${pngout[1]}" in + CHK) + error='invalid checksum' + ;; + TFB) + error='broken IDAT window length' + ;; + esac + + if [[ -n ${error} ]] ; then + if [[ -z ${next} ]] ; then + eqawarn "QA Notice: broken .png files found:" + next=1 + fi + eqawarn " ${pngout[@]:7}: ${error}" + fi + done < <(find "${ED}" -type f -name '*.png' -exec "${pngfix}" {} +) + fi +} + +pngfix_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60systemd b/bin/install-qa-check.d/60systemd new file mode 100644 index 000000000..f134a3068 --- /dev/null +++ b/bin/install-qa-check.d/60systemd @@ -0,0 +1,25 @@ +# QA checks for systemd units. + +systemd_check() { + local systemddir f + + # Common mistakes in systemd service files. + if type -P pkg-config >/dev/null && pkg-config --exists systemd; then + systemddir=$(pkg-config --variable=systemdsystemunitdir systemd) + else + systemddir=/usr/lib/systemd/system + fi + if [[ -d ${ED%/}${systemddir} ]]; then + f=$(grep -sH '^EnvironmentFile.*=.*/etc/conf\.d' "${ED%/}${systemddir}"/*.service) + if [[ -n ${f} ]] ; then + eqawarn "QA Notice: systemd units using /etc/conf.d detected:" + eqawarn "${f//${D}}" + eqawarn "See: https://wiki.gentoo.org/wiki/Project:Systemd/conf.d_files" + fi + fi +} + +systemd_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/60udev b/bin/install-qa-check.d/60udev new file mode 100644 index 000000000..4327d069d --- /dev/null +++ b/bin/install-qa-check.d/60udev @@ -0,0 +1,21 @@ +# Check udev rule installs + +udev_check() { + set +f + local x f= + for x in "${ED}etc/udev/rules.d/"* "${ED}lib"*"/udev/rules.d/"* ; do + [[ -e ${x} ]] || continue + [[ ${x} == ${ED}lib/udev/rules.d/* ]] && continue + f+=" ${x#${ED}}\n" + done + if [[ -n $f ]] ; then + eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:" + eqawarn + eqawarn "$f" + fi +} + +udev_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/80libraries b/bin/install-qa-check.d/80libraries new file mode 100644 index 000000000..c83f27800 --- /dev/null +++ b/bin/install-qa-check.d/80libraries @@ -0,0 +1,167 @@ +# Check for issues with installed libraries + +lib_check() { + local f x i j + + if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then + # Check for shared libraries lacking SONAMEs + local qa_var="QA_SONAME_${ARCH/-/_}" + eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")" + f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$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 + if [[ ${#QA_SONAME[@]} -gt 1 ]] ; then + for x in "${QA_SONAME[@]}" ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log + done + else + local shopts=$- + set -o noglob + for x in ${QA_SONAME} ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log + done + set +o noglob + set -${shopts} + fi + fi + sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log + f=$(<"${T}"/scanelf-missing-SONAME.log) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: The following shared libraries lack a SONAME" + eqawarn "${f}" + __vecho -ne '\n' + sleep 1 + else + rm -f "${T}"/scanelf-missing-SONAME.log + fi + fi + + # 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' "${ED}"{,usr/}lib*/lib*.so* | awk '$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 + if [[ ${#QA_DT_NEEDED[@]} -gt 1 ]] ; then + for x in "${QA_DT_NEEDED[@]}" ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log + done + else + local shopts=$- + set -o noglob + for x in ${QA_DT_NEEDED} ; do + sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log + done + set +o noglob + set -${shopts} + fi + fi + sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log + f=$(<"${T}"/scanelf-missing-NEEDED.log) + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: The following shared libraries lack NEEDED entries" + eqawarn "${f}" + __vecho -ne '\n' + sleep 1 + else + rm -f "${T}"/scanelf-missing-NEEDED.log + fi + fi + fi + + # this should help to ensure that all (most?) shared libraries are executable + # and that all libtool scripts / static libraries are not executable + 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#${ED}}" + chmod +x "${j}" + done + + for j in "${i}"/*.a "${i}"/*.la ; do + [[ ! -e ${j} ]] && continue + [[ -L ${j} ]] && continue + [[ ! -x ${j} ]] && continue + __vecho "removing executable bit: ${j#${ED}}" + chmod -x "${j}" + done + + for j in "${i}"/*.{a,dll,dylib,sl,so}.* "${i}"/*.{a,dll,dylib,sl,so} ; do + [[ ! -e ${j} ]] && continue + [[ ! -L ${j} ]] && continue + linkdest=$(readlink "${j}") + if [[ ${linkdest} == /* ]] ; then + __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" + eqawarn " or a linker script if it crosses the /usr boundary." + fi + done + done + + # When installing static libraries into /usr/lib and shared libraries into + # /lib, we have to make sure we have a linker script in /usr/lib along side + # the static library, or gcc will utilize the static lib when linking :(. + # http://bugs.gentoo.org/4411 + local abort="no" + local a s + for a in "${ED}"usr/lib*/*.a ; do + # PREFIX LOCAL: support MachO objects + [[ ${CHOST} == *-darwin* ]] \ + && s=${a%.a}.dylib \ + || s=${a%.a}.so + # END PREFIX LOCAL + if [[ ! -e ${s} ]] ; then + s=${s%usr/*}${s##*/usr/} + if [[ -e ${s} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}" + abort="yes" + fi + fi + done + [[ ${abort} == "yes" ]] && die "add those ldscripts" + + # Make sure people don't store libtool files or static libs in /lib + # PREFIX LOCAL: on AIX, "dynamic libs" have extension .a, so don't + # get false positives + [[ ${CHOST} == *-aix* ]] \ + && f=$(ls "${ED}"lib*/*.la 2>/dev/null || true) \ + || f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null) + # END PREFIX LOCAL + if [[ -n ${f} ]] ; then + __vecho -ne '\n' + eqawarn "QA Notice: Excessive files found in the / partition" + eqawarn "${f}" + __vecho -ne '\n' + die "static archives (*.a) and libtool library files (*.la) belong in /usr/lib*, not /lib*" + fi + + # Verify that the libtool files don't contain bogus $D entries. + local abort=no gentoo_bug=no always_overflow=no + for a in "${ED}"usr/lib*/*.la ; do + s=${a##*/} + if grep -qs "${ED}" "${a}" ; then + __vecho -ne '\n' + eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths" + abort="yes" + fi + done + [[ ${abort} == "yes" ]] && die "soiled libtool library files found" +} + +lib_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/80multilib-strict b/bin/install-qa-check.d/80multilib-strict new file mode 100644 index 000000000..436932e80 --- /dev/null +++ b/bin/install-qa-check.d/80multilib-strict @@ -0,0 +1,50 @@ +# Strict multilib directory checks +multilib_strict_check() { + if has multilib-strict ${FEATURES} && \ + [[ -x ${EPREFIX}/usr/bin/file && -x ${EPREFIX}/usr/bin/find ]] && \ + [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]] + then + rm -f "${T}/multilib-strict.log" + local abort=no dir file + MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g') + for dir in ${MULTILIB_STRICT_DIRS} ; 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 + echo "${file#${ED}//}" >> "${T}/multilib-strict.log" + fi + done + done + + if [[ -s ${T}/multilib-strict.log ]] ; then + if [[ ${#QA_MULTILIB_PATHS[@]} -eq 1 ]] ; then + local shopts=$- + set -o noglob + QA_MULTILIB_PATHS=(${QA_MULTILIB_PATHS}) + set +o noglob + set -${shopts} + fi + if [ "${QA_STRICT_MULTILIB_PATHS-unset}" = unset ] ; then + local x + for x in "${QA_MULTILIB_PATHS[@]}" ; do + sed -e "s#^${x#/}\$##" -i "${T}/multilib-strict.log" + done + sed -e "/^\$/d" -i "${T}/multilib-strict.log" + fi + if [[ -s ${T}/multilib-strict.log ]] ; then + abort=yes + echo "Files matching a file type that is not allowed:" + while read -r ; do + echo " ${REPLY}" + done < "${T}/multilib-strict.log" + fi + fi + + [[ ${abort} == yes ]] && die "multilib-strict check failed!" + fi +} + +multilib_strict_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/90gcc-warnings b/bin/install-qa-check.d/90gcc-warnings new file mode 100644 index 000000000..9703c39de --- /dev/null +++ b/bin/install-qa-check.d/90gcc-warnings @@ -0,0 +1,168 @@ +# Check for important gcc warning + +gcc_warn_check() { + local f + + # Evaluate misc gcc warnings + if [[ -n ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]] ; then + # In debug mode, this variable definition and corresponding grep calls + # will produce false positives if they're shown in the trace. + local reset_debug=0 + if [[ ${-/x/} != $- ]] ; then + set +x + reset_debug=1 + fi + local m msgs=( + # only will and does, no might :) + 'warning: .*will.*\[-Wstrict-aliasing\]' + 'warning: .*does.*\[-Wstrict-aliasing\]' + # implicit declaration of function ‘...’ + 'warning: .*\[-Wimplicit-function-declaration\]' + # with -Wall, goes in pair with -Wimplicit-function-declaration + # but without -Wall, we need to assert for it alone + 'warning: .*incompatible implicit declaration of built-in function' + # 'is used uninitialized in this function' and some more + 'warning: .*\[-Wuninitialized\]' + # comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning + 'warning: .*mathematical meaning*\[-Wparentheses\]' + # null argument where non-null required + 'warning: .*\[-Wnonnull\]' + # array subscript is above/below/outside array bounds + 'warning: .*\[-Warray-bounds\]' + # attempt to free a non-heap object + 'warning: .*\[-Wfree-nonheap-object\]' + # those three do not have matching -W flags, it seems + 'warning: .*will always overflow destination buffer' + 'warning: .*assuming pointer wraparound does not occur' + 'warning: .*escape sequence out of range' + # left/right-hand operand of comma expression has no effect + 'warning: .*comma.*\[-Wunused-value\]' + # converting to non-pointer type ... from NULL and likes + 'warning: .*\[-Wconversion-null\]' + # NULL used in arithmetic + 'warning: .*NULL.*\[-Wpointer-arith\]' + # pointer to a function used in arithmetic and likes + 'warning: .*function.*\[-Wpointer-arith\]' + # the address of ... will never be NULL and likes + # (uses of function refs & string constants in conditionals) + 'warning: .*\[-Waddress\]' + # outdated? + 'warning: .*too few arguments for format' + # format ... expects a matching ... argument + # (iow, too few arguments for format in new wording :)) + 'warning: .*matching.*\[-Wformat=\]' + # function returns address of local variable + 'warning: .*\[-Wreturn-local-addr\]' + # argument to sizeof ... is the same expression as the source + 'warning: .*\[-Wsizeof-pointer-memaccess\]' + # iteration invokes undefined behavior + 'warning: .*\[-Waggressive-loop-optimizations\]' + + # this may be valid code :/ + #': warning: multi-character character constant' + # need to check these two ... + #': warning: assuming signed overflow does not occur when' + #': warning: comparison with string literal results in unspecified behav' + # yacc/lex likes to trigger this one + #': warning: extra tokens at end of .* directive' + # only gcc itself triggers this ? + #': warning: .*noreturn.* function does return' + # these throw false positives when 0 is used instead of NULL + #': warning: missing sentinel in function call' + #': warning: not enough variable arguments to fit a sentinel' + ) + + # join all messages into one grep-expression + local joined_msgs + printf -v joined_msgs '%s|' "${msgs[@]}" + joined_msgs=${joined_msgs%|} + + local abort="no" + local grep_cmd=grep + [[ $PORTAGE_LOG_FILE = *.gz ]] && grep_cmd=zgrep + + # force C locale to work around slow unicode locales #160234 + f=$(LC_CTYPE=C LC_COLLATE=C "${grep_cmd}" -E "${joined_msgs}" "${PORTAGE_LOG_FILE}") + if [[ -n ${f} ]] ; then + abort="yes" + # for now, don't make this fatal (see bug #337031) + #if [[ ${f} == *'will always overflow destination buffer'* ]]; then + # always_overflow=yes + #fi + if [[ $always_overflow = yes ]] ; then + eerror + eerror "QA Notice: Package triggers severe warnings which indicate that it" + eerror " may exhibit random runtime failures." + eerror + eerror "${f}" + eerror + eerror " Please file a bug about this at http://bugs.gentoo.org/" + eerror " with the maintaining herd of the package." + eerror + else + __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' + fi + fi + + local cat_cmd=cat + [[ $PORTAGE_LOG_FILE = *.gz ]] && cat_cmd=zcat + [[ $reset_debug = 1 ]] && set -x + # Use safe cwd, avoiding unsafe import for bug #469338. + f=$(cd "${PORTAGE_PYM_PATH}" ; $cat_cmd "${PORTAGE_LOG_FILE}" | \ + "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py || die "check-implicit-pointer-usage.py failed") + if [[ -n ${f} ]] ; then + + # In the future this will be a forced "die". In preparation, + # increase the log level from "qa" to "eerror" so that people + # are aware this is a problem that must be fixed asap. + + # just warn on 32bit hosts but bail on 64bit hosts + case ${CHOST} in + alpha*|hppa64*|ia64*|powerpc64*|mips64*|sparc64*|sparcv9*|x86_64*) gentoo_bug=yes ;; + esac + + abort=yes + + if [[ $gentoo_bug = yes ]] ; then + eerror + eerror "QA Notice: Package triggers severe warnings which indicate that it" + eerror " will almost certainly crash on 64bit architectures." + eerror + eerror "${f}" + eerror + eerror " Please file a bug about this at http://bugs.gentoo.org/" + eerror " with the maintaining herd of the package." + eerror + else + __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' + fi + + fi + if [[ ${abort} == "yes" ]] ; then + if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then + 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}" + has stricter ${FEATURES} && \ + die "install aborted due to severe warnings shown above" + fi + fi + fi +} + +gcc_warn_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/install-qa-check.d/90world-writable b/bin/install-qa-check.d/90world-writable new file mode 100644 index 000000000..635612dc8 --- /dev/null +++ b/bin/install-qa-check.d/90world-writable @@ -0,0 +1,27 @@ +# Check for world-writable files + +world_writable_check() { + # Now we look for all world writable files. + # PREFIX LOCAL: keep offset prefix in the reported files + local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${D}:- :") + # END PREFIX LOCAL + 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 + fi + + local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')' | sed -e "s:^${D}:/:") + if [[ -n ${unsafe_files} ]] ; then + eqawarn "QA Notice: Unsafe files detected (set*id and world writable)" + eqawarn "${unsafe_files}" + die "Unsafe files found in \${D}. Portage will not install them." + fi +} + +world_writable_check +: # guarantee successful exit + +# vim:ft=sh diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index d92103f4f..1904c258f 100644 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -1,5 +1,5 @@ #!@PORTAGE_BASH@ -# Copyright 1999-2013 Gentoo Foundation +# Copyright 1999-2014 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 @@ -176,63 +176,32 @@ install_qa_check() { cd "${D}" || die "cd failed" # END PREFIX LOCAL - 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 + # Run QA checks from install-qa-check.d. + # Note: checks need to be run *before* stripping. + local f + # TODO: handle nullglob-like + for f in "${PORTAGE_BIN_PATH}"/install-qa-check.d/*; do + # Run in a subshell to treat it like external script, + # but use 'source' to pass all variables through. + ( + source "${f}" || eerror "Post-install QA check ${f##*/} failed to run" + ) + done - # 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}") ; 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 + # Run QA checks from repositories + # (yes, PORTAGE_ECLASS_LOCATIONS contains repo paths...) + local repo_location + for repo_location in "${PORTAGE_ECLASS_LOCATIONS[@]}"; do + for f in "${repo_location}"/metadata/install-qa-check.d/*; do + if [[ -f ${f} ]]; then + ( + # allow inheriting eclasses + _IN_INSTALL_QA_CHECK=1 + source "${f}" || eerror "Post-install QA check ${f##*/} failed to run" + ) 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 + done export STRIP_MASK prepall @@ -240,62 +209,6 @@ install_qa_check() { 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 ${ED}/$x ]] && f+=" $x\n" - done - if [[ -n $f ]] ; then - eqawarn "QA Notice: This ebuild installs into the following deprecated directories:" - eqawarn - eqawarn "$f" - fi - - # It's ok create these directories, but not to install into them. #493154 - # TODO: We should add var/lib to this list. - f= - for x in var/cache var/lock var/run run ; do - if [[ ! -L ${ED}/${x} && -d ${ED}/${x} ]] ; then - if [[ -z $(find "${ED}/${x}" -prune -empty) ]] ; then - f+=$(cd "${ED}"; find "${x}" -printf ' %p\n') - fi - fi - done - if [[ -n ${f} ]] ; then - eqawarn "QA Notice: This ebuild installs into paths that should be created at runtime." - eqawarn " To fix, simply do not install into these directories. Instead, your package" - eqawarn " should create dirs on the fly at runtime as needed via init scripts/etc..." - eqawarn - eqawarn "${f}" - fi - - set +f - f= - for x in "${ED}etc/udev/rules.d/"* "${ED}lib"*"/udev/rules.d/"* ; do - [[ -e ${x} ]] || continue - [[ ${x} == ${ED}lib/udev/rules.d/* ]] && continue - f+=" ${x#${ED}}\n" - done - if [[ -n $f ]] ; then - eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:" - eqawarn - eqawarn "$f" - fi - - # Now we look for all world writable files. - # PREFIX LOCAL: keep offset in the paths - local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${D}:- :") - # END PREFIX LOCAL - 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 - fi - # PREFIX LOCAL: # anything outside the prefix should be caught by the Prefix QA # check, so if there's nothing in ED, we skip searching for QA @@ -329,238 +242,6 @@ install_qa_check() { } install_qa_check_elf() { - 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 - if has stricter ${FEATURES} ; then - unset PORTAGE_QUIET - fi - - # Make sure we disallow insecure RUNPATH/RPATHs. - # 1) References to PORTAGE_BUILDDIR are banned because it's a - # security risk. We don't want to load files from a - # temporary directory. - # 2) If ROOT != "/", references to ROOT are banned because - # that directory won't exist on the target system. - # 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+=" ${ROOT}" - fi - 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%%:*}" - TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null - fi - done - done - - # Reject set*id binaries with $ORIGIN in RPATH #260331 - x=$( - 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' - 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' - if [[ -n ${x} ]] || has stricter ${FEATURES} ; then - insecure_rpath=1 - fi - fi - - # TEXTRELs are baaaaaaaad - # Allow devs to mark things as ignorable ... e.g. things that are - # binary-only and upstream isn't cooperating (nvidia-glx) ... we - # allow ebuild authors to set QA_TEXTRELS_arch and QA_TEXTRELS ... - # the former overrides the latter ... regexes allowed ! :) - qa_var="QA_TEXTRELS_${ARCH/-/_}" - [[ -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' "${ED}" | grep -v 'usr/lib/debug/') - if [[ -n ${f} ]] ; then - scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log - __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" - eqawarn " risk. On some architectures, the code may not even function" - eqawarn " properly, if at all." - 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' - die_msg="${die_msg} textrels," - sleep 1 - fi - - # Also, executable stacks only matter on linux (and just glibc atm ...) - f="" - case ${CTARGET:-${CHOST}} in - *-linux-gnu*) - # Check for files with executable stacks, but only on arches which - # are supported at the moment. Keep this list in sync with - # http://www.gentoo.org/proj/en/hardened/gnu-stack.xml (Arch Status) - case ${CTARGET:-${CHOST}} in - arm*|i?86*|ia64*|m68k*|s390*|sh*|x86_64*) - # Allow devs to mark things as ignorable ... e.g. things - # that are binary-only and upstream isn't cooperating ... - # we allow ebuild authors to set QA_EXECSTACK_arch and - # QA_EXECSTACK ... the former overrides the latter ... - # regexes allowed ! :) - - qa_var="QA_EXECSTACK_${ARCH/-/_}" - [[ -n ${!qa_var} ]] && QA_EXECSTACK=${!qa_var} - [[ -n ${QA_STRICT_EXECSTACK} ]] && QA_EXECSTACK="" - qa_var="QA_WX_LOAD_${ARCH/-/_}" - [[ -n ${!qa_var} ]] && QA_WX_LOAD=${!qa_var} - [[ -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' "${ED}" | grep -v 'usr/lib/debug/') - ;; - esac - ;; - esac - 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' - 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" - eqawarn " http://bugs.gentoo.org/ to make sure the issue is fixed." - eqawarn " For more information, see http://hardened.gentoo.org/gnu-stack.xml" - eqawarn " Please include the following list of files in your report:" - 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' - die_msg="${die_msg} execstacks" - sleep 1 - fi - - # Check for files built without respecting LDFLAGS - if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \ - ! has binchecks ${RESTRICT} ; then - f=$(scanelf -qyRF '#k%p' -k .hash "${ED}") - if [[ -n ${f} ]] ; then - echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log - 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. - sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \ - -i "${T}"/scanelf-ignored-LDFLAGS.log - f=$(<"${T}"/scanelf-ignored-LDFLAGS.log) - if [[ -n ${f} ]] ; then - __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' - sleep 1 - else - rm -f "${T}"/scanelf-ignored-LDFLAGS.log - fi - fi - fi - - if [[ ${insecure_rpath} -eq 1 ]] ; then - die "Aborting due to serious QA concerns with RUNPATH/RPATH" - elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then - die "Aborting due to QA concerns: ${die_msg}" - fi - - # Check for shared libraries lacking SONAMEs - qa_var="QA_SONAME_${ARCH/-/_}" - eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")" - f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$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 - if [[ ${#QA_SONAME[@]} -gt 1 ]] ; then - for x in "${QA_SONAME[@]}" ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log - done - else - local shopts=$- - set -o noglob - for x in ${QA_SONAME} ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log - done - set +o noglob - set -${shopts} - fi - fi - sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log - f=$(<"${T}"/scanelf-missing-SONAME.log) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: The following shared libraries lack a SONAME" - eqawarn "${f}" - __vecho -ne '\n' - sleep 1 - else - rm -f "${T}"/scanelf-missing-SONAME.log - fi - fi - - # Check for shared libraries lacking NEEDED entries - qa_var="QA_DT_NEEDED_${ARCH/-/_}" - eval "[[ -n \${!qa_var} ]] && QA_DT_NEEDED=(\"\${${qa_var}[@]}\")" - # PREFIX LOCAL: keep offset prefix in the recorded files - f=$(scanelf -ByF '%n %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${D}:/:") - # END PREFIX LOCAL - if [[ -n ${f} ]] ; then - echo "${f}" > "${T}"/scanelf-missing-NEEDED.log - if [[ "${QA_STRICT_DT_NEEDED-unset}" == unset ]] ; then - if [[ ${#QA_DT_NEEDED[@]} -gt 1 ]] ; then - for x in "${QA_DT_NEEDED[@]}" ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log - done - else - local shopts=$- - set -o noglob - for x in ${QA_DT_NEEDED} ; do - sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log - done - set +o noglob - set -${shopts} - fi - fi - sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log - f=$(<"${T}"/scanelf-missing-NEEDED.log) - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: The following shared libraries lack NEEDED entries" - eqawarn "${f}" - __vecho -ne '\n' - sleep 1 - else - rm -f "${T}"/scanelf-missing-NEEDED.log - fi - fi - - PORTAGE_QUIET=${tmp_quiet} - 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 @@ -591,441 +272,8 @@ install_qa_check_elf() { } install_qa_check_misc() { - # PREFIX LOCAL: keep offset prefix in the reported files - local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')' | sed -e "s:^${D}:/:") - # END PREFIX LOCAL - if [[ -n ${unsafe_files} ]] ; then - eqawarn "QA Notice: Unsafe files detected (set*id and world writable)" - eqawarn "${unsafe_files}" - die "Unsafe files found in \${D}. Portage will not install them." - fi - - if [[ -d ${D%/}${D} ]] ; then - local -i INSTALLTOD=0 - while read -r -d $'\0' i ; do - eqawarn "QA Notice: /${i##${D%/}${D}} installed in \${D}/\${D}" - ((INSTALLTOD++)) - done < <(find "${D%/}${D}" -print0) - die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D%/}${D}" - fi - - # Sanity check syntax errors in init.d scripts - local d - for d in /etc/conf.d /etc/init.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 - if [[ ${d} == /etc/init.d && ${i} != *.sh ]] ; then - # skip non-shell-script for bug #451386 - [[ $(head -n1 "${i}") =~ ^#!.*[[:space:]/](runscript|sh)$ ]] || continue - fi - bash -n "${i}" || die "The init.d file has syntax errors: ${i}" - done - done - - local checkbashisms=$(type -P checkbashisms) - if [[ -n ${checkbashisms} ]] ; then - for d in /etc/init.d ; do - [[ -d ${ED}${d} ]] || continue - for i in "${ED}${d}"/* ; do - [[ -e ${i} ]] || continue - [[ -L ${i} ]] && continue - f=$("${checkbashisms}" -f "${i}" 2>&1) - [[ $? != 0 && -n ${f} ]] || continue - eqawarn "QA Notice: shell script appears to use non-POSIX feature(s):" - while read -r ; - do eqawarn " ${REPLY}" - done <<< "${f//${ED}}" - done - done - fi - - # 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 "${ED}"opt/*/lib* \ - "${ED}"lib* \ - "${ED}"usr/lib* ; do - [[ ! -d ${i} ]] && continue - - for j in "${i}"/*.so.* "${i}"/*.so "${i}"/*.dylib "${i}"/*.dll ; do - [[ ! -e ${j} ]] && continue - [[ -L ${j} ]] && continue - [[ -x ${j} ]] && continue - __vecho "making executable: ${j#${ED}}" - chmod +x "${j}" - done - - for j in "${i}"/*.a "${i}"/*.la ; do - [[ ! -e ${j} ]] && continue - [[ -L ${j} ]] && continue - [[ ! -x ${j} ]] && continue - __vecho "removing executable bit: ${j#${ED}}" - chmod -x "${j}" - done - - for j in "${i}"/*.{a,dll,dylib,sl,so}.* "${i}"/*.{a,dll,dylib,sl,so} ; do - [[ ! -e ${j} ]] && continue - [[ ! -L ${j} ]] && continue - linkdest=$(readlink "${j}") - if [[ ${linkdest} == /* ]] ; then - __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" - eqawarn " or a linker script if it crosses the /usr boundary." - fi - done - done - - # When installing static libraries into /usr/lib and shared libraries into - # /lib, we have to make sure we have a linker script in /usr/lib along side - # the static library, or gcc will utilize the static lib when linking :(. - # http://bugs.gentoo.org/4411 - abort="no" - local a s - for a in "${ED}"usr/lib*/*.a ; do - # PREFIX LOCAL: support MachO objects - [[ ${CHOST} == *-darwin* ]] \ - && s=${a%.a}.dylib \ - || s=${a%.a}.so - # END PREFIX LOCAL - if [[ ! -e ${s} ]] ; then - s=${s%usr/*}${s##*/usr/} - if [[ -e ${s} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}" - abort="yes" - fi - fi - done - [[ ${abort} == "yes" ]] && die "add those ldscripts" - - # Make sure people don't store libtool files or static libs in /lib - # PREFIX LOCAL: on AIX, "dynamic libs" have extension .a, so don't - # get false positives - [[ ${CHOST} == *-aix* ]] \ - && f=$(ls "${ED}"lib*/*.la 2>/dev/null || true) \ - || f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null) - # END PREFIX LOCAL - if [[ -n ${f} ]] ; then - __vecho -ne '\n' - eqawarn "QA Notice: Excessive files found in the / partition" - eqawarn "${f}" - __vecho -ne '\n' - die "static archives (*.a) and libtool library files (*.la) belong in /usr/lib*, not /lib*" - fi - - # Verify that the libtool files don't contain bogus $D entries. - local abort=no gentoo_bug=no always_overflow=no - for a in "${ED}"usr/lib*/*.la ; do - s=${a##*/} - if grep -qs "${ED}" "${a}" ; then - __vecho -ne '\n' - eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths" - abort="yes" - fi - done - [[ ${abort} == "yes" ]] && die "soiled libtool library files found" - - # Evaluate misc gcc warnings - if [[ -n ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]] ; then - # In debug mode, this variable definition and corresponding grep calls - # will produce false positives if they're shown in the trace. - local reset_debug=0 - if [[ ${-/x/} != $- ]] ; then - set +x - reset_debug=1 - fi - local m msgs=( - ": warning: dereferencing type-punned pointer will break strict-aliasing rules" - ": warning: dereferencing pointer .* does break strict-aliasing rules" - ": warning: implicit declaration of function" - ": warning: incompatible implicit declaration of built-in function" - ": warning: is used uninitialized in this function" # we'll ignore "may" and "might" - ": warning: comparisons like X<=Y<=Z do not have their mathematical meaning" - ": warning: null argument where non-null required" - ": warning: array subscript is below array bounds" - ": warning: array subscript is above array bounds" - ": warning: attempt to free a non-heap object" - ": warning: .* called with .*bigger.* than .* destination buffer" - ": warning: call to .* will always overflow destination buffer" - ": warning: assuming pointer wraparound does not occur when comparing" - ": warning: hex escape sequence out of range" - ": warning: [^ ]*-hand operand of comma .*has no effect" - ": warning: converting to non-pointer type .* from NULL" - ": warning: NULL used in arithmetic" - ": warning: passing NULL to non-pointer argument" - ": warning: the address of [^ ]* will always evaluate as" - ": warning: the address of [^ ]* will never be NULL" - ": warning: too few arguments for format" - ": warning: reference to local variable .* returned" - ": warning: returning reference to temporary" - ": warning: function returns address of local variable" - ": warning: .*\\[-Wsizeof-pointer-memaccess\\]" - ": warning: .*\\[-Waggressive-loop-optimizations\\]" - # this may be valid code :/ - #": warning: multi-character character constant" - # need to check these two ... - #": warning: assuming signed overflow does not occur when" - #": warning: comparison with string literal results in unspecified behav" - # yacc/lex likes to trigger this one - #": warning: extra tokens at end of .* directive" - # only gcc itself triggers this ? - #": warning: .*noreturn.* function does return" - # these throw false positives when 0 is used instead of NULL - #": warning: missing sentinel in function call" - #": warning: not enough variable arguments to fit a sentinel" - ) - abort="no" - i=0 - local grep_cmd=grep - [[ $PORTAGE_LOG_FILE = *.gz ]] && grep_cmd=zgrep - while [[ -n ${msgs[${i}]} ]] ; do - m=${msgs[$((i++))]} - # force C locale to work around slow unicode locales #160234 - f=$(LC_ALL=C $grep_cmd "${m}" "${PORTAGE_LOG_FILE}") - if [[ -n ${f} ]] ; then - abort="yes" - # for now, don't make this fatal (see bug #337031) - #case "$m" in - # ": warning: call to .* will always overflow destination buffer") always_overflow=yes ;; - #esac - if [[ $always_overflow = yes ]] ; then - eerror - eerror "QA Notice: Package triggers severe warnings which indicate that it" - eerror " may exhibit random runtime failures." - eerror - eerror "${f}" - eerror - eerror " Please file a bug about this at http://bugs.gentoo.org/" - eerror " with the maintaining herd of the package." - eerror - else - __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' - fi - fi - done - local cat_cmd=cat - [[ $PORTAGE_LOG_FILE = *.gz ]] && cat_cmd=zcat - [[ $reset_debug = 1 ]] && set -x - # Use safe cwd, avoiding unsafe import for bug #469338. - f=$(cd "${PORTAGE_PYM_PATH}" ; $cat_cmd "${PORTAGE_LOG_FILE}" | \ - "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py || die "check-implicit-pointer-usage.py failed") - if [[ -n ${f} ]] ; then - - # In the future this will be a forced "die". In preparation, - # increase the log level from "qa" to "eerror" so that people - # are aware this is a problem that must be fixed asap. - - # just warn on 32bit hosts but bail on 64bit hosts - case ${CHOST} in - alpha*|hppa64*|ia64*|powerpc64*|mips64*|sparc64*|sparcv9*|x86_64*) gentoo_bug=yes ;; - esac - - abort=yes - - if [[ $gentoo_bug = yes ]] ; then - eerror - eerror "QA Notice: Package triggers severe warnings which indicate that it" - eerror " will almost certainly crash on 64bit architectures." - eerror - eerror "${f}" - eerror - eerror " Please file a bug about this at http://bugs.gentoo.org/" - eerror " with the maintaining herd of the package." - eerror - else - __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' - fi - - fi - if [[ ${abort} == "yes" ]] ; then - if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then - 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}" - has stricter ${FEATURES} && \ - die "install aborted due to severe warnings shown above" - fi - fi - fi - # Portage regenerates this on the installed system. rm -f "${ED}"/usr/share/info/dir{,.gz,.bz2} || die "rm failed!" - - if has multilib-strict ${FEATURES} && \ - [[ -x ${EPREFIX}/usr/bin/file && -x ${EPREFIX}/usr/bin/find ]] && \ - [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]] - then - rm -f "${T}/multilib-strict.log" - local abort=no dir file - MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g') - for dir in ${MULTILIB_STRICT_DIRS} ; 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 - echo "${file#${ED}//}" >> "${T}/multilib-strict.log" - fi - done - done - - if [[ -s ${T}/multilib-strict.log ]] ; then - if [[ ${#QA_MULTILIB_PATHS[@]} -eq 1 ]] ; then - local shopts=$- - set -o noglob - QA_MULTILIB_PATHS=(${QA_MULTILIB_PATHS}) - set +o noglob - set -${shopts} - fi - if [ "${QA_STRICT_MULTILIB_PATHS-unset}" = unset ] ; then - for x in "${QA_MULTILIB_PATHS[@]}" ; do - sed -e "s#^${x#/}\$##" -i "${T}/multilib-strict.log" - done - sed -e "/^\$/d" -i "${T}/multilib-strict.log" - fi - if [[ -s ${T}/multilib-strict.log ]] ; then - abort=yes - echo "Files matching a file type that is not allowed:" - while read -r ; do - echo " ${REPLY}" - done < "${T}/multilib-strict.log" - fi - fi - - [[ ${abort} == yes ]] && die "multilib-strict check failed!" - 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 - - # 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 or an init - # script? - if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${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_qa_check_macho() { diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh index 042fab53e..2dece5ada 100644 --- a/bin/phase-functions.sh +++ b/bin/phase-functions.sh @@ -382,6 +382,19 @@ __dyn_prepare() { trap - SIGINT SIGQUIT } +# @FUNCTION: __start_distcc +# @DESCRIPTION: +# Start distcc-pump if necessary. +__start_distcc() { + if has distcc $FEATURES && has distcc-pump $FEATURES ; then + if [[ -z $INCLUDE_SERVER_PORT ]] || [[ ! -w $INCLUDE_SERVER_PORT ]] ; then + # adding distcc to PATH repeatedly results in fatal distcc recursion :) + eval $(pump --startup | grep -v PATH) + trap "pump --shutdown >/dev/null" EXIT + fi + fi +} + __dyn_configure() { if [[ -e $PORTAGE_BUILDDIR/.configured ]] ; then @@ -401,6 +414,7 @@ __dyn_configure() { fi trap __abort_configure SIGINT SIGQUIT + __start_distcc __ebuild_phase pre_src_configure @@ -434,13 +448,7 @@ __dyn_compile() { fi trap __abort_compile SIGINT SIGQUIT - - if has distcc $FEATURES && has distcc-pump $FEATURES ; then - if [[ -z $INCLUDE_SERVER_PORT ]] || [[ ! -w $INCLUDE_SERVER_PORT ]] ; then - eval $(pump --startup) - trap "pump --shutdown" EXIT - fi - fi + __start_distcc __ebuild_phase pre_src_compile @@ -464,6 +472,8 @@ __dyn_test() { fi trap "__abort_test" SIGINT SIGQUIT + __start_distcc + if [ -d "${S}" ]; then cd "${S}" else @@ -489,7 +499,11 @@ __dyn_test() { local save_sp=${SANDBOX_PREDICT} addpredict / __ebuild_phase pre_src_test + + __vecho ">>> Test phase: ${CATEGORY}/${PF}" __ebuild_phase src_test + __vecho ">>> Completed testing ${CATEGORY}/${PF}" + >> "$PORTAGE_BUILDDIR/.tested" || \ die "Failed to create $PORTAGE_BUILDDIR/.tested" __ebuild_phase post_src_test @@ -509,6 +523,8 @@ __dyn_install() { return 0 fi trap "__abort_install" SIGINT SIGQUIT + __start_distcc + __ebuild_phase pre_src_install if ___eapi_has_prefix_variables; then @@ -735,91 +751,84 @@ __ebuild_phase_funcs() { [ $# -ne 2 ] && die "expected exactly 2 args, got $#: $*" local eapi=$1 local phase_func=$2 - local default_phases="pkg_nofetch src_unpack src_prepare src_configure - src_compile src_install src_test" - local x y default_func="" - - for x in pkg_nofetch src_unpack src_test ; do - declare -F $x >/dev/null || \ - eval "$x() { __eapi0_$x \"\$@\" ; }" + local all_phases="src_compile pkg_config src_configure pkg_info + src_install pkg_nofetch pkg_postinst pkg_postrm pkg_preinst + src_prepare pkg_prerm pkg_pretend pkg_setup src_test src_unpack" + local x + + # First, set up the error handlers for default* + for x in ${all_phases} ; do + eval "default_${x}() { + die \"default_${x}() is not supported in EAPI='${eapi}' in phase ${phase_func}\" + }" done + # We can just call the specific handler -- it will either error out + # on invalid phase or run it. + eval "default() { + default_${phase_func} + }" + case "$eapi" in + 0|1) # EAPIs not supporting 'default' - 0|1) + for x in pkg_nofetch src_unpack src_test ; do + declare -F $x >/dev/null || \ + eval "$x() { __eapi0_$x; }" + done if ! declare -F src_compile >/dev/null ; then case "$eapi" in 0) - src_compile() { __eapi0_src_compile "$@" ; } + src_compile() { __eapi0_src_compile; } ;; *) - src_compile() { __eapi1_src_compile "$@" ; } + src_compile() { __eapi1_src_compile; } ;; esac fi - - for x in $default_phases ; do - eval "default_$x() { - die \"default_$x() is not supported with EAPI='$eapi' during phase $phase_func\" - }" - done - - eval "default() { - die \"default() is not supported with EAPI='$eapi' during phase $phase_func\" - }" - ;; - *) - + *) # EAPIs supporting 'default' + + # defaults starting with EAPI 0 + [[ ${phase_func} == pkg_nofetch ]] && \ + default_pkg_nofetch() { __eapi0_pkg_nofetch; } + [[ ${phase_func} == src_unpack ]] && \ + default_src_unpack() { __eapi0_src_unpack; } + [[ ${phase_func} == src_test ]] && \ + default_src_test() { __eapi0_src_test; } + + # defaults starting with EAPI 2 + [[ ${phase_func} == src_prepare ]] && \ + default_src_prepare() { __eapi2_src_prepare; } + [[ ${phase_func} == src_configure ]] && \ + default_src_configure() { __eapi2_src_configure; } + [[ ${phase_func} == src_compile ]] && \ + default_src_compile() { __eapi2_src_compile; } + + # bind supported phases to the defaults + declare -F pkg_nofetch >/dev/null || \ + pkg_nofetch() { default; } + declare -F src_unpack >/dev/null || \ + src_unpack() { default; } + declare -F src_prepare >/dev/null || \ + src_prepare() { default; } declare -F src_configure >/dev/null || \ - src_configure() { __eapi2_src_configure "$@" ; } - + src_configure() { default; } declare -F src_compile >/dev/null || \ - src_compile() { __eapi2_src_compile "$@" ; } - - has $eapi 2 3 || declare -F src_install >/dev/null || \ - src_install() { __eapi4_src_install "$@" ; } - - if has $phase_func $default_phases ; then - - __eapi2_pkg_nofetch () { __eapi0_pkg_nofetch "$@" ; } - __eapi2_src_unpack () { __eapi0_src_unpack "$@" ; } - __eapi2_src_prepare () { true ; } - __eapi2_src_test () { __eapi0_src_test "$@" ; } - __eapi2_src_install () { die "$FUNCNAME is not supported" ; } - - for x in $default_phases ; do - eval "default_$x() { __eapi2_$x \"\$@\" ; }" - done - - eval "default() { __eapi2_$phase_func \"\$@\" ; }" + src_compile() { default; } + declare -F src_test >/dev/null || \ + src_test() { default; } - case "$eapi" in - 2|3) - ;; - *) - eval "default_src_install() { __eapi4_src_install \"\$@\" ; }" - [[ $phase_func = src_install ]] && \ - eval "default() { __eapi4_$phase_func \"\$@\" ; }" - ;; - esac - - else - - for x in $default_phases ; do - eval "default_$x() { - die \"default_$x() is not supported in phase $default_func\" - }" - done - - eval "default() { - die \"default() is not supported with EAPI='$eapi' during phase $phase_func\" - }" + # defaults starting with EAPI 4 + if ! has ${eapi} 2 3; then + [[ ${phase_func} == src_install ]] && \ + default_src_install() { __eapi4_src_install; } + declare -F src_install >/dev/null || \ + src_install() { default; } fi - ;; esac } diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh index d2f78aa62..0ef083d32 100644 --- a/bin/phase-helpers.sh +++ b/bin/phase-helpers.sh @@ -521,23 +521,20 @@ econf() { done fi + local conf_args=() if ___eapi_econf_passes_--disable-dependency-tracking || ___eapi_econf_passes_--disable-silent-rules; then local conf_help=$("${ECONF_SOURCE}/configure" --help 2>/dev/null) if ___eapi_econf_passes_--disable-dependency-tracking; then - case "${conf_help}" in - *--disable-dependency-tracking*) - set -- --disable-dependency-tracking "$@" - ;; - esac + if [[ ${conf_help} == *--disable-dependency-tracking* ]]; then + conf_args+=( --disable-dependency-tracking ) + fi fi if ___eapi_econf_passes_--disable-silent-rules; then - case "${conf_help}" in - *--disable-silent-rules*) - set -- --disable-silent-rules "$@" - ;; - esac + if [[ ${conf_help} == *--disable-silent-rules* ]]; then + conf_args+=( --disable-silent-rules ) + fi fi fi @@ -554,7 +551,9 @@ econf() { CONF_PREFIX=${CONF_PREFIX#*=} [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX="/${CONF_PREFIX}" [[ ${CONF_LIBDIR} != /* ]] && CONF_LIBDIR="/${CONF_LIBDIR}" - set -- --libdir="$(__strip_duplicate_slashes "${CONF_PREFIX}${CONF_LIBDIR}")" "$@" + conf_args+=( + --libdir="$(__strip_duplicate_slashes "${CONF_PREFIX}${CONF_LIBDIR}")" + ) fi # Handle arguments containing quoted whitespace (see bug #457136). @@ -570,6 +569,7 @@ econf() { --datadir="${EPREFIX}"/usr/share \ --sysconfdir="${EPREFIX}"/etc \ --localstatedir="${EPREFIX}"/var/lib \ + "${conf_args[@]}" \ "$@" \ "${EXTRA_ECONF[@]}" __vecho "${ECONF_SOURCE}/configure" "$@" @@ -617,8 +617,8 @@ einstall() { mandir="${ED}usr/share/man" \ sysconfdir="${ED}etc" \ ${LOCAL_EXTRA_EINSTALL} \ - ${MAKEOPTS} ${EXTRA_EMAKE} -j1 \ - "$@" install + ${MAKEOPTS} -j1 \ + "$@" ${EXTRA_EMAKE} install fi ${MAKE:-make} prefix="${ED}usr" \ datadir="${ED}usr/share" \ @@ -627,8 +627,8 @@ einstall() { mandir="${ED}usr/share/man" \ sysconfdir="${ED}etc" \ ${LOCAL_EXTRA_EINSTALL} \ - ${MAKEOPTS} ${EXTRA_EMAKE} -j1 \ - "$@" install || die "einstall failed" + ${MAKEOPTS} -j1 \ + "$@" ${EXTRA_EMAKE} install || die "einstall failed" else die "no Makefile found" fi @@ -667,15 +667,13 @@ __eapi0_src_test() { internal_opts+=" -j1" fi if $emake_cmd ${internal_opts} check -n &> /dev/null; then - __vecho ">>> Test phase [check]: ${CATEGORY}/${PF}" + __vecho "${emake_cmd} ${internal_opts} check" >&2 $emake_cmd ${internal_opts} check || \ die "Make check failed. See above for details." elif $emake_cmd ${internal_opts} test -n &> /dev/null; then - __vecho ">>> Test phase [test]: ${CATEGORY}/${PF}" + __vecho "${emake_cmd} ${internal_opts} test" >&2 $emake_cmd ${internal_opts} test || \ die "Make test failed. See above for details." - else - __vecho ">>> Test phase [none]: ${CATEGORY}/${PF}" fi } @@ -684,6 +682,10 @@ __eapi1_src_compile() { __eapi2_src_compile } +__eapi2_src_prepare() { + : +} + __eapi2_src_configure() { if [[ -x ${ECONF_SOURCE:-.}/configure ]] ; then econf diff --git a/bin/portageq b/bin/portageq index ea9dfde24..7b9e17739 100755 --- a/bin/portageq +++ b/bin/portageq @@ -29,16 +29,16 @@ if os.environ.__contains__("PORTAGE_PYTHONPATH"): else: pym_path = os.path.join(os.path.dirname( os.path.dirname(os.path.realpath(__file__))), "pym") -# Avoid sandbox violations after python upgrade. +# Avoid sandbox violations after Python upgrade. if os.environ.get("SANDBOX_ON") == "1": sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":") - if pym_path not in sandbox_write: - sandbox_write.append(pym_path) - os.environ["SANDBOX_WRITE"] = \ - ":".join(filter(None, sandbox_write)) - del sandbox_write + for pym_path in pym_paths: + if pym_path not in sandbox_write: + sandbox_write.append(pym_path) + os.environ["SANDBOX_WRITE"] = ":".join(filter(None, sandbox_write)) + del pym_path, sandbox_write +del pym_paths -sys.path.insert(0, pym_path) import portage portage._internal_caller = True from portage import os @@ -66,6 +66,10 @@ def uses_eroot(function): function.uses_eroot = True return function +# global to hold all function docstrings to be used for argparse help. +# Avoids python compilation level 2 optimization troubles. +docstrings = {} + #----------------------------------------------------------------------------- # # To add functionality to this tool, add a function below. @@ -73,10 +77,12 @@ def uses_eroot(function): # The format for functions is: # # def function(argv): -# """<list of options for this function> +# <code> +# +# docstrings['function'] = """<list of options for this function> # <description of the function> # """ -# <code> +# function.__doc__ = docstrings['function'] # # "argv" is an array of the command line parameters provided after the command. # @@ -89,9 +95,6 @@ def uses_eroot(function): @uses_eroot def has_version(argv): - """<eroot> <category/package> - Return code 0 if it's available, 1 otherwise. - """ if (len(argv) < 2): print("ERROR: insufficient parameters!") return 3 @@ -132,12 +135,14 @@ def has_version(argv): noiselevel=-1) return 2 +docstrings['has_version'] = """<eroot> <category/package> + Return code 0 if it's available, 1 otherwise. + """ +has_version.__doc__ = docstrings['has_version'] + @uses_eroot def best_version(argv): - """<eroot> <category/package> - Returns category/package-version (without .ebuild). - """ if (len(argv) < 2): print("ERROR: insufficient parameters!") return 3 @@ -171,12 +176,14 @@ def best_version(argv): except KeyError: return 1 +docstrings['best_version'] = """<eroot> <category/package> + Returns category/package-version (without .ebuild). + """ +best_version.__doc__ = docstrings['best_version'] + @uses_eroot def mass_best_version(argv): - """<eroot> [<category/package>]+ - Returns category/package-version (without .ebuild). - """ if (len(argv) < 2): print("ERROR: insufficient parameters!") return 2 @@ -187,6 +194,11 @@ def mass_best_version(argv): except KeyError: return 1 +docstrings['mass_best_version'] = """<eroot> [<category/package>]+ + Returns category/package-version (without .ebuild). + """ +mass_best_version.__doc__ = docstrings['mass_best_version'] + @uses_eroot def metadata(argv): @@ -215,21 +227,17 @@ def metadata(argv): print("Package not found: '%s'" % pkgspec, file=sys.stderr) return 1 -metadata.__doc__ = """ +docstrings['metadata'] = """ <eroot> <pkgtype> <category/package> [<key>]+ Returns metadata values for the specified package. Available keys: %s """ % ','.join(sorted(x for x in portage.auxdbkeys \ if not x.startswith('UNUSED_'))) +metadata.__doc__ = docstrings['metadata'] @uses_eroot def contents(argv): - """<eroot> <category/package> - List the files that are installed for a given package, with - one file listed on each line. All file names will begin with - <eroot>. - """ if len(argv) != 2: print("ERROR: expected 2 parameters, got %d!" % len(argv)) return 2 @@ -245,16 +253,16 @@ def contents(argv): writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())), noiselevel=-1) +docstrings['contents'] = """<eroot> <category/package> + List the files that are installed for a given package, with + one file listed on each line. All file names will begin with + <eroot>. + """ +contents.__doc__ = docstrings['contents'] + @uses_eroot def owners(argv): - """<eroot> [<filename>]+ - Given a list of files, print the packages that own the files and which - files belong to each package. Files owned by a package are listed on - the lines below it, indented by a single tab character (\\t). All file - paths must either start with <eroot> or be a basename alone. - Returns 1 if no owners could be found, and 0 otherwise. - """ if len(argv) < 2: sys.stderr.write("ERROR: insufficient parameters!\n") sys.stderr.flush() @@ -325,13 +333,18 @@ def owners(argv): return 0 return 1 +docstrings['owners'] = """<eroot> [<filename>]+ + Given a list of files, print the packages that own the files and which + files belong to each package. Files owned by a package are listed on + the lines below it, indented by a single tab character (\\t). All file + paths must either start with <eroot> or be a basename alone. + Returns 1 if no owners could be found, and 0 otherwise. + """ +owners.__doc__ = docstrings['owners'] + @uses_eroot def is_protected(argv): - """<eroot> <filename> - Given a single filename, return code 0 if it's protected, 1 otherwise. - The filename must begin with <eroot>. - """ if len(argv) != 2: sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv)) sys.stderr.flush() @@ -372,13 +385,15 @@ def is_protected(argv): return 0 return 1 +docstrings['is_protected'] = """<eroot> <filename> + Given a single filename, return code 0 if it's protected, 1 otherwise. + The filename must begin with <eroot>. + """ +is_protected.__doc__ = docstrings['is_protected'] + @uses_eroot def filter_protected(argv): - """<eroot> - Read filenames from stdin and write them to stdout if they are protected. - All filenames are delimited by \\n and must begin with <eroot>. - """ if len(argv) != 1: sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv)) sys.stderr.flush() @@ -430,14 +445,15 @@ def filter_protected(argv): return 0 +docstrings['filter_protected'] = """<eroot> + Read filenames from stdin and write them to stdout if they are protected. + All filenames are delimited by \\n and must begin with <eroot>. + """ +filter_protected.__doc__ = docstrings['filter_protected'] + @uses_eroot def best_visible(argv): - """<eroot> [pkgtype] <atom> - Returns category/package-version (without .ebuild). - The pkgtype argument defaults to "ebuild" if unspecified, - otherwise it must be one of ebuild, binary, or installed. - """ if (len(argv) < 2): writemsg("ERROR: insufficient parameters!\n", noiselevel=-1) return 2 @@ -512,14 +528,16 @@ def best_visible(argv): return 1 - -@uses_eroot -def mass_best_visible(argv): - """<eroot> [<type>] [<category/package>]+ +docstrings['best_visible'] = """<eroot> [pkgtype] <atom> Returns category/package-version (without .ebuild). The pkgtype argument defaults to "ebuild" if unspecified, otherwise it must be one of ebuild, binary, or installed. """ +best_visible.__doc__ = docstrings['best_visible'] + + +@uses_eroot +def mass_best_visible(argv): type_map = { "ebuild":"porttree", "binary":"bintree", @@ -539,12 +557,16 @@ def mass_best_visible(argv): except KeyError: return 1 +docstrings['mass_best_visible'] = """<eroot> [<type>] [<category/package>]+ + Returns category/package-version (without .ebuild). + The pkgtype argument defaults to "ebuild" if unspecified, + otherwise it must be one of ebuild, binary, or installed. + """ +mass_best_visible.__doc__ = docstrings['mass_best_visible'] + @uses_eroot def all_best_visible(argv): - """<eroot> - Returns all best_visible packages (without .ebuild). - """ if len(argv) < 1: sys.stderr.write("ERROR: insufficient parameters!\n") sys.stderr.flush() @@ -556,14 +578,14 @@ def all_best_visible(argv): if mybest: print(mybest) +docstrings['all_best_visible'] = """<eroot> + Returns all best_visible packages (without .ebuild). + """ +all_best_visible.__doc__ = docstrings['all_best_visible'] + @uses_eroot def match(argv): - """<eroot> <atom> - Returns a \\n separated list of category/package-version. - When given an empty string, all installed packages will - be listed. - """ if len(argv) != 2: print("ERROR: expected 2 parameters, got %d!" % len(argv)) return 2 @@ -605,20 +627,16 @@ def match(argv): for cpv in results: print(cpv) +docstrings['match'] = """<eroot> <atom> + Returns a \\n separated list of category/package-version. + When given an empty string, all installed packages will + be listed. + """ +match.__doc__ = docstrings['match'] + @uses_eroot def expand_virtual(argv): - """<eroot> <atom> - Returns a \\n separated list of atoms expanded from a - given virtual atom (GLEP 37 virtuals only), - excluding blocker atoms. Satisfied - virtual atoms are not included in the output, since - they are expanded to real atoms which are displayed. - Unsatisfied virtual atoms are displayed without - any expansion. The "match" command can be used to - resolve the returned atoms to specific installed - packages. - """ if len(argv) != 2: writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv), noiselevel=-1) @@ -641,101 +659,134 @@ def expand_virtual(argv): return os.EX_OK +docstrings['expand_virtual'] = """<eroot> <atom> + Returns a \\n separated list of atoms expanded from a + given virtual atom (GLEP 37 virtuals only), + excluding blocker atoms. Satisfied + virtual atoms are not included in the output, since + they are expanded to real atoms which are displayed. + Unsatisfied virtual atoms are displayed without + any expansion. The "match" command can be used to + resolve the returned atoms to specific installed + packages. + """ +expand_virtual.__doc__ = docstrings['expand_virtual'] + def vdb_path(_argv): - """ - Returns the path used for the var(installed) package database for the - set environment/configuration options. - """ out = sys.stdout out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n") out.flush() return os.EX_OK -def gentoo_mirrors(_argv): +docstrings['vdb_path'] = """ + Returns the path used for the var(installed) package database for the + set environment/configuration options. """ +vdb_path.__doc__ = docstrings['vdb_path'] + + +def gentoo_mirrors(_argv): + print(portage.settings["GENTOO_MIRRORS"]) + +docstrings['gentoo_mirrors'] = """ Returns the mirrors set to use in the portage configuration. """ - print(portage.settings["GENTOO_MIRRORS"]) +gentoo_mirrors.__doc__ = docstrings['gentoo_mirrors'] @uses_eroot def repositories_configuration(argv): - """<eroot> - Returns the configuration of repositories. - """ if len(argv) < 1: print("ERROR: insufficient parameters!", file=sys.stderr) return 3 sys.stdout.write(portage.db[argv[0]]["vartree"].settings.repositories.config_string()) sys.stdout.flush() +docstrings['repositories_configuration'] = """<eroot> + Returns the configuration of repositories. + """ +repositories_configuration.__doc__ = docstrings['repositories_configuration'] + + @uses_eroot def repos_config(argv): - """ + return repositories_configuration(argv) + +docstrings['repos_config'] = """ <eroot> This is an alias for the repositories_configuration command. """ - return repositories_configuration(argv) +repos_config.__doc__ = docstrings['repos_config'] + def portdir(_argv): - """ + print("WARNING: 'portageq portdir' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr) + print(portage.settings["PORTDIR"]) + +docstrings['portdir'] = """ Returns the PORTDIR path. Deprecated in favor of repositories_configuration command. """ - print("WARNING: 'portageq portdir' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr) - print(portage.settings["PORTDIR"]) +portdir.__doc__ = docstrings['portdir'] def config_protect(_argv): - """ + print(portage.settings["CONFIG_PROTECT"]) + +docstrings['config_protect'] = """ Returns the CONFIG_PROTECT paths. """ - print(portage.settings["CONFIG_PROTECT"]) +config_protect.__doc__ = docstrings['config_protect'] def config_protect_mask(_argv): - """ - Returns the CONFIG_PROTECT_MASK paths. - """ print(portage.settings["CONFIG_PROTECT_MASK"]) +docstrings['config_protect_mask'] = """ + Returns the CONFIG_PROTECT_MASK paths. + """ +config_protect_mask.__doc__ = docstrings['config_protect_mask'] def portdir_overlay(_argv): - """ + print("WARNING: 'portageq portdir_overlay' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr) + print(portage.settings["PORTDIR_OVERLAY"]) + +docstrings['portdir_overlay'] = """ Returns the PORTDIR_OVERLAY path. Deprecated in favor of repositories_configuration command. """ - print("WARNING: 'portageq portdir_overlay' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr) - print(portage.settings["PORTDIR_OVERLAY"]) +portdir_overlay.__doc__ = docstrings['portdir_overlay'] def pkgdir(_argv): - """ + print(portage.settings["PKGDIR"]) + +docstrings['pkgdir'] = """ Returns the PKGDIR path. """ - print(portage.settings["PKGDIR"]) +pkgdir.__doc__ = docstrings['pkgdir'] def distdir(_argv): - """ + print(portage.settings["DISTDIR"]) + +docstrings['distdir'] = """ Returns the DISTDIR path. """ - print(portage.settings["DISTDIR"]) +distdir.__doc__ = docstrings['distdir'] def colormap(_argv): - """ + print(portage.output.colormap()) + +docstrings['colormap'] = """ Display the color.map as environment variables. """ - print(portage.output.colormap()) +colormap.__doc__ = docstrings['colormap'] def envvar(argv): - """<variable>+ - Returns a specific environment variable as exists prior to ebuild.sh. - Similar to: emerge --verbose --info | egrep '^<variable>=' - """ verbose = "-v" in argv if verbose: argv.pop(argv.index("-v")) @@ -752,23 +803,28 @@ def envvar(argv): else: print(portage.settings[arg]) +docstrings['envvar'] = """<variable>+ + Returns a specific environment variable as exists prior to ebuild.sh. + Similar to: emerge --verbose --info | egrep '^<variable>=' + """ +envvar.__doc__ = docstrings['envvar'] + @uses_eroot def get_repos(argv): - """<eroot> - Returns all repos with names (repo_name file) argv[0] = $EROOT - """ if len(argv) < 1: print("ERROR: insufficient parameters!") return 2 print(" ".join(reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order))) +docstrings['get_repos'] = """<eroot> + Returns all repos with names (repo_name file) argv[0] = $EROOT + """ +get_repos.__doc__ = docstrings['get_repos'] + @uses_eroot def master_repositories(argv): - """<eroot> <repo_id>+ - Returns space-separated list of master repositories for specified repository. - """ if len(argv) < 2: print("ERROR: insufficient parameters!", file=sys.stderr) return 3 @@ -784,18 +840,25 @@ def master_repositories(argv): else: print(" ".join(x.name for x in repo.masters)) +docstrings['master_repositories'] = """<eroot> <repo_id>+ + Returns space-separated list of master repositories for specified repository. + """ +master_repositories.__doc__ = docstrings['master_repositories'] + + @uses_eroot def master_repos(argv): - """<eroot> <repo_id>+ + return master_repositories(argv) + +docstrings['master_repos'] = """<eroot> <repo_id>+ This is an alias for the master_repositories command. """ - return master_repositories(argv) +master_repos.__doc__ = docstrings['master_repos'] + @uses_eroot def get_repo_path(argv): - """<eroot> <repo_id>+ - Returns the path to the repo named argv[1], argv[0] = $EROOT - """ + if len(argv) < 2: print("ERROR: insufficient parameters!", file=sys.stderr) return 3 @@ -809,12 +872,14 @@ def get_repo_path(argv): return 1 print(path) +docstrings['get_repo_path'] = """<eroot> <repo_id>+ + Returns the path to the repo named argv[1], argv[0] = $EROOT + """ +get_repo_path.__doc__ = docstrings['get_repo_path'] + @uses_eroot def available_eclasses(argv): - """<eroot> <repo_id>+ - Returns space-separated list of available eclasses for specified repository. - """ if len(argv) < 2: print("ERROR: insufficient parameters!", file=sys.stderr) return 3 @@ -830,12 +895,14 @@ def available_eclasses(argv): else: print(" ".join(sorted(repo.eclass_db.eclasses))) +docstrings['available_eclasses'] = """<eroot> <repo_id>+ + Returns space-separated list of available eclasses for specified repository. + """ +available_eclasses.__doc__ = docstrings['available_eclasses'] + @uses_eroot def eclass_path(argv): - """<eroot> <repo_id> <eclass>+ - Returns the path to specified eclass for specified repository. - """ if len(argv) < 3: print("ERROR: insufficient parameters!", file=sys.stderr) return 3 @@ -859,12 +926,14 @@ def eclass_path(argv): print(eclass.location) return retval +docstrings['eclass_path'] = """<eroot> <repo_id> <eclass>+ + Returns the path to specified eclass for specified repository. + """ +eclass_path.__doc__ = docstrings['eclass_path'] + @uses_eroot def license_path(argv): - """<eroot> <repo_id> <license>+ - Returns the path to specified license for specified repository. - """ if len(argv) < 3: print("ERROR: insufficient parameters!", file=sys.stderr) return 3 @@ -890,15 +959,14 @@ def license_path(argv): print(eclass_path) return retval +docstrings['license_path'] = """<eroot> <repo_id> <license>+ + Returns the path to specified license for specified repository. + """ +license_path.__doc__ = docstrings['license_path'] + @uses_eroot def list_preserved_libs(argv): - """<eroot> - Print a list of libraries preserved during a package update in the form - package: path. Returns 1 if no preserved libraries could be found, - 0 otherwise. - """ - if len(argv) != 1: print("ERROR: wrong number of arguments") return 2 @@ -914,6 +982,13 @@ def list_preserved_libs(argv): writemsg_stdout(''.join(msg), noiselevel=-1) return rValue +docstrings['list_preserved_libs'] = """<eroot> + Print a list of libraries preserved during a package update in the form + package: path. Returns 1 if no preserved libraries could be found, + 0 otherwise. + """ +list_preserved_libs.__doc__ = docstrings['list_preserved_libs'] + class MaintainerEmailMatcher(object): def __init__(self, maintainer_emails): @@ -938,10 +1013,6 @@ class HerdMatcher(object): def pquery(parser, opts, args): - """[options] [atom]+ - Emulates a subset of Pkgcore's pquery tool. - """ - portdb = portage.db[portage.root]['porttree'].dbapi root_config = RootConfig(portdb.settings, portage.db[portage.root], None) @@ -1120,6 +1191,11 @@ def pquery(parser, opts, args): return os.EX_OK +docstrings['pquery'] = """[options] [atom]+ + Emulates a subset of Pkgcore's pquery tool. + """ +pquery.__doc__ = docstrings['pquery'] + #----------------------------------------------------------------------------- # @@ -1217,10 +1293,7 @@ def usage(argv): # help_mode = '--help' in argv for name in commands: - # Drop non-functions - obj = globals()[name] - - doc = obj.__doc__ + doc = docstrings.get(name) if (doc == None): print(" " + name) print(" MISSING DOCUMENTATION!") diff --git a/bin/quickpkg b/bin/quickpkg index d787ca1f3..7019fb351 100755 --- a/bin/quickpkg +++ b/bin/quickpkg @@ -2,7 +2,7 @@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -from __future__ import print_function +from __future__ import division, print_function import errno import math @@ -11,8 +11,8 @@ import sys import tarfile from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os @@ -264,7 +264,7 @@ def quickpkg_main(options, args, eout): size_str = "0" else: power_of_2 = math.log(size, 2) - power_of_2 = 10*int(power_of_2/10) + power_of_2 = 10*(power_of_2//10) unit = units.get(power_of_2) if unit: size = float(size)/(2**power_of_2) diff --git a/bin/regenworld b/bin/regenworld index d3fb9ed24..1c7678cd3 100755 --- a/bin/regenworld +++ b/bin/regenworld @@ -6,8 +6,8 @@ from __future__ import print_function import sys from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True from portage import os diff --git a/bin/repoman b/bin/repoman index efab92183..918357747 100755 --- a/bin/repoman +++ b/bin/repoman @@ -32,8 +32,8 @@ except ImportError: from urlparse import urlparse from os import path as osp -pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") -sys.path.insert(0, pym_path) +if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")): + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage portage._internal_caller = True portage._disable_legacy_globals() @@ -62,7 +62,7 @@ from repoman import utilities from repoman.herdbase import make_herd_base from _emerge.Package import Package from _emerge.RootConfig import RootConfig -from _emerge.userquery import userquery +from _emerge.UserQuery import UserQuery import portage.checksum import portage.const import portage.repository.config @@ -299,6 +299,7 @@ qahelp = { "dependency.badindev": "User-visible ebuilds with unsatisfied dependencies (matched against *visible* ebuilds) in developing arch", "dependency.badmaskedindev": "Masked ebuilds with unsatisfied dependencies (matched against *all* ebuilds) in developing arch", "dependency.badtilde": "Uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)", + "dependency.perlcore": "This ebuild directly depends on a package in perl-core; it should use the corresponding virtual instead.", "dependency.syntax": "Syntax error in dependency string (usually an extra/missing space/parenthesis)", "dependency.unknown": "Ebuild has a dependency that refers to an unknown package (which may be valid if it is a blocker for a renamed/removed package, or is an alternative choice provided by an overlay)", "file.executable": "Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do not need the executable bit", @@ -318,7 +319,6 @@ qahelp = { "LICENSE.missing": "Ebuilds that have a missing or empty LICENSE variable", "LICENSE.virtual": "Virtuals that have a non-empty LICENSE variable", "DESCRIPTION.missing": "Ebuilds that have a missing or empty DESCRIPTION variable", - "DESCRIPTION.punctuation": "DESCRIPTION ends with a period character", "DESCRIPTION.toolong": "DESCRIPTION is over %d characters" % max_desc_len, "EAPI.definition": "EAPI definition does not conform to PMS section 7.3.1 (first non-comment, non-blank line)", "EAPI.deprecated": "Ebuilds that use features that are deprecated in the current EAPI", @@ -387,7 +387,7 @@ qawarnings = set(( "dependency.badindev", "dependency.badmaskedindev", "dependency.badtilde", -"DESCRIPTION.punctuation", +"dependency.perlcore", "DESCRIPTION.toolong", "EAPI.deprecated", "HOMEPAGE.virtual", @@ -1895,12 +1895,6 @@ for x in effective_scanlist: stats[myqakey] += 1 fails[myqakey].append(relative_path) - if myaux['DESCRIPTION'][-1:] in ['.']: - stats['DESCRIPTION.punctuation'] += 1 - fails['DESCRIPTION.punctuation'].append( - "%s: DESCRIPTION ends with a '%s' character" - % (relative_path, myaux['DESCRIPTION'][-1:])) - # 14 is the length of DESCRIPTION="" if len(myaux['DESCRIPTION']) > max_desc_len: stats['DESCRIPTION.toolong'] += 1 @@ -2042,16 +2036,16 @@ for x in effective_scanlist: if atom == "||": continue + is_blocker = atom.blocker + # Skip dependency.unknown for blockers, so that we # don't encourage people to remove necessary blockers, # as discussed in bug #382407. - if atom.blocker is None and \ + if not is_blocker and \ not portdb.xmatch("match-all", atom) and \ not atom.cp.startswith("virtual/"): unknown_pkgs.add((mytype, atom.unevaluated_atom)) - is_blocker = atom.blocker - if catdir != "virtual": if not is_blocker and \ atom.cp in suspect_virtual: @@ -2060,6 +2054,13 @@ for x in effective_scanlist: relative_path + ": %s: consider using '%s' instead of '%s'" % (mytype, suspect_virtual[atom.cp], atom)) + if not is_blocker and \ + atom.cp.startswith("perl-core/"): + stats['dependency.perlcore'] += 1 + fails['dependency.perlcore'].append( + relative_path + + ": %s: please use '%s' instead of '%s'" % + (mytype, atom.replace("perl-core/","virtual/perl-"), atom)) if buildtime and \ not is_blocker and \ @@ -2882,7 +2883,8 @@ else: logging.info("myupdates: %s", myupdates) logging.info("myheaders: %s", myheaders) - if options.ask and userquery('Commit changes?', True) != 'Yes': + uq = UserQuery(options) + if options.ask and uq.query('Commit changes?', True) != 'Yes': print("* aborting commit.") sys.exit(128 + signal.SIGINT) diff --git a/bin/save-ebuild-env.sh b/bin/save-ebuild-env.sh index 194e46ea9..b790306d1 100644 --- a/bin/save-ebuild-env.sh +++ b/bin/save-ebuild-env.sh @@ -42,7 +42,7 @@ __save_ebuild_env() { for x in pkg_setup pkg_nofetch src_unpack src_prepare src_configure \ src_compile src_test src_install pkg_preinst pkg_postinst \ - pkg_prerm pkg_postrm ; do + pkg_prerm pkg_postrm pkg_config pkg_info pkg_pretend ; do unset -f default_$x __eapi{0,1,2,3,4}_$x done unset x diff --git a/bin/xattr-helper.py b/bin/xattr-helper.py index fdbed54ac..f84e94340 100755 --- a/bin/xattr-helper.py +++ b/bin/xattr-helper.py @@ -2,7 +2,7 @@ # Copyright 2012-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -"""Dump and restore extended attributes. +doc = """Dump and restore extended attributes. We use formats like that used by getfattr --dump. This is meant for shell helpers to save/restore. If you're looking for a python/portage API, see @@ -10,6 +10,8 @@ portage.util.movefile._copyxattr instead. https://en.wikipedia.org/wiki/Extended_file_attributes """ +__doc__ = doc + import array import os @@ -147,7 +149,7 @@ def restore_xattrs(file_in): def main(argv): - parser = ArgumentParser(description=__doc__) + parser = ArgumentParser(description=doc) parser.add_argument('paths', nargs='*', default=[]) actions = parser.add_argument_group('Actions') |