diff options
134 files changed, 3507 insertions, 259 deletions
diff --git a/.travis.yml b/.travis.yml index 2132c8c87..6d3afa4ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,20 @@ install: script: - printf "[build_ext]\nportage-ext-modules=true" >> setup.cfg + - find . -type f -exec + sed -e "s|@PORTAGE_EPREFIX@||" + -e "s|@PORTAGE_BASE@|${PWD}|" + -e "s|@PORTAGE_MV@|$(type -P mv)|" + -e "s|@PORTAGE_BASH@|$(type -P bash)|" + -e "s|@PREFIX_PORTAGE_PYTHON@|$(type -P python)|" + -e "s|@EXTRA_PATH@|/usr/sbin:/sbin|" + -e "s|@portagegroup@|$(id -gn)|" + -e "s|@portageuser@|$(id -un)|" + -e "s|@rootuser@|$(id -un)|" + -e "s|@rootuid@|$(id -u)|" + -e "s|@rootgid@|$(id -g)|" + -e "s|@sysconfdir@|/etc|" + -i '{}' + - ./setup.py test - ./setup.py install --root=/tmp/install-root - if [[ ${TRAVIS_PYTHON_VERSION/-dev/} == ?.? ]]; then diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..62b0edcbd --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +In addition to the the long list of regular portage contributors, these +folks (in no particular order) have put their hard work into this. + +Kito Dietrich <kito at ???> +Emanuele Giaquinta <emanuele.giaquinta at gmail.com> +Fabian Groffen <grobian at gentoo.org> +Brian Harring <ferringb at gmail.com> +Michael Haubenwallner <haubi at gentoo.org> diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..9bcfa00e7 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +SHELL = @PORTAGE_BASH@ + +SUBDIRS = man bin lib cnf + +AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip + +MAINTAINERCLEANFILES = \ + Makefile.in config.guess config.sub configure ltmain.sh aclocal.m4 @@ -1,3 +1,12 @@ +This is the prefix branch of portage, a branch that deals with portage +setup as packagemanager for a given offset in the filesystem running +with user privileges. + +If you are not looking for something Gentoo Prefix like, then this +is not the right place. + + +======= About Portage ============= diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 000000000..1d9ccf55f --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,83 @@ +dnl acinclude.m4 generated automatically by ac-archive's acinclude 0.5.63 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +dnl ______ ______ + +dnl GENTOO_PATH_PYTHON([minimum-version], [path]) +dnl author: Fabian Groffen <grobian a gentoo.org> +AC_DEFUN([GENTOO_PATH_PYTHON], +[ + AC_PATH_PROG([PREFIX_PORTAGE_PYTHON], [python], no, $2) + + dnl is is there at all? + if test "$PREFIX_PORTAGE_PYTHON" = "no" ; then + AC_MSG_ERROR([no python found in your path]) + fi + + dnl is it the version we want? + ver=`$PREFIX_PORTAGE_PYTHON -c 'import sys; print(sys.version.split(" ")[[0]])'` + AC_MSG_CHECKING([whether $PREFIX_PORTAGE_PYTHON $ver >= $1]) + cmp=`$PREFIX_PORTAGE_PYTHON -c 'import sys; print(sys.version.split(" ")[[0]] >= "$1")'` + if test "$cmp" = "True" ; then + AC_MSG_RESULT([yes]) + else + AC_MSG_ERROR([need at least version $1 of python]) + fi +]) + +dnl GENTOO_PATH_XCU_ID([path]) +dnl author: Fabian Groffen <grobian a gentoo.org> +dnl based on the original work by +dnl Michael Haubenwallner <mhaubi at users dot sourceforge dot net> +AC_DEFUN([GENTOO_PATH_XCU_ID], +[ + AC_PATH_PROG([XCU_ID], [id], no, $1) + + dnl does it support all the bells and whistles we need? + AC_MSG_CHECKING([whether $XCU_ID is good enough]) + for a in '' '-u' '-g' ; do + if ! "$XCU_ID" $a >/dev/null 2>&1 ; then + XCU_ID=no + break + fi + done + if test "$XCU_ID" != "no" ; then + AC_MSG_RESULT([yes]) + else + AC_MSG_ERROR([$XCU_ID doesn't understand $a]) + fi +])dnl + +dnl GENTOO_PATH_GNUPROG([variable], [prog-to-check-for], [path]) +dnl author: Fabian Groffen <grobian a gentoo.org> +AC_DEFUN([GENTOO_PATH_GNUPROG], +[ + AC_PATH_PROG([$1], [$2], no, $3) + + dnl is is there at all? + tool="`eval echo \$$1`" + if test "$tool" = "no" ; then + AC_MSG_ERROR([$1 was not found in your path]) + fi + + dnl is it a GNU version? + AC_MSG_CHECKING([whether $tool is GNU $2]) + ver=`$tool --version 2>/dev/null | head -n 1` + case $ver in + *GNU*) + AC_MSG_RESULT([yes]) + ;; + *) + AC_MSG_ERROR([no]) + ;; + esac +]) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..ec510e01b --- /dev/null +++ b/autogen.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env sh + +die() { + echo "!!! $*" > /dev/stderr + exit -1 +} + +#autoheader || { echo "failed autoheader"; exit 1; }; +aclocal || die "failed aclocal" +[ "`type -t glibtoolize`" = "file" ] && alias libtoolize=glibtoolize +libtoolize --automake -c -f || die "failed libtoolize" +autoconf || die "failed autoconf" +touch ChangeLog +automake -a -c || die "failed automake" + +if [ -x ./test.sh ] ; then + exec ./test.sh "$@" +fi +echo "finished" diff --git a/bin/Makefile.in b/bin/Makefile.in new file mode 100644 index 000000000..afff11dfb --- /dev/null +++ b/bin/Makefile.in @@ -0,0 +1,76 @@ +SHELL = @PORTAGE_BASH@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +sysconfdir = @sysconfdir@ +libdir = @libdir@ + +srcdir = @srcdir@ +top_builddir = @top_builddir@ + +portageuser = @portageuser@ +portagegroup = @portagegroup@ + +PORTAGE_BIN = @PORTAGE_BASE@/bin +LN_S = @LN_S@ +INSTALL = @INSTALL@ +INSTALL_subst = $(top_builddir)/subst-install + +usr_binprogs = \ + ebuild \ + egencache \ + emerge \ + emerge-webrsync \ + emirrordist \ + portageq \ + quickpkg + +usr_sbinprogs = \ + archive-conf \ + dispatch-conf \ + emaint \ + env-update \ + etc-update \ + fixpackages \ + readpecoff \ + regenworld + +all: + +install: + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(PORTAGE_BIN) + ( cd "$(srcdir)" && find . -type d ) | while read f ; do \ + files=( ) ; \ + shopt -s nullglob ; \ + for t in "$(srcdir)/$${f}"/* ; do \ + [[ -d $${t} ]] && continue ; \ + [[ $${t} == */Makefile* ]] && continue ; \ + files=( "$${files[@]}" "$${t}" ) ; \ + done ; \ + $(INSTALL) -d -m 755 \ + -o "$(portageuser)" -g "$(portagegroup)" \ + "$(DESTDIR)$(PORTAGE_BIN)/$${f}" && \ + [[ $${files[0]} ]] || continue ; \ + $(INSTALL_subst) -m 755 \ + -o "$(portageuser)" -g "$(portagegroup)" \ + -t "$(DESTDIR)$(PORTAGE_BIN)/$${f}" \ + "$${files[@]}" ; \ + done + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(prefix)/bin + cd $(DESTDIR)$(prefix)/bin \ + ; for p in $(usr_binprogs) \ + ; do test -f $(DESTDIR)$(PORTAGE_BIN)/$${p} \ + || { echo "$(DESTDIR)$(PORTAGE_BIN)/$${p} does not exist" ; exit 1 ; } \ + ; rm -f $(DESTDIR)$(prefix)/bin/$${p} \ + ; $(LN_S) ../lib/portage/bin/$${p} $${p} || exit 1 \ + ; done + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(prefix)/sbin + cd $(DESTDIR)$(prefix)/sbin \ + ; for p in $(usr_sbinprogs) \ + ; do test -f $(DESTDIR)$(PORTAGE_BIN)/$${p} \ + || { echo "$(DESTDIR)$(PORTAGE_BIN)/$${p} does not exist" ; exit 1 ; } \ + ; rm -f $(DESTDIR)$(prefix)/sbin/$${p} \ + ; $(LN_S) ../lib/portage/bin/$${p} $${p} || exit 1 \ + ; done + +.PHONY: all install diff --git a/bin/archive-conf b/bin/archive-conf index 8341ffe73..6271b833c 100755 --- a/bin/archive-conf +++ b/bin/archive-conf @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/bashrc-functions.sh b/bin/bashrc-functions.sh index cc025467f..f01f5c5d0 100644 --- a/bin/bashrc-functions.sh +++ b/bin/bashrc-functions.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/binhost-snapshot b/bin/binhost-snapshot index d677e7568..41d556831 100755 --- a/bin/binhost-snapshot +++ b/bin/binhost-snapshot @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2010-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/check-implicit-pointer-usage.py b/bin/check-implicit-pointer-usage.py index a49db8107..7921d005d 100755 --- a/bin/check-implicit-pointer-usage.py +++ b/bin/check-implicit-pointer-usage.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Ripped from HP and updated from Debian # Update by Gentoo to support unicode output diff --git a/bin/chmod-lite b/bin/chmod-lite index ffa8d4d23..8c62e2de7 100755 --- a/bin/chmod-lite +++ b/bin/chmod-lite @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -7,4 +7,4 @@ export __PORTAGE_HELPER_CWD=${PWD} # Use safe cwd, avoiding unsafe import for bug #469338. cd "${PORTAGE_PYM_PATH}" || exit 1 PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ - exec "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/chmod-lite.py" "$@" + exec "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" "$PORTAGE_BIN_PATH/chmod-lite.py" "$@" diff --git a/bin/chmod-lite.py b/bin/chmod-lite.py index 177be7eab..b9a4fc9a2 100755 --- a/bin/chmod-lite.py +++ b/bin/chmod-lite.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/chpathtool.py b/bin/chpathtool.py index fbd18b987..b9483b841 100755 --- a/bin/chpathtool.py +++ b/bin/chpathtool.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2011-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/clean_locks b/bin/clean_locks index 94ba4c606..a35b9f73a 100755 --- a/bin/clean_locks +++ b/bin/clean_locks @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/dispatch-conf b/bin/dispatch-conf index 62ab3f6cc..c05215fc3 100755 --- a/bin/dispatch-conf +++ b/bin/dispatch-conf @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/dohtml.py b/bin/dohtml.py index dfcaa6026..f99cd9812 100755 --- a/bin/dohtml.py +++ b/bin/dohtml.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/eapi.sh b/bin/eapi.sh index 29dfb008c..26df37328 100644 --- a/bin/eapi.sh +++ b/bin/eapi.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2012-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild b/bin/ebuild index 460aa0fd1..a57dd4941 100755 --- a/bin/ebuild +++ b/bin/ebuild @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/bsd/sed b/bin/ebuild-helpers/bsd/sed index 8bece09cd..fd8dc2183 100755 --- a/bin/ebuild-helpers/bsd/sed +++ b/bin/ebuild-helpers/bsd/sed @@ -1,10 +1,17 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2007-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 scriptpath=${BASH_SOURCE[0]} scriptname=${scriptpath##*/} +# PREFIX LOCAL: warn about screwups early +if [[ -n ${EPREFIX} ]] ; then + echo "When using Prefix, this BSD sed wrapper should not exist (in ${scriptpath})! This is a bug!" > /dev/stderr + exit 1 +fi +# END PREFIX LOCAL + if [[ sed == ${scriptname} && -n ${ESED} ]]; then exec ${ESED} "$@" elif type -P g${scriptname} > /dev/null ; then diff --git a/bin/ebuild-helpers/die b/bin/ebuild-helpers/die index 5c6b1d2cb..00b67901f 100755 --- a/bin/ebuild-helpers/die +++ b/bin/ebuild-helpers/die @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dobin b/bin/ebuild-helpers/dobin index 975067fb1..0f0518aba 100755 --- a/bin/ebuild-helpers/dobin +++ b/bin/ebuild-helpers/dobin @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doconfd b/bin/ebuild-helpers/doconfd index 15ad980f3..e32c9d5c0 100755 --- a/bin/ebuild-helpers/doconfd +++ b/bin/ebuild-helpers/doconfd @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dodir b/bin/ebuild-helpers/dodir index 9b376c73f..4d309e4b1 100755 --- a/bin/ebuild-helpers/dodir +++ b/bin/ebuild-helpers/dodir @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dodoc b/bin/ebuild-helpers/dodoc index e83091045..9fdb6495a 100755 --- a/bin/ebuild-helpers/dodoc +++ b/bin/ebuild-helpers/dodoc @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doenvd b/bin/ebuild-helpers/doenvd index f14b95104..4e8068659 100755 --- a/bin/ebuild-helpers/doenvd +++ b/bin/ebuild-helpers/doenvd @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doexe b/bin/ebuild-helpers/doexe index 152c13bf6..5fa8f058d 100755 --- a/bin/ebuild-helpers/doexe +++ b/bin/ebuild-helpers/doexe @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dohard b/bin/ebuild-helpers/dohard index 66e2604b0..1dd2eb582 100755 --- a/bin/ebuild-helpers/dohard +++ b/bin/ebuild-helpers/dohard @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doheader b/bin/ebuild-helpers/doheader index aedc2322a..a87536c33 100755 --- a/bin/ebuild-helpers/doheader +++ b/bin/ebuild-helpers/doheader @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dohtml b/bin/ebuild-helpers/dohtml index 49d6a6dfb..a60dbdab8 100755 --- a/bin/ebuild-helpers/dohtml +++ b/bin/ebuild-helpers/dohtml @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2009-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -17,7 +17,7 @@ fi export __PORTAGE_HELPER_CWD=${PWD} cd "${PORTAGE_PYM_PATH}" || die PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/dohtml.py" "$@" + "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" "$PORTAGE_BIN_PATH/dohtml.py" "$@" ret=$? # Restore cwd for display by __helpers_die diff --git a/bin/ebuild-helpers/doinfo b/bin/ebuild-helpers/doinfo index 30a38e055..e261e9e74 100755 --- a/bin/ebuild-helpers/doinfo +++ b/bin/ebuild-helpers/doinfo @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doinitd b/bin/ebuild-helpers/doinitd index a216d9827..883858320 100755 --- a/bin/ebuild-helpers/doinitd +++ b/bin/ebuild-helpers/doinitd @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doins b/bin/ebuild-helpers/doins index 24fe48121..825a421af 100755 --- a/bin/ebuild-helpers/doins +++ b/bin/ebuild-helpers/doins @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 @@ -50,6 +50,15 @@ if [[ ${_E_INSDESTTREE_#${ED}} != "${_E_INSDESTTREE_}" ]]; then __helpers_die "${helper} used with \${D} or \${ED}" exit 1 fi +# PREFIX LOCAL: check for usage with EPREFIX +if [[ ${INSDESTTREE#${EPREFIX}} != "${INSDESTTREE}" ]]; then + __vecho "-------------------------------------------------------" 1>&2 + __vecho "You should not use \${EPREFIX} with helpers." 1>&2 + __vecho " --> ${INSDESTTREE}" 1>&2 + __vecho "-------------------------------------------------------" 1>&2 + exit 1 +fi +# END PREFIX LOCAL if ___eapi_doins_and_newins_preserve_symlinks; then DOINS_ARGS+=( --preserve_symlinks ) diff --git a/bin/ebuild-helpers/dolib b/bin/ebuild-helpers/dolib index bd8eebca7..049088de7 100755 --- a/bin/ebuild-helpers/dolib +++ b/bin/ebuild-helpers/dolib @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dolib.a b/bin/ebuild-helpers/dolib.a index 5ea126b5d..f45aed3e6 100755 --- a/bin/ebuild-helpers/dolib.a +++ b/bin/ebuild-helpers/dolib.a @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dolib.so b/bin/ebuild-helpers/dolib.so index a3b579e5e..2272679c8 100755 --- a/bin/ebuild-helpers/dolib.so +++ b/bin/ebuild-helpers/dolib.so @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/doman b/bin/ebuild-helpers/doman index 9cfc89df0..bfd7356a0 100755 --- a/bin/ebuild-helpers/doman +++ b/bin/ebuild-helpers/doman @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/domo b/bin/ebuild-helpers/domo index 2e95eb751..fb1475470 100755 --- a/bin/ebuild-helpers/domo +++ b/bin/ebuild-helpers/domo @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dosbin b/bin/ebuild-helpers/dosbin index ac0ab37ca..e92286088 100755 --- a/bin/ebuild-helpers/dosbin +++ b/bin/ebuild-helpers/dosbin @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dosed b/bin/ebuild-helpers/dosed index 37c8a29d3..44752f54e 100755 --- a/bin/ebuild-helpers/dosed +++ b/bin/ebuild-helpers/dosed @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/dosym b/bin/ebuild-helpers/dosym index abd4da4f0..681e198c5 100755 --- a/bin/ebuild-helpers/dosym +++ b/bin/ebuild-helpers/dosym @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2020 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/elog b/bin/ebuild-helpers/elog index 911f8d57f..f57fce4bd 100755 --- a/bin/ebuild-helpers/elog +++ b/bin/ebuild-helpers/elog @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2009 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/emake b/bin/ebuild-helpers/emake index 60718a2e4..cca9cb63b 100755 --- a/bin/ebuild-helpers/emake +++ b/bin/ebuild-helpers/emake @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # @@ -12,7 +12,7 @@ source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1 cmd=( - ${MAKE:-make} ${MAKEOPTS} "$@" ${EXTRA_EMAKE} + ${MAKE:-make} SHELL="${BASH:-/bin/bash}" ${MAKEOPTS} "$@" ${EXTRA_EMAKE} ) if [[ ${PORTAGE_QUIET} != 1 ]] ; then diff --git a/bin/ebuild-helpers/fowners b/bin/ebuild-helpers/fowners index 0eda73e58..01a89dc1e 100755 --- a/bin/ebuild-helpers/fowners +++ b/bin/ebuild-helpers/fowners @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/fperms b/bin/ebuild-helpers/fperms index f98560039..9780e6ca8 100755 --- a/bin/ebuild-helpers/fperms +++ b/bin/ebuild-helpers/fperms @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/keepdir b/bin/ebuild-helpers/keepdir index a3c0c151c..9b8986a5e 100755 --- a/bin/ebuild-helpers/keepdir +++ b/bin/ebuild-helpers/keepdir @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/newins b/bin/ebuild-helpers/newins index 30e54b7e5..9b31a2ccf 100755 --- a/bin/ebuild-helpers/newins +++ b/bin/ebuild-helpers/newins @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/portageq b/bin/ebuild-helpers/portageq index d31bd6810..47640c5a8 100755 --- a/bin/ebuild-helpers/portageq +++ b/bin/ebuild-helpers/portageq @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2009-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -16,7 +16,7 @@ for path in ${PATH}; do [[ ${path} == */portage/*/ebuild-helpers* ]] && continue [[ ${path}/${scriptname} -ef ${scriptpath} ]] && continue PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ - exec "${PORTAGE_PYTHON:-/usr/bin/python}" \ + exec "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" \ "${path}/${scriptname}" "$@" done diff --git a/bin/ebuild-helpers/prepall b/bin/ebuild-helpers/prepall index e23a6d410..0251e7948 100755 --- a/bin/ebuild-helpers/prepall +++ b/bin/ebuild-helpers/prepall @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepalldocs b/bin/ebuild-helpers/prepalldocs index e23a6d410..0251e7948 100755 --- a/bin/ebuild-helpers/prepalldocs +++ b/bin/ebuild-helpers/prepalldocs @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepallinfo b/bin/ebuild-helpers/prepallinfo index e23a6d410..0251e7948 100755 --- a/bin/ebuild-helpers/prepallinfo +++ b/bin/ebuild-helpers/prepallinfo @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepallman b/bin/ebuild-helpers/prepallman index e23a6d410..0251e7948 100755 --- a/bin/ebuild-helpers/prepallman +++ b/bin/ebuild-helpers/prepallman @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepallstrip b/bin/ebuild-helpers/prepallstrip index 4bde1f4b2..40764fc30 100755 --- a/bin/ebuild-helpers/prepallstrip +++ b/bin/ebuild-helpers/prepallstrip @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepinfo b/bin/ebuild-helpers/prepinfo index 9d33e6e9a..e448ac926 100755 --- a/bin/ebuild-helpers/prepinfo +++ b/bin/ebuild-helpers/prepinfo @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepman b/bin/ebuild-helpers/prepman index 4c6d47bb2..6fab36e0b 100755 --- a/bin/ebuild-helpers/prepman +++ b/bin/ebuild-helpers/prepman @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip index ecbea47ec..4a899ee1a 100755 --- a/bin/ebuild-helpers/prepstrip +++ b/bin/ebuild-helpers/prepstrip @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/unprivileged/chown b/bin/ebuild-helpers/unprivileged/chown index a7a4ff447..54174cc6c 100755 --- a/bin/ebuild-helpers/unprivileged/chown +++ b/bin/ebuild-helpers/unprivileged/chown @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2012-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-helpers/xattr/install b/bin/ebuild-helpers/xattr/install index e5bb10895..b1719bcaf 100755 --- a/bin/ebuild-helpers/xattr/install +++ b/bin/ebuild-helpers/xattr/install @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2013-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/ebuild-ipc b/bin/ebuild-ipc index e77b94b2c..739564d15 100755 --- a/bin/ebuild-ipc +++ b/bin/ebuild-ipc @@ -1,8 +1,8 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 2010-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # Use safe cwd, avoiding unsafe import for bug #469338. cd "${PORTAGE_PYM_PATH}" || exit 1 PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ - exec "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/ebuild-ipc.py" "$@" + exec "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" "$PORTAGE_BIN_PATH/ebuild-ipc.py" "$@" diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py index d68d3f05e..773054f5d 100755 --- a/bin/ebuild-ipc.py +++ b/bin/ebuild-ipc.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2010-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # diff --git a/bin/ebuild.sh b/bin/ebuild.sh index cfcf6eba3..dddaada87 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -220,7 +220,7 @@ debug-print() { # default target printf '%s\n' "${@}" >> "${T}/eclass-debug.log" # let the portage user own/write to this file - chgrp "${PORTAGE_GRPNAME:-portage}" "${T}/eclass-debug.log" + chgrp "${PORTAGE_GRPNAME:-${PORTAGE_GROUP}}" "${T}/eclass-debug.log" chmod g+w "${T}/eclass-debug.log" fi } diff --git a/bin/egencache b/bin/egencache index d172319f8..04c8af2f0 100755 --- a/bin/egencache +++ b/bin/egencache @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2009-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/emaint b/bin/emaint index df904f7c0..ea97c9b04 100755 --- a/bin/emaint +++ b/bin/emaint @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2005-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/emerge b/bin/emerge index e372f5e9e..65547e390 100755 --- a/bin/emerge +++ b/bin/emerge @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2006-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/emerge-webrsync b/bin/emerge-webrsync index db39b272e..6ac7e3328 100755 --- a/bin/emerge-webrsync +++ b/bin/emerge-webrsync @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # Author: Karl Trygve Kalleberg <karltk@gentoo.org> @@ -51,9 +51,15 @@ eval "$("${portageq}" envvar -v DISTDIR EPREFIX FEATURES \ PORTAGE_BIN_PATH PORTAGE_CONFIGROOT PORTAGE_GPG_DIR \ PORTAGE_NICENESS PORTAGE_REPOSITORIES PORTAGE_RSYNC_EXTRA_OPTS \ PORTAGE_RSYNC_OPTS PORTAGE_TEMP_GPG_DIR PORTAGE_TMPDIR \ - USERLAND http_proxy ftp_proxy)" + USERLAND http_proxy ftp_proxy \ + PORTAGE_USER PORTAGE_GROUP)" export http_proxy ftp_proxy +# PREFIX LOCAL: use Prefix servers, just because we want this and infra +# can't support us yet +GENTOO_MIRRORS="http://rsync.prefix.bitzolder.nl" +# END PREFIX LOCAL + source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1 repo_name=gentoo @@ -247,7 +253,9 @@ sync_local() { __vecho "Syncing local tree ..." - local ownership="portage:portage" + # PREFIX LOCAL: use PORTAGE_USER and PORTAGE_GROUP + local ownership="${PORTAGE_USER:-portage}:${PORTAGE_GROUP:-portage}" + # END PREFIX LOCAL if has usersync ${FEATURES} ; then case "${USERLAND}" in BSD) diff --git a/bin/emirrordist b/bin/emirrordist index 3ea08379e..866a2be65 100755 --- a/bin/emirrordist +++ b/bin/emirrordist @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2013-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/env-update b/bin/env-update index 2256b37f5..6ffadc638 100755 --- a/bin/env-update +++ b/bin/env-update @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/etc-update b/bin/etc-update index 7897d9b16..773db2daa 100755 --- a/bin/etc-update +++ b/bin/etc-update @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -32,7 +32,7 @@ get_config() { "${PORTAGE_CONFIGROOT}"etc/etc-update.conf) } -OS_RELEASE_POSSIBLE_IDS=$(source /etc/os-release >/dev/null 2>&1; echo ":${ID}:${ID_LIKE//[[:space:]]/:}:") +OS_RELEASE_POSSIBLE_IDS=$(source "@PORTAGE_EPREFIX@"/etc/os-release >/dev/null 2>&1; echo ":${ID}:${ID_LIKE//[[:space:]]/:}:") case ${OS_RELEASE_POSSIBLE_IDS} in *:suse:*|*:opensuse:*|*:opensuse-tumbleweed:*) OS_FAMILY='rpm';; diff --git a/bin/filter-bash-environment.py b/bin/filter-bash-environment.py index 045ea6f52..06cac7214 100755 --- a/bin/filter-bash-environment.py +++ b/bin/filter-bash-environment.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/fixpackages b/bin/fixpackages index a291e013d..f43506600 100755 --- a/bin/fixpackages +++ b/bin/fixpackages @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/glsa-check b/bin/glsa-check index eff01cf31..f9dae110f 100755 --- a/bin/glsa-check +++ b/bin/glsa-check @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/helper-functions.sh b/bin/helper-functions.sh index f76703f0c..34cbc3eec 100644 --- a/bin/helper-functions.sh +++ b/bin/helper-functions.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix index e1fc2bd99..03da3bbce 100644 --- a/bin/install-qa-check.d/05prefix +++ b/bin/install-qa-check.d/05prefix @@ -3,24 +3,24 @@ install_qa_check_prefix() { [[ ${ED} == ${D} ]] && return - if [[ -d ${ED}/${D} ]] ; then - find "${ED}/${D}" | \ + if [[ -d ${ED%/}${D%/} ]] ; then + find "${ED%/}${D%/}/" | \ while read i ; do - eqawarn "QA Notice: /${i##${ED}/${D}} installed in \${ED}/\${D}" + eqawarn "QA Notice: /${i#${ED%/}${D%/}/} installed in \${ED}\${D}" done - die "Aborting due to QA concerns: files installed in ${ED}/${D}" + die "Aborting due to QA concerns: files installed in ${ED%/}${D%/}/" fi - if [[ -d ${ED}/${EPREFIX} ]] ; then - find "${ED}/${EPREFIX}/" | \ + if [[ -d ${ED%/}${EPREFIX} ]] ; then + find "${ED%/}${EPREFIX}/" | \ while read i ; do - eqawarn "QA Notice: ${i#${D}} double prefix" + 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 [[ -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}" @@ -34,8 +34,23 @@ install_qa_check_prefix() { # check shebangs, bug #282539 rm -f "${T}"/non-prefix-shebangs-errs local WHITELIST=" /usr/bin/env " + # shebang can be an absolutised path, bug #342929 + local eprefix=$(canonicalize ${EPREFIX}) + # Without the stacked-prefix feature, tests using BPREFIX + # are redundant to EPREFIX, but run only if we will fail. + # Otherways, BPREFIX really is BROOT (the EAPI 7 one). + local BPREFIX=${EPREFIX} + local bprefix=${eprefix} + if has stacked-prefix ${FEATURES} && + [[ -z ${ROOT%/} ]] && + [[ ${CBUILD} == ${CHOST} ]] && + [[ ${EPREFIX} != ${BROOT-${PORTAGE_OVERRIDE_EPREFIX}} ]] && + :; then + BPREFIX=${BROOT-${PORTAGE_OVERRIDE_EPREFIX}} + bprefix=$(canonicalize ${BPREFIX}) + fi # this is hell expensive, but how else? - find "${ED}" -executable \! -type d -print0 \ + find "${ED%/}/" -executable \! -type d -print0 \ | xargs -0 grep -H -n -m1 "^#!" \ | while read f ; do @@ -49,9 +64,7 @@ install_qa_check_prefix() { 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 fp=${fn#${D%/}/} ; fp=/${fp%/*} 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) @@ -60,45 +73,56 @@ install_qa_check_prefix() { [[ ${rf} != /* ]] && rf=${fn%/*}/${rf} # ignore symlinks pointing to outside prefix # as seen in sys-devel/native-cctools - [[ $(canonicalize "/${rf#${D}}") != ${eprefix}/* ]] && continue + [[ $(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 [[ ${line[0]} == ${EPREFIX}/* || ${line[0]} == ${eprefix}/* ]] \ + || [[ ${line[0]} == ${BPREFIX}/* || ${line[0]} == ${bprefix}/* ]] ; 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)" \ + 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]})" + eqawarn "${fn#${D%/}/} has explicit EPREFIX in shebang but target not found (${line[0]})" fi fi continue fi - # unprefixed shebang, is the script directly in $PATH? - if [[ ":${PATH}:" == *":${fp}:"* ]] ; then - if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then + # unprefixed shebang, is the script directly in $PATH or an init + # script? + if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${fp}:"* ]] ; then + local foundprefix="none" + if [[ -e ${EROOT%/}${line[0]} || -e ${ED%/}${line[0]} ]] ; then + # is it unprefixed, but we can just fix it because an + # eprefixed variant exists + eqawarn "eprefixing shebang of ${fn#${D%/}/}" + foundprefix=${EPREFIX} + elif [[ -e ${BPREFIX}${line[0]} ]] ; then # is it unprefixed, but we can just fix it because a - # prefixed variant exists - eqawarn "prefixing shebang of ${fn#${D}}" + # bprefixed variant exists + eqawarn "bprefixing shebang of ${fn#${D%/}/}" + foundprefix=${BPREFIX} + fi + if [[ ${foundprefix} != "none" ]] ; then # 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}" + sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${foundprefix}"${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)" \ + 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]}" + eqawarn "invalid shebang in ${fn#${D%/}/}: ${line[0]}" fi done if [[ -e "${T}"/non-prefix-shebangs-errs ]] ; then diff --git a/bin/install-qa-check.d/80libraries b/bin/install-qa-check.d/80libraries index d1d2c4fdd..7ab419803 100644 --- a/bin/install-qa-check.d/80libraries +++ b/bin/install-qa-check.d/80libraries @@ -140,7 +140,11 @@ lib_check() { local abort="no" local a s for a in "${ED%/}"/usr/lib*/*.a ; do - s=${a%.a}.so + # 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 @@ -153,7 +157,12 @@ lib_check() { [[ ${abort} == "yes" ]] && die "add those ldscripts" # Make sure people don't store libtool files or static libs in /lib - f=$(ls "${ED%/}"/lib*/*.{a,la} 2>/dev/null) + # 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" diff --git a/bin/install-qa-check.d/80multilib-strict b/bin/install-qa-check.d/80multilib-strict index afd223250..6c705bf16 100644 --- a/bin/install-qa-check.d/80multilib-strict +++ b/bin/install-qa-check.d/80multilib-strict @@ -1,7 +1,7 @@ # Strict multilib directory checks multilib_strict_check() { if has multilib-strict ${FEATURES} && \ - [[ -x /usr/bin/file && -x /usr/bin/find ]] && \ + [[ -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" diff --git a/bin/install-qa-check.d/90gcc-warnings b/bin/install-qa-check.d/90gcc-warnings index bde198c97..3c737b51e 100644 --- a/bin/install-qa-check.d/90gcc-warnings +++ b/bin/install-qa-check.d/90gcc-warnings @@ -115,7 +115,7 @@ gcc_warn_check() { [[ $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") + "${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, diff --git a/bin/install-qa-check.d/90world-writable b/bin/install-qa-check.d/90world-writable index 820683bd6..90b961a86 100644 --- a/bin/install-qa-check.d/90world-writable +++ b/bin/install-qa-check.d/90world-writable @@ -2,7 +2,9 @@ world_writable_check() { # Now we look for all world writable files. - local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${ED}:/:") + # 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 local OLDIFS x prev_shopts=$- OLDIFS=$IFS @@ -19,7 +21,9 @@ world_writable_check() { eqawarn fi - local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')' | sed -e "s:^${ED}:/:") + # 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)" diff --git a/bin/install.py b/bin/install.py index 495534d33..03a4511bb 100755 --- a/bin/install.py +++ b/bin/install.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2013-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh index fde684013..7840d6012 100644 --- a/bin/isolated-functions.sh +++ b/bin/isolated-functions.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2020 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 @@ -425,16 +425,22 @@ case "${NOCOLOR:-false}" in ;; esac -if [[ -z ${USERLAND} ]] ; then - case $(uname -s) in - *BSD|DragonFly) - export USERLAND="BSD" - ;; - *) - export USERLAND="GNU" - ;; - esac -fi +# In Prefix every platform has USERLAND=GNU, even FreeBSD. Since I +# don't know how to reliably "figure out" we are in a Prefix instance of +# portage here, I for now disable this check, and hardcode it to GNU. +# Somehow it appears stange to me that this code is in this file, +# non-ebuilds/eclasses should never rely on USERLAND and XARGS, don't they? +#if [[ -z ${USERLAND} ]] ; then +# case $(uname -s) in +# *BSD|DragonFly) +# export USERLAND="BSD" +# ;; +# *) +# export USERLAND="GNU" +# ;; +# esac +#fi +[[ -z ${USERLAND} ]] && USERLAND="GNU" if [[ -z ${XARGS} ]] ; then case ${USERLAND} in diff --git a/bin/lock-helper.py b/bin/lock-helper.py index aa2dd60fa..427c1380b 100755 --- a/bin/lock-helper.py +++ b/bin/lock-helper.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2010-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index c2a16cbe0..d01a8edb1 100755 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # @@ -19,6 +19,10 @@ source "${PORTAGE_BIN_PATH}/ebuild.sh" || exit 1 install_symlink_html_docs() { if ! ___eapi_has_prefix_variables; then local ED=${D} + else + # PREFIX LOCAL: ED needs not to exist, whereas D does + [[ ! -d ${ED} && -d ${D} ]] && dodir / + # END PREFIX LOCAL fi cd "${ED}" || die "cd failed" #symlink the html documentation (if DOC_SYMLINKS_DIR is set in make.conf) @@ -83,7 +87,9 @@ install_qa_check() { local EPREFIX= ED=${D} fi - cd "${ED}" || die "cd failed" + # PREFIX LOCAL: ED needs not to exist, whereas D does + cd "${D}" || die "cd failed" + # END PREFIX LOCAL # Collect the paths for QA checks, highest prio first. paths=( @@ -170,6 +176,39 @@ install_qa_check() { mtree -U -e -p "${ED}" -k flags < "${T}/bsdflags.mtree" &> /dev/null 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 + # checks there, the specific QA funcs can hence rely on ED existing + if [[ -d ${ED} ]] ; then + case ${CHOST} in + *-darwin*) + # Mach-O platforms (NeXT, Darwin, OSX) + install_qa_check_macho + ;; + *-interix*|*-winnt*) + # PECOFF platforms (Windows/Interix) + install_qa_check_pecoff + ;; + *-aix*) + # XCOFF platforms (AIX) + install_qa_check_xcoff + ;; + *) + # because this is the majority: ELF platforms (Linux, + # Solaris, *BSD, IRIX, etc.) + install_qa_check_elf + ;; + esac + fi + + # this is basically here such that the diff with trunk remains just + # offsetted and not out of order + install_qa_check_misc + # END PREFIX LOCAL +} + +install_qa_check_elf() { # 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 @@ -207,11 +246,396 @@ install_qa_check() { eqawarn "$(while read -r x; do x=${x#*;} ; x=${x%%;*} ; echo "${x#${EPREFIX}}" ; done < "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2)" fi fi +} +install_qa_check_misc() { # Portage regenerates this on the installed system. rm -f "${ED%/}"/usr/share/info/dir{,.gz,.bz2} || die "rm failed!" } +install_qa_check_macho() { + if ! has binchecks ${RESTRICT} ; then + # on Darwin, dynamic libraries are called .dylibs instead of + # .sos. In addition the version component is before the + # extension, not after it. Check for this, and *only* warn + # about it. Some packages do ship .so files on Darwin and make + # it work (ugly!). + rm -f "${T}/mach-o.check" + find ${ED%/} -name "*.so" -or -name "*.so.*" | \ + while read i ; do + [[ $(file $i) == *"Mach-O"* ]] && \ + echo "${i#${D}}" >> "${T}/mach-o.check" + done + if [[ -f ${T}/mach-o.check ]] ; then + f=$(< "${T}/mach-o.check") + __vecho -ne '\a\n' + eqawarn "QA Notice: Found .so dynamic libraries on Darwin:" + eqawarn " ${f//$'\n'/\n }" + fi + rm -f "${T}/mach-o.check" + + # The naming for dynamic libraries is different on Darwin; the + # version component is before the extention, instead of after + # it, as with .sos. Again, make this a warning only. + rm -f "${T}/mach-o.check" + find ${ED%/} -name "*.dylib.*" | \ + while read i ; do + echo "${i#${D}}" >> "${T}/mach-o.check" + done + if [[ -f "${T}/mach-o.check" ]] ; then + f=$(< "${T}/mach-o.check") + __vecho -ne '\a\n' + eqawarn "QA Notice: Found wrongly named dynamic libraries on Darwin:" + eqawarn " ${f// /\n }" + fi + rm -f "${T}/mach-o.check" + fi + + install_name_is_relative() { + case $1 in + "@executable_path/"*) return 0 ;; + "@loader_path"/*) return 0 ;; + "@rpath/"*) return 0 ;; + *) return 1 ;; + esac + } + + # While we generate the NEEDED files, check that we don't get kernel + # traps at runtime because of broken install_names on Darwin. + rm -f "${T}"/.install_name_check_failed + scanmacho -qyRF '%a;%p;%S;%n' "${D}" | { while IFS= read l ; do + arch=${l%%;*}; l=${l#*;} + obj="/${l%%;*}"; l=${l#*;} + install_name=${l%%;*}; l=${l#*;} + needed=${l%%;*}; l=${l#*;} + + ignore= + qa_var="QA_IGNORE_INSTALL_NAME_FILES_${ARCH/-/_}" + eval "[[ -n \${!qa_var} ]] && + QA_IGNORE_INSTALL_NAME_FILES=(\"\${${qa_var}[@]}\")" + + if [[ ${#QA_IGNORE_INSTALL_NAME_FILES[@]} -gt 1 ]] ; then + for x in "${QA_IGNORE_INSTALL_NAME_FILES[@]}" ; do + [[ ${obj##*/} == ${x} ]] && \ + ignore=true + done + else + local shopts=$- + set -o noglob + for x in ${QA_IGNORE_INSTALL_NAME_FILES} ; do + [[ ${obj##*/} == ${x} ]] && \ + ignore=true + done + set +o noglob + set -${shopts} + fi + + # See if the self-reference install_name points to an existing + # and to be installed file. This usually is a symlink for the + # major version. + if install_name_is_relative ${install_name} ; then + # try to locate the library in the installed image + local inpath=${install_name#@*/} + local libl + for libl in $(find "${ED}" -name "${inpath##*/}") ; do + if [[ ${libl} == */${inpath} ]] ; then + install_name=/${libl#${D}} + break + fi + done + fi + if [[ ! -e ${D}${install_name} ]] ; then + eqawarn "QA Notice: invalid self-reference install_name ${install_name} in ${obj}" + # remember we are in an implicit subshell, that's + # why we touch a file here ... ideally we should be + # able to die correctly/nicely here + [[ -z ${ignore} ]] && touch "${T}"/.install_name_check_failed + fi + + # this is ugly, paths with spaces won't work + for lib in ${needed//,/ } ; do + if [[ ${lib} == ${D}* ]] ; then + eqawarn "QA Notice: install_name references \${D}: ${lib} in ${obj}" + [[ -z ${ignore} ]] && touch "${T}"/.install_name_check_failed + elif [[ ${lib} == ${S}* ]] ; then + eqawarn "QA Notice: install_name references \${S}: ${lib} in ${obj}" + [[ -z ${ignore} ]] && touch "${T}"/.install_name_check_failed + elif ! install_name_is_relative ${lib} && [[ ! -e ${lib} && ! -e ${D}${lib} ]] ; then + eqawarn "QA Notice: invalid reference to ${lib} in ${obj}" + [[ -z ${ignore} ]] && touch "${T}"/.install_name_check_failed + fi + done + + # backwards compatibility + echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED + # what we use + echo "${arch};${obj};${install_name};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.MACHO.3 + done } + if [[ -f ${T}/.install_name_check_failed ]] ; then + # secret switch "allow_broken_install_names" to get + # around this and install broken crap (not a good idea) + has allow_broken_install_names ${FEATURES} || \ + die "invalid install_name found, your application or library will crash at runtime" + fi +} + +install_qa_check_pecoff() { + local _pfx_scan="readpecoff ${CHOST}" + + # this one uses readpecoff, which supports multiple prefix platforms! + # this is absolutely _not_ optimized for speed, and there may be plenty + # of possibilities by introducing one or the other cache! + if ! has binchecks ${RESTRICT}; then + # copied and adapted from the above scanelf code. + local qa_var insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET} + local f x + + # display warnings when using stricter because we die afterwards + if has stricter ${FEATURES} ; then + unset PORTAGE_QUIET + fi + + local _exec_find_opt="-executable" + [[ ${CHOST} == *-winnt* ]] && _exec_find_opt='-name *.dll -o -name *.exe' + + # Make sure we disallow insecure RUNPATH/RPATH's + # Don't want paths that point to the tree where the package was built + # (older, broken libtools would do this). Also check for null paths + # because the loader will search $PWD when it finds null paths. + + f=$( + find "${ED}" -type f '(' ${_exec_find_opt} ')' -print0 | xargs -0 ${_pfx_scan} | \ + while IFS=";" read arch obj soname rpath needed ; do \ + echo "${rpath}" | grep -E "(${PORTAGE_BUILDDIR}|: |::|^:|^ )" > /dev/null 2>&1 \ + && echo "${obj}"; 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 ${_pfx_scan} | while IFS=";" read arch obj soname rpath needed; do \ + echo "${rpath}" | grep '$ORIGIN' > /dev/null 2>&1 && echo "${obj}"; done; + ) + if [[ -n ${f}${x} ]] ; then + __vecho -ne '\a\n' + eqawarn "QA Notice: The following files contain insecure RUNPATH's" + 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 '\a\n' + if [[ -n ${x} ]] || has stricter ${FEATURES} ; then + insecure_rpath=1 + else + eqawarn "cannot automatically fix runpaths on interix platforms!" + fi + fi + + rm -f "${PORTAGE_BUILDDIR}"/build-info/NEEDED + rm -f "${PORTAGE_BUILDDIR}"/build-info/NEEDED.PECOFF.1 + + # Save NEEDED information after removing self-contained providers + find "${ED}" -type f '(' ${_exec_find_opt} ')' -print0 | xargs -0 ${_pfx_scan} | { while IFS=';' read arch obj soname rpath needed; do + # need to strip image dir from object name. + obj="/${obj#${D}}" + if [ -z "${rpath}" -o -n "${rpath//*ORIGIN*}" ]; then + # object doesn't contain $ORIGIN in its runpath attribute + echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED + echo "${arch};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.PECOFF.1 + else + dir=${obj%/*} + # replace $ORIGIN with the dirname of the current object for the lookup + opath=$(echo :${rpath}: | sed -e "s#.*:\(.*\)\$ORIGIN\(.*\):.*#\1${dir}\2#") + sneeded=$(echo ${needed} | tr , ' ') + rneeded="" + for lib in ${sneeded}; do + found=0 + for path in ${opath//:/ }; do + [ -e "${ED}/${path}/${lib}" ] && found=1 && break + done + [ "${found}" -eq 0 ] && rneeded="${rneeded},${lib}" + done + rneeded=${rneeded:1} + if [ -n "${rneeded}" ]; then + echo "${obj} ${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED + echo "${arch};${obj};${soname};${rpath};${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.PECOFF.1 + fi + fi + done } + + if [[ ${insecure_rpath} -eq 1 ]] ; then + die "Aborting due to serious QA concerns with RUNPATH/RPATH" + elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then + die "Aborting due to QA concerns: ${die_msg}" + fi + + local _so_ext='.so*' + + case "${CHOST}" in + *-winnt*) _so_ext=".dll" ;; # no "*" intentionally! + esac + + # Run some sanity checks on shared libraries + for d in "${ED}"lib* "${ED}"usr/lib* ; do + [[ -d "${d}" ]] || continue + f=$(find "${d}" -name "lib*${_so_ext}" -print0 | \ + xargs -0 ${_pfx_scan} | while IFS=";" read arch obj soname rpath needed; \ + do [[ -z "${soname}" ]] && echo "${obj}"; done) + if [[ -n ${f} ]] ; then + __vecho -ne '\a\n' + eqawarn "QA Notice: The following shared libraries lack a SONAME" + eqawarn "${f}" + __vecho -ne '\a\n' + sleep 1 + fi + + f=$(find "${d}" -name "lib*${_so_ext}" -print0 | \ + xargs -0 ${_pfx_scan} | while IFS=";" read arch obj soname rpath needed; \ + do [[ -z "${needed}" ]] && echo "${obj}"; done) + if [[ -n ${f} ]] ; then + __vecho -ne '\a\n' + eqawarn "QA Notice: The following shared libraries lack NEEDED entries" + eqawarn "${f}" + __vecho -ne '\a\n' + sleep 1 + fi + done + + PORTAGE_QUIET=${tmp_quiet} + fi +} + +install_qa_check_xcoff() { + if ! has binchecks ${RESTRICT}; then + local tmp_quiet=${PORTAGE_QUIET} + local queryline deplib + local insecure_rpath_list= undefined_symbols_list= + + # display warnings when using stricter because we die afterwards + if has stricter ${FEATURES} ; then + unset PORTAGE_QUIET + fi + + rm -f "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 + + local neededfd + for neededfd in {3..1024} none; do ( : <&${neededfd} ) 2>/dev/null || break; done + [[ ${neededfd} != none ]] || die "cannot find free file descriptor handle" + + eval "exec ${neededfd}>\"${PORTAGE_BUILDDIR}\"/build-info/NEEDED.XCOFF.1" || die "cannot open ${PORTAGE_BUILDDIR}/build-info/NEEDED.XCOFF.1" + + ( # work around a problem in /usr/bin/dump (used by aixdll-query) + # dumping core when path names get too long. + cd "${ED}" >/dev/null && + find . -not -type d -exec \ + aixdll-query '{}' FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS ';' + ) > "${T}"/needed 2>/dev/null + + # Symlinking shared archive libraries is not a good idea on aix, + # as there is nothing like "soname" on pure filesystem level. + # So we create a copy instead of the symlink. + local prev_FILE= + local FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS + while read queryline + do + FILE= MEMBER= FLAGS= FORMAT= RUNPATH= DEPLIBS= + eval ${queryline} + FILE=${FILE#./} + + if [[ ${prev_FILE} != ${FILE} ]]; then + if [[ " ${FLAGS} " == *" SHROBJ "* && -h ${ED}${FILE} ]]; then + prev_FILE=${FILE} + local target=$(readlink "${ED}${FILE}") + if [[ ${target} == /* ]]; then + target=${D}${target} + else + target=${FILE%/*}/${target} + fi + rm -f "${ED}${FILE}" || die "cannot prune ${FILE}" + cp -f "${ED}${target}" "${ED}${FILE}" || die "cannot copy ${target} to ${FILE}" + fi + fi + done <"${T}"/needed + + prev_FILE= + while read queryline + do + FILE= MEMBER= FLAGS= FORMAT= RUNPATH= DEPLIBS= + eval ${queryline} + FILE=${FILE#./} + + if [[ -n ${MEMBER} && ${prev_FILE} != ${FILE} ]]; then + # Save NEEDED information for each archive library stub + # even if it is static only: the already installed archive + # may contain shared objects to be preserved. + echo "${FORMAT##* }${FORMAT%%-*};${EPREFIX}/${FILE};${FILE##*/};;" >&${neededfd} + fi + prev_FILE=${FILE} + + # shared objects have both EXEC and SHROBJ flags, + # while executables have EXEC flag only. + [[ " ${FLAGS} " == *" EXEC "* ]] || continue + + # Make sure we disallow insecure RUNPATH's + # Don't want paths that point to the tree where the package was built + # (older, broken libtools would do this). Also check for null paths + # because the loader will search $PWD when it finds null paths. + # And we really want absolute paths only. + if [[ -n $(echo ":${RUNPATH}:" | grep -E "(${PORTAGE_BUILDDIR}|::|:[^/])") ]]; then + insecure_rpath_list="${insecure_rpath_list}\n${FILE}${MEMBER:+[${MEMBER}]}" + fi + + local needed= + [[ -n ${MEMBER} ]] && needed=${FILE##*/} + for deplib in ${DEPLIBS}; do + eval deplib=${deplib} + if [[ ${deplib} == '.' || ${deplib} == '..' ]]; then + # Although we do have runtime linking, we don't want undefined symbols. + # AIX does indicate this by needing either '.' or '..' + undefined_symbols_list="${undefined_symbols_list}\n${FILE}" + else + needed="${needed}${needed:+,}${deplib}" + fi + done + + FILE=${EPREFIX}/${FILE} + + [[ -n ${MEMBER} ]] && MEMBER="[${MEMBER}]" + # Save NEEDED information + echo "${FORMAT##* }${FORMAT%%-*};${FILE}${MEMBER};${FILE##*/}${MEMBER};${RUNPATH};${needed}" >&${neededfd} + done <"${T}"/needed + + eval "exec ${neededfd}>&-" || die "cannot close handle to ${PORTAGE_BUILDDIR}/build-info/NEEDED.XCOFF.1" + + if [[ -n ${undefined_symbols_list} ]]; then + __vecho -ne '\a\n' + eqawarn "QA Notice: The following files contain undefined symbols." + eqawarn " Please file a bug about this at http://bugs.gentoo.org/" + eqawarn " with 'prefix' as the maintaining herd of the package." + eqawarn "${undefined_symbols_list}" + __vecho -ne '\a\n' + fi + + if [[ -n ${insecure_rpath_list} ]] ; then + __vecho -ne '\a\n' + eqawarn "QA Notice: The following files contain insecure RUNPATH's" + eqawarn " Please file a bug about this at http://bugs.gentoo.org/" + eqawarn " with 'prefix' as the maintaining herd of the package." + eqawarn "${insecure_rpath_list}" + __vecho -ne '\a\n' + if has stricter ${FEATURES} ; then + insecure_rpath=1 + 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 + + PORTAGE_QUIET=${tmp_quiet} + fi +} + __dyn_instprep() { if [[ -e ${PORTAGE_BUILDDIR}/.instprepped ]] ; then __vecho ">>> It appears that '$PF' is already instprepped; skipping." @@ -318,14 +742,267 @@ postinst_qa_check() { done < <(printf "%s\0" "${qa_checks[@]}" | LC_ALL=C sort -u -z) } +install_mask() { + local root="$1" + shift + local install_mask="$*" + + # We think of $install_mask as a space-separated list of + # globs. We don't want globbing in the "for" loop; that is, we + # want to keep the asterisks in the indivual entries. + local shopts=$- + set -o noglob + local no_inst + for no_inst in ${install_mask}; do + # Here, $no_inst is a single "entry" potentially + # containing a glob. From now on, we *do* want to + # expand it. + set +o noglob + + # The standard case where $no_inst is something that + # the shell could expand on its own. + if [[ -e "${root}"/${no_inst} || -L "${root}"/${no_inst} || + "${root}"/${no_inst} != $(echo "${root}"/${no_inst}) ]] ; then + __quiet_mode || einfo "Removing ${no_inst}" + rm -Rf "${root}"/${no_inst} >&/dev/null + fi + + # We also want to allow the user to specify a "bare + # glob." For example, $no_inst="*.a" should prevent + # ALL files ending in ".a" from being installed, + # regardless of their location/depth. We achieve this + # by passing the pattern to `find`. + find "${root}" \( -path "${no_inst}" -or -name "${no_inst}" \) \ + -print0 2> /dev/null \ + | LC_ALL=C sort -z \ + | while read -r -d ''; do + __quiet_mode || einfo "Removing /${REPLY#${root}}" + rm -Rf "${REPLY}" >&/dev/null + done + + done + # set everything back the way we found it + set +o noglob + set -${shopts} +} + +preinst_aix() { + if [[ ${CHOST} != *-aix* ]] || has binchecks ${RESTRICT}; then + return 0 + fi + local ar strip + if type ${CHOST}-ar >/dev/null 2>&1 && type ${CHOST}-strip >/dev/null 2>&1; then + ar=${CHOST}-ar + strip=${CHOST}-strip + elif [[ ${CBUILD} == "${CHOST}" ]] && type ar >/dev/null 2>&1 && type strip >/dev/null 2>&1; then + ar=ar + strip=strip + elif [[ -x /usr/ccs/bin/ar && -x /usr/ccs/bin/strip ]]; then + ar=/usr/ccs/bin/ar + strip=/usr/ccs/bin/strip + else + die "cannot find where to use 'ar' and 'strip' from" + fi + local archives_members= archives=() helperfiles=() + local archive_member soname runpath needed archive contentmember + while read archive_member; do + archive_member=${archive_member#*;${EPREFIX}/} # drop "^type;EPREFIX/" + soname=${archive_member#*;} + runpath=${soname#*;} + needed=${runpath#*;} + soname=${soname%%;*} + runpath=${runpath%%;*} + archive_member=${archive_member%%;*} # drop ";soname;runpath;needed$" + archive=${archive_member%[*} + if [[ ${archive_member} != *'['*']' ]]; then + if [[ "${soname};${runpath};${needed}" == "${archive##*/};;" && -e ${EROOT}${archive} ]]; then + # most likely is an archive stub that already exists, + # may have to preserve members being a shared object. + archives[${#archives[@]}]=${archive} + fi + continue + fi + archives_members="${archives_members}:(${archive_member}):" + contentmember="${archive%/*}/.${archive##*/}${archive_member#${archive}}" + # portage does os.lstat() on merged files every now + # and then, so keep stamp-files for archive members + # around to get the preserve-libs feature working. + helperfiles[${#helperfiles[@]}]=${ED}${contentmember} + done < "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 + if [[ ${#helperfiles[@]} > 0 ]]; then + rm -f "${helperfiles[@]}" || die "cannot prune ${helperfiles[@]}" + local f prev= + for f in "${helperfiles[@]}" + do + if [[ -z ${prev} ]]; then + { echo "Please leave this file alone, it is an important helper" + echo "for portage to implement the 'preserve-libs' feature on AIX." + } > "${f}" || die "cannot create ${f}" + chmod 0400 "${f}" || die "cannot chmod ${f}" + prev=${f} + else + ln "${prev}" "${f}" || die "cannot create hardlink ${f}" + fi + done + fi + + local preservemembers libmetadir prunedirs=() + local FILE MEMBER FLAGS + for archive in "${archives[@]}"; do + preservemembers= + while read line; do + [[ -n ${line} ]] || continue + FILE= MEMBER= FLAGS= + eval ${line} + [[ ${FILE} == ${EROOT}${archive} ]] || + die "invalid result of aixdll-query for ${EROOT}${archive}" + [[ -n ${MEMBER} && " ${FLAGS} " == *" SHROBJ "* ]] || continue + [[ ${archives_members} == *":(${archive}[${MEMBER}]):"* ]] && continue + preservemembers="${preservemembers} ${MEMBER}" + done <<-EOF + $(aixdll-query "${EROOT}${archive}" FILE MEMBER FLAGS) + EOF + [[ -n ${preservemembers} ]] || continue + einfo "preserving (on spec) ${archive}[${preservemembers# }]" + libmetadir=${ED}${archive%/*}/.${archive##*/} + mkdir "${libmetadir}" || die "cannot create ${libmetadir}" + pushd "${libmetadir}" >/dev/null || die "cannot cd to ${libmetadir}" + ${ar} -X32_64 -x "${EROOT}${archive}" ${preservemembers} || die "cannot unpack ${EROOT}${archive}" + chmod u+w ${preservemembers} || die "cannot chmod${preservemembers}" + ${strip} -X32_64 -e ${preservemembers} || die "cannot strip${preservemembers}" + ${ar} -X32_64 -q "${ED}${archive}" ${preservemembers} || die "cannot update ${archive}" + eend $? + popd >/dev/null || die "cannot leave ${libmetadir}" + prunedirs[${#prunedirs[@]}]=${libmetadir} + done + [[ ${#prunedirs[@]} == 0 ]] || + rm -rf "${prunedirs[@]}" || die "cannot prune ${prunedirs[@]}" + return 0 +} + +postinst_aix() { + if [[ ${CHOST} != *-aix* ]] || has binchecks ${RESTRICT}; then + return 0 + fi + local MY_PR=${PR%r0} + local ar strip + if type ${CHOST}-ar >/dev/null 2>&1 && type ${CHOST}-strip >/dev/null 2>&1; then + ar=${CHOST}-ar + strip=${CHOST}-strip + elif [[ ${CBUILD} == "${CHOST}" ]] && type ar >/dev/null 2>&1 && type strip >/dev/null 2>&1; then + ar=ar + strip=strip + elif [[ -x /usr/ccs/bin/ar && -x /usr/ccs/bin/strip ]]; then + ar=/usr/ccs/bin/ar + strip=/usr/ccs/bin/strip + else + die "cannot find where to use 'ar' and 'strip' from" + fi + local archives_members= archives=() activearchives= + local archive_member soname runpath needed + while read archive_member; do + archive_member=${archive_member#*;${EPREFIX}/} # drop "^type;EPREFIX/" + soname=${archive_member#*;} + runpath=${soname#*;} + needed=${runpath#*;} + soname=${soname%%;*} + runpath=${runpath%%;*} + archive_member=${archive_member%%;*} # drop ";soname;runpath;needed$" + [[ ${archive_member} == *'['*']' ]] && continue + [[ "${soname};${runpath};${needed}" == "${archive_member##*/};;" ]] || continue + # most likely is an archive stub, we might have to + # drop members being preserved shared objects. + archives[${#archives[@]}]=${archive_member} + activearchives="${activearchives}:(${archive_member}):" + done < "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 + + local type allcontentmembers= oldarchives=() + local contentmember + while read type contentmember; do + [[ ${type} == 'obj' ]] || continue + contentmember=${contentmember% *} # drop " timestamp$" + contentmember=${contentmember% *} # drop " hash$" + [[ ${contentmember##*/} == *'['*']' ]] || continue + contentmember=${contentmember#${EPREFIX}/} + allcontentmembers="${allcontentmembers}:(${contentmember}):" + contentmember=${contentmember%[*} + contentmember=${contentmember%/.*}/${contentmember##*/.} + [[ ${activearchives} == *":(${contentmember}):"* ]] && continue + oldarchives[${#oldarchives[@]}]=${contentmember} + done < "${EPREFIX}/var/db/pkg/${CATEGORY}/${P}${MY_PR:+-}${MY_PR}/CONTENTS" + + local archive line delmembers + local FILE MEMBER FLAGS + for archive in "${archives[@]}"; do + [[ -r ${EROOT}${archive} && -w ${EROOT}${archive} ]] || + chmod a+r,u+w "${EROOT}${archive}" || die "cannot chmod ${EROOT}${archive}" + delmembers= + while read line; do + [[ -n ${line} ]] || continue + FILE= MEMBER= FLAGS= + eval ${line} + [[ ${FILE} == "${EROOT}${archive}" ]] || + die "invalid result '${FILE}' of aixdll-query, expected '${EROOT}${archive}'" + [[ -n ${MEMBER} && " ${FLAGS} " == *" SHROBJ "* ]] || continue + [[ ${allcontentmembers} == *":(${archive%/*}/.${archive##*/}[${MEMBER}]):"* ]] && continue + delmembers="${delmembers} ${MEMBER}" + done <<-EOF + $(aixdll-query "${EROOT}${archive}" FILE MEMBER FLAGS) + EOF + [[ -n ${delmembers} ]] || continue + einfo "dropping ${archive}[${delmembers# }]" + rm -f "${EROOT}${archive}".new || die "cannot prune ${EROOT}${archive}.new" + cp "${EROOT}${archive}" "${EROOT}${archive}".new || die "cannot backup ${archive}" + ${ar} -X32_64 -z -o -d "${EROOT}${archive}".new ${delmembers} || die "cannot remove${delmembers} from ${archive}.new" + mv -f "${EROOT}${archive}".new "${EROOT}${archive}" || die "cannot put ${EROOT}${archive} in place" + eend $? + done + local libmetadir keepmembers prunedirs=() + for archive in "${oldarchives[@]}"; do + [[ -r ${EROOT}${archive} && -w ${EROOT}${archive} ]] || + chmod a+r,u+w "${EROOT}${archive}" || die "cannot chmod ${EROOT}${archive}" + keepmembers= + while read line; do + FILE= MEMBER= FLAGS= + eval ${line} + [[ ${FILE} == "${EROOT}${archive}" ]] || + die "invalid result of aixdll-query for ${EROOT}${archive}" + [[ -n ${MEMBER} && " ${FLAGS} " == *" SHROBJ "* ]] || continue + [[ ${allcontentmembers} == *":(${archive%/*}/.${archive##*/}[${MEMBER}]):"* ]] || continue + keepmembers="${keepmembers} ${MEMBER}" + done <<-EOF + $(aixdll-query "${EROOT}${archive}" FILE MEMBER FLAGS) + EOF + + if [[ -n ${keepmembers} ]]; then + einfo "preserving (extra)${keepmembers}" + libmetadir=${EROOT}${archive%/*}/.${archive##*/} + [[ ! -e ${libmetadir} ]] || rm -rf "${libmetadir}" || die "cannot prune ${libmetadir}" + mkdir "${libmetadir}" || die "cannot create ${libmetadir}" + pushd "${libmetadir}" >/dev/null || die "cannot cd to ${libmetadir}" + ${ar} -X32_64 -x "${EROOT}${archive}" ${keepmembers} || die "cannot unpack ${archive}" + ${strip} -X32_64 -e ${keepmembers} || die "cannot strip ${keepmembers}" + rm -f "${EROOT}${archive}.new" || die "cannot prune ${EROOT}${archive}.new" + ${ar} -X32_64 -q "${EROOT}${archive}.new" ${keepmembers} || die "cannot create ${EROOT}${archive}.new" + mv -f "${EROOT}${archive}.new" "${EROOT}${archive}" || die "cannot put ${EROOT}${archive} in place" + popd > /dev/null || die "cannot leave ${libmetadir}" + prunedirs[${#prunedirs[@]}]=${libmetadir} + eend $? + fi + done + [[ ${#prunedirs[@]} == 0 ]] || + rm -rf "${prunedirs[@]}" || die "cannot prune ${prunedirs[@]}" + return 0 +} + preinst_mask() { # Remove man pages, info pages, docs if requested. This is # implemented in bash in order to respect INSTALL_MASK settings # from bashrc. local f x for f in man info doc; do - if has no${f} ${FEATURES}; then - INSTALL_MASK+=" /usr/share/${f}" + if has no${f} $FEATURES; then + INSTALL_MASK="${INSTALL_MASK} ${EPREFIX}/usr/share/${f}" fi done @@ -477,7 +1154,7 @@ __dyn_package() { $PORTAGE_COMPRESSION_COMMAND > "$PORTAGE_BINPKG_TMPFILE" assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'" PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \ + "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \ "$PORTAGE_BINPKG_TMPFILE" "$PORTAGE_BUILDDIR/build-info" if [ $? -ne 0 ]; then rm -f "${PORTAGE_BINPKG_TMPFILE}" diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh index 90e622e75..78bb5caca 100644 --- a/bin/phase-functions.sh +++ b/bin/phase-functions.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 @@ -31,7 +31,7 @@ PORTAGE_READONLY_VARS="D EBUILD EBUILD_PHASE EBUILD_PHASE_FUNC \ PORTAGE_TMPDIR PORTAGE_UPDATE_ENV PORTAGE_USERNAME \ PORTAGE_VERBOSE PORTAGE_WORKDIR_MODE PORTAGE_XATTR_EXCLUDE \ REPLACING_VERSIONS REPLACED_BY_VERSION T WORKDIR \ - __PORTAGE_HELPER __PORTAGE_TEST_HARDLINK_LOCKS" + __PORTAGE_HELPER __PORTAGE_TEST_HARDLINK_LOCKS ED EROOT" PORTAGE_SAVED_READONLY_VARS="A CATEGORY P PF PN PR PV PVR" @@ -146,7 +146,7 @@ __filter_readonly_variables() { fi fi - "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${filtered_vars}" || die "filter-bash-environment.py failed" + "${PORTAGE_PYTHON:-@PREFIX_PORTAGE_PYTHON@}" "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${filtered_vars}" || die "filter-bash-environment.py failed" } # @FUNCTION: __preprocess_ebuild_env @@ -763,6 +763,7 @@ __dyn_help() { echo "production (stripped)" fi echo " merge to : ${ROOT}" + echo " offset : ${EPREFIX}" echo if [ -n "$USE" ]; then echo "Additionally, support for the following optional features will be enabled:" @@ -1087,7 +1088,7 @@ __ebuild_main() { __save_ebuild_env | __filter_readonly_variables \ --filter-features > "$T/environment" assert "__save_ebuild_env failed" - chgrp "${PORTAGE_GRPNAME:-portage}" "$T/environment" + chgrp "${PORTAGE_GRPNAME:-${PORTAGE_GROUP}}" "$T/environment" chmod g+w "$T/environment" fi [[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE" diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh index 9495465f9..c4ab51d78 100644 --- a/bin/phase-helpers.sh +++ b/bin/phase-helpers.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2020 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 @@ -895,6 +895,22 @@ ___best_version_and_has_version_common() { fi ;; esac + # PREFIX LOCAL: stacked-prefix feature + if ___eapi_has_prefix_variables && + has "${root_arg}" '--host-root' '-b' && + has stacked-prefix ${FEATURES} && + [[ -z ${ROOT%/} ]] && + [[ ${CBUILD} == ${CHOST} ]] && + [[ ${EPREFIX} != ${BROOT-${PORTAGE_OVERRIDE_EPREFIX}} ]] && + :; then + # When we merge into another EPREFIX, but not into some ROOT, + # and CHOST is equal to CBUILD, build tools found in EPREFIX + # perfectly work for the current build environment. + # In a "stacked prefix" we explicitly utilize this situation. + "${FUNCNAME[1]}" "${atom}" && return 0 + fi + # END PREFIX LOCAL + if [[ -n $PORTAGE_IPC_DAEMON ]] ; then cmd+=("${PORTAGE_BIN_PATH}"/ebuild-ipc "${FUNCNAME[1]}" "${root}" "${atom}") else diff --git a/bin/portageq b/bin/portageq index 3be5ab584..2d572b70c 100755 --- a/bin/portageq +++ b/bin/portageq @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -28,8 +28,8 @@ if os.path.isfile(os.path.join(os.path.dirname(os.path.dirname(os.path.realpath( pym_paths = [os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "lib")] 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")] + pym_paths = [ os.path.join(os.path.dirname( + os.path.dirname(os.path.realpath(__file__))), "pym") ] # Avoid sandbox violations after Python upgrade. if os.environ.get("SANDBOX_ON") == "1": sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":") diff --git a/bin/quickpkg b/bin/quickpkg index df8c1a8e8..b9ce52f8a 100755 --- a/bin/quickpkg +++ b/bin/quickpkg @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/readpecoff b/bin/readpecoff new file mode 100755 index 000000000..389b55081 --- /dev/null +++ b/bin/readpecoff @@ -0,0 +1,108 @@ +#!@PORTAGE_BASH@ + +################################################################### +# This script does the following: for implemented platforms, # +# it echos for each given path a line with the following format: # +# # +# <arch>;<obj>;<soname>;<rpath1:rpathN>;<needed1,neededN> # +# # +# arch may be any string, e.g. "PE32". obj is the full (!) path # +# to the file itself. soname, rpath and needed should be self # +# explaining - rpath is ":" separated, needed is "," separated. # +# # +# WARNING: Depends on CHOST argument to decide what to do! # +# # +# WARNING: The Script does _never_ fail! If required binaries # +# are missing, or information gathering fails, the # +# script will SILENTLY (!) exit, to not disturb the # +# normal merging process. # +# # +# WARNING: The _first_ argument needs to be a valid CHOST!!! # +# # +################################################################### + + +# Interix: Uses native objdump, since thats the only facility that +# knows about the native shared library information data. +# objdump is there in all interix installations where the GNU SDK +# is installed, which is a prerequisite for prefix anyway. + +scanbin_interix() { + local _itx_objdump="/opt/gcc.3.3/bin/objdump" + [[ -x ${_itx_objdump} ]] || _itx_objdump="/opt/gcc.4.2/bin/objdump" + [[ -x ${_itx_objdump} ]] || exit 0 + + # objdump is there, so now gather the information + _itx_full_info() { + local obj="$(cd "$(dirname "$1")"; pwd)/${1##*/}" + local so= + local rp= + local ne= + + { file -L "${obj}" | grep "PE" > /dev/null 2>&1; } || return + + _itx_gather() { + ${_itx_objdump} -p "$1" | while IFS= read line; do + [[ ${line} == *RPATH* || ${line} == *NEEDED* || ${line} == *SONAME* ]] || continue + + eval "$(echo "${line}" | sed -e 's,[[:space:]]*\([A-Z]*\)[[:space:]]*\(.*\)$,key=\1;value="\2",g')" + + case "${key}" in + RPATH) echo "rp=\"${value}\"" ;; + NEEDED) echo "test -n \"\${ne}\" && ne=\"\${ne},${value}\"; test -z \"\${ne}\" && ne=\"${value}\"" ;; + SONAME) echo "so=\"${value}\"" ;; + esac + done + } + + eval "$(_itx_gather ${obj})" + echo "386;${obj};${so};${rp};${ne}" + } + + for x in "$@"; do + _itx_full_info "${x}" + done + + exit 0 +} + + +# Native Windows: Uses the winnt compiler ("parity") to gather +# information. parity is the only one knowing about the location +# and format of the relevant data, and it is there always when +# wanting to build native win32 executables. + +scanbin_winnt() { + local _winnt_inspector="$(type -P "parity.inspector")" + [[ -x ${_winnt_inspector} ]] || exit 0 + + _winnt_full_info () { + local obj="$(cd "$(dirname "$1")"; pwd)/${1##*/}" + + { file -L "${obj}" | grep "PE" > /dev/null 2>&1; } || exit 0 + + # parity.inspector in --raw mode has exactly the format we + # want - wonder, wonder, i implemented that switch :) + + local info="$(${_winnt_inspector} --raw "${obj}")" + echo "386;${obj};${info}" + } + + for x in "$@"; do + _winnt_full_info "${x}" + done +} + +# CHOST is the first argument! +_chost=$1 + +# verify CHOST... +[[ -z ${_chost} ]] && { echo "CHOST not set!!"; exit 1; } +[[ ${_chost} == *-*-* ]] || { echo "invalid CHOST!!"; exit 1; } +shift + +case "${_chost}" in +*-interix*) scanbin_interix "$@" ;; +*-winnt*) scanbin_winnt "$@" ;; +esac + diff --git a/bin/regenworld b/bin/regenworld index bedc58bda..45394ab5b 100755 --- a/bin/regenworld +++ b/bin/regenworld @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/save-ebuild-env.sh b/bin/save-ebuild-env.sh index 947ac79d5..7d7235f23 100644..100755 --- a/bin/save-ebuild-env.sh +++ b/bin/save-ebuild-env.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -89,9 +89,13 @@ __save_ebuild_env() { ___eapi_has_package_manager_build_user && unset -f package_manager_build_user ___eapi_has_package_manager_build_group && unset -f package_manager_build_group - # Clear out the triple underscore namespace as it is reserved by the PM. - unset -f $(compgen -A function ___) - unset ${!___*} + # BEGIN PREFIX LOCAL: compgen is not compiled in during bootstrap + if type compgen >& /dev/null ; then + # Clear out the triple underscore namespace as it is reserved by the PM. + unset -f $(compgen -A function ___) + unset ${!___*} + fi + # END PREFIX LOCAL # portage config variables and variables set directly by portage unset ACCEPT_LICENSE BAD BRACKET BUILD_PREFIX COLS \ @@ -118,6 +122,10 @@ __save_ebuild_env() { # user config variables unset DOC_SYMLINKS_DIR INSTALL_MASK PKG_INSTALL_MASK + # PREFIX LOCAL: Prefix additions + unset EXTRA_PATH PORTAGE_GROUP PORTAGE_USER + # END PREFIX LOCAL + declare -p declare -fp if [[ ${BASH_VERSINFO[0]} == 3 ]]; then diff --git a/bin/xattr-helper.py b/bin/xattr-helper.py index 49c981580..a8aef3880 100755 --- a/bin/xattr-helper.py +++ b/bin/xattr-helper.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2012-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/bin/xpak-helper.py b/bin/xpak-helper.py index 8c965ecda..ccb6c0eff 100755 --- a/bin/xpak-helper.py +++ b/bin/xpak-helper.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -b +#!@PREFIX_PORTAGE_PYTHON@ -b # Copyright 2009-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 diff --git a/cnf/Makefile.in b/cnf/Makefile.in new file mode 100644 index 000000000..6cf3fc690 --- /dev/null +++ b/cnf/Makefile.in @@ -0,0 +1,42 @@ +SHELL = @PORTAGE_BASH@ + +prefix = @prefix@ +sysconfdir = @sysconfdir@ +datadir = @datadir@ + +srcdir = @srcdir@ +top_builddir = @top_builddir@ +PORTAGE_CONF = $(datadir)/portage/config + +portageuser = @portageuser@ +portagegroup = @portagegroup@ + +INSTALL = @INSTALL@ +INSTALL_subst = ${top_builddir}/subst-install +LN_S = @LN_S@ + +all: + +install: + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(PORTAGE_CONF) + $(INSTALL_subst) \ + -o "$(portageuser)" -g "$(portagegroup)" \ + -t "$(DESTDIR)$(PORTAGE_CONF)" \ + "$(srcdir)"/make.globals "$(srcdir)"/repos.conf + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(PORTAGE_CONF)/sets + $(INSTALL_subst) \ + -o "$(portageuser)" -g "$(portagegroup)" \ + -t "$(DESTDIR)$(PORTAGE_CONF)/sets" \ + "$(srcdir)"/sets/portage.conf + $(INSTALL_subst) \ + -o "$(portageuser)" -g "$(portagegroup)" \ + "$(srcdir)"/make.conf.example "$(DESTDIR)$(PORTAGE_CONF)"/make.conf.example + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(sysconfdir) + $(INSTALL_subst) \ + -o "$(portageuser)" -g "$(portagegroup)" \ + -t "$(DESTDIR)$(sysconfdir)" \ + "$(srcdir)"/dispatch-conf.conf \ + "$(srcdir)"/etc-update.conf + ( cd $(DESTDIR)$(sysconfdir) && $(LN_S) $(DESTDIR)$(PORTAGE_CONF)/make.globals ) + +.PHONY: all install diff --git a/cnf/make.conf.example b/cnf/make.conf.example index a309a5c43..c1d060c7c 100644 --- a/cnf/make.conf.example +++ b/cnf/make.conf.example @@ -100,7 +100,7 @@ # PORTAGE_TMPDIR is the location portage will use for compilations and # temporary storage of data. This can get VERY large depending upon # the application being installed. -#PORTAGE_TMPDIR=/var/tmp +#PORTAGE_TMPDIR=@PORTAGE_EPREFIX@/var/tmp # # PORTDIR is the location of the ebuild repository. This is the repository # for all profile information as well as all ebuilds. If you change @@ -108,7 +108,7 @@ # ***Warning*** # Data stored inside PORTDIR is in peril of being overwritten or deleted by # the emerge --sync command. -#PORTDIR=/var/db/repos/gentoo +#PORTDIR=@PORTAGE_EPREFIX@/var/db/repos/gentoo # # DISTDIR is where all of the source code tarballs will be placed for # emerges. After packages are built, it is safe to remove any and @@ -116,12 +116,12 @@ # fetched on demand for a given build. If you would like to # selectively prune obsolete files from this directory, see # eclean from the gentoolkit package. -#DISTDIR=/var/cache/distfiles +#DISTDIR=@PORTAGE_EPREFIX@/var/cache/distfiles # # PKGDIR is the location of binary packages that you can have created # with '--buildpkg' or '-b' while emerging a package. This can get # up to several hundred megs, or even a few gigs. -#PKGDIR=/var/cache/binpkgs +#PKGDIR=@PORTAGE_EPREFIX@/var/cache/binpkgs # # PORTAGE_LOGDIR is the location where portage will store all the logs it # creates from each individual merge. They are stored as @@ -134,7 +134,7 @@ # PORTDIR_OVERLAY is a directory where local ebuilds may be stored without # concern that they will be deleted by rsync updates. Default is not # defined. -#PORTDIR_OVERLAY=/usr/local/portage +#PORTDIR_OVERLAY=@PORTAGE_EPREFIX@/usr/local/portage # Fetching files # ============== @@ -157,8 +157,8 @@ #RESUMECOMMAND="wget -c -t 3 -T 60 --passive-ftp --limit-rate=200k -O \"\${DISTDIR}/\${FILE}\" \"\${URI}\"" # # Lukemftp (BSD ftp): -#FETCHCOMMAND="/usr/bin/lukemftp -s -a -o \"\${DISTDIR}/\${FILE}\" \"\${URI}\"" -#RESUMECOMMAND="/usr/bin/lukemftp -s -a -R -o \"\${DISTDIR}/\${FILE}\" \"\${URI}\"" +#FETCHCOMMAND="lukemftp -s -a -o \"\${DISTDIR}/\${FILE}\" \"\${URI}\"" +#RESUMECOMMAND="lukemftp -s -a -R -o \"\${DISTDIR}/\${FILE}\" \"\${URI}\"" # # Portage uses GENTOO_MIRRORS to specify mirrors to use for source retrieval. # The list is a space separated list which is read left to right. If you use @@ -210,6 +210,10 @@ # Instructions for setting up a local rsync server are available here: # https://wiki.gentoo.org/wiki/Local_Mirror # +# For Gentoo Prefix, use the following URL: +# +# Default: "rsync://rsync.prefix.bitzolder.nl/gentoo-portage-prefix +# #SYNC="rsync://rsync.gentoo.org/gentoo-portage" # # PORTAGE_RSYNC_RETRIES sets the number of times portage will attempt to retrieve diff --git a/cnf/make.globals b/cnf/make.globals index dd3f28f70..d3ba98513 100644 --- a/cnf/make.globals +++ b/cnf/make.globals @@ -27,12 +27,12 @@ ACCEPT_PROPERTIES="*" ACCEPT_RESTRICT="*" # Miscellaneous paths -DISTDIR="/var/cache/distfiles" -PKGDIR="/var/cache/binpkgs" -RPMDIR="/var/cache/rpm" +DISTDIR="@PORTAGE_EPREFIX@/var/cache/distfiles" +PKGDIR="@PORTAGE_EPREFIX@/var/cache/binpkgs" +RPMDIR="@PORTAGE_EPREFIX@/var/cache/rpm" # Temporary build directory -PORTAGE_TMPDIR="/var/tmp" +PORTAGE_TMPDIR="@PORTAGE_EPREFIX@/var/tmp" # The compression used for binary packages. Defaults to zstd except for # existing installs where bzip2 is used for backward compatibility. @@ -71,6 +71,9 @@ FEATURES="assume-digests binpkg-docompress binpkg-dostrip binpkg-logs COLLISION_IGNORE="/lib/modules/* *.py[co] *\$py.class" UNINSTALL_IGNORE="/lib/modules/*" +# Force EPREFIX, ED and EROOT to exist in all EAPIs, not just 3 and up +FEATURES="${FEATURES} force-prefix" + # By default wait 5 secs before cleaning a package CLEAN_DELAY="5" @@ -108,12 +111,32 @@ PORTAGE_SYNC_STALE="30" PORTAGE_LOGDIR_CLEAN="find \"\${PORTAGE_LOGDIR}\" -type f ! -name \"summary.log*\" -mtime +7 -delete" # Minimal CONFIG_PROTECT +# NOTE: in Prefix, these are NOT prefixed on purpose, because the +# profiles define them too CONFIG_PROTECT="/etc" CONFIG_PROTECT_MASK="/etc/env.d" # Disable auto-use USE_ORDER="env:pkg:conf:defaults:pkginternal:features:repo:env.d" +# PREFIX LOCAL: additional vars set during install +# Default portage user/group +PORTAGE_USER='@portageuser@' +PORTAGE_GROUP='@portagegroup@' +PORTAGE_ROOT_USER='@rootuser@' + +# Default ownership of installed files. +PORTAGE_INST_UID="@rootuid@" +PORTAGE_INST_GID="@rootgid@" + +# Any extra PATHs to add to the ebuild environment's PATH (if any) +EXTRA_PATH="@EXTRA_PATH@" + +# The offset prefix this Portage was configured with (not used by +# Portage itself) +CONFIGURE_EPREFIX="@PORTAGE_EPREFIX@" +# END PREFIX LOCAL + # Mode bits for ${WORKDIR} (see ebuild.5). PORTAGE_WORKDIR_MODE="0700" @@ -121,9 +144,9 @@ PORTAGE_WORKDIR_MODE="0700" PORTAGE_ELOG_CLASSES="log warn error" PORTAGE_ELOG_SYSTEM="save_summary:log,warn,error,qa echo" -PORTAGE_ELOG_MAILURI="root" +PORTAGE_ELOG_MAILURI="@rootuser@" PORTAGE_ELOG_MAILSUBJECT="[portage] ebuild log for \${PACKAGE} on \${HOST}" -PORTAGE_ELOG_MAILFROM="portage@localhost" +PORTAGE_ELOG_MAILFROM="@portageuser@@localhost" # Signing command used by repoman PORTAGE_GPG_SIGNING_COMMAND="gpg --sign --digest-algo SHA256 --clearsign --yes --default-key \"\${PORTAGE_GPG_KEY}\" --homedir \"\${PORTAGE_GPG_DIR}\" \"\${FILE}\"" @@ -138,6 +161,20 @@ PORTAGE_XATTR_EXCLUDE="btrfs.* security.evm security.ima security.selinux system.nfs4_acl user.apache_handler user.Beagle.* user.dublincore.* user.mime_encoding user.xdg.*" +# Writeable paths for Mac OS X seatbelt sandbox +# +# If path ends in a slash (/), access will recursively be allowed to directory +# contents (using a regex), not the directory itself. Without a slash, access +# to the directory or file itself will be allowed (using a literal), so it can +# be created, removed and changed. If both is needed, the directory needs to be +# given twice, once with and once without the slash. Obviously this only makes +# sense for directories, not files. +# +# An empty value for either variable will disable all restrictions on the +# corresponding operation. +MACOSSANDBOX_PATHS="/dev/fd/ /private/tmp/ /private/var/tmp/ @@PORTAGE_BUILDDIR@@/ @@PORTAGE_ACTUAL_DISTDIR@@/" +MACOSSANDBOX_PATHS_CONTENT_ONLY="/dev/null /dev/dtracehelper /dev/tty /private/var/run/syslog" + # ***************************** # ** DO NOT EDIT THIS FILE ** # *************************************************** diff --git a/cnf/repos.conf b/cnf/repos.conf index 6cb6e3b3c..77ffab3e9 100644 --- a/cnf/repos.conf +++ b/cnf/repos.conf @@ -1,10 +1,10 @@ [DEFAULT] -main-repo = gentoo +main-repo = gentoo_prefix -[gentoo] -location = /var/db/repos/gentoo +[gentoo_prefix] +location = @PORTAGE_EPREFIX@/var/db/repos/gentoo sync-type = rsync -sync-uri = rsync://rsync.gentoo.org/gentoo-portage +sync-uri = rsync://rsync.prefix.bitzolder.nl/gentoo-portage-prefix auto-sync = yes sync-rsync-verify-jobs = 1 sync-rsync-verify-metamanifest = yes diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..9083824eb --- /dev/null +++ b/configure.ac @@ -0,0 +1,135 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(portage-prefix, @version@, prefix@gentoo.org) + +AC_PREREQ([2.61]) + +case "${prefix}" in + '') AC_MSG_ERROR([bad value ${prefix} for --prefix, must not be empty]) ;; + */) AC_MSG_ERROR([bad value ${prefix} for --prefix, must not end with '/']) ;; + /*|NONE) ;; + *) AC_MSG_ERROR([bad value ${prefix} for --prefix, must start with /]) ;; +esac + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE + +dnl Checks for programs. +dnl store cflags prior, otherwise it's not propagated. +if test "x$CFLAGS" != "x" +then + CFLAGS=$CFLAGS +fi + +AC_PREFIX_DEFAULT([/usr]) + +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_EGREP + +GENTOO_PATH_XCU_ID() +GENTOO_PATH_PYTHON([2.7]) + +AC_PATH_PROG(PORTAGE_RM, [rm], no) +AC_PATH_PROG(PORTAGE_MV, [mv], no) +AC_PATH_PROG(PORTAGE_BASENAME, [basename], no) +AC_PATH_PROG(PORTAGE_DIRNAME, [dirname], no) +dnl avoid bash internal variable messing up things here +GENTOO_PATH_GNUPROG(PORTAGE_BASH, [bash]) +GENTOO_PATH_GNUPROG(PORTAGE_SED, [sed]) +GENTOO_PATH_GNUPROG(PORTAGE_WGET, [wget]) +GENTOO_PATH_GNUPROG(PORTAGE_FIND, [find]) +GENTOO_PATH_GNUPROG(PORTAGE_XARGS, [xargs]) +GENTOO_PATH_GNUPROG(PORTAGE_GREP, [grep]) + +AC_ARG_WITH(portage-user, +AC_HELP_STRING([--with-portage-user=myuser],[use user 'myuser' as portage owner (default portage)]), +[case "${withval}" in + ""|yes) AC_MSG_ERROR(bad value ${withval} for --with-portage-user);; + *) portageuser="${withval}";; +esac], +[portageuser="portage"]) + +AC_ARG_WITH(portage-group, +AC_HELP_STRING([--with-portage-group=mygroup],[use group 'mygroup' as portage users group (default portage)]), +[case "${withval}" in + ""|yes) AC_MSG_ERROR(bad value ${withval} for --with-portage-group);; + *) portagegroup="${withval}";; +esac], +[portagegroup="portage"]) + +AC_ARG_WITH(root-user, +AC_HELP_STRING([--with-root-user=myuser],[uses 'myuser' as owner of installed files (default is portage-user)]), +[case "${withval}" in + ""|yes) AC_MSG_ERROR(bad value ${withval} for --with-root-user);; + *) rootuser="${withval}";; +esac], +[rootuser="${portageuser}"]) + +AC_MSG_CHECKING([for user id of ${rootuser}]) +dnl grab uid of rootuser +rootuid=`${XCU_ID} -u "${rootuser}"` +if test "x`echo ${rootuid} | ${EGREP} '^[[0-9]]+$'`" != "x" +then + AC_MSG_RESULT([${rootuid}]) +else + AC_MSG_ERROR([error finding the user id of ${rootuser}]) +fi +AC_MSG_CHECKING([for group id of ${rootuser}]) +rootgid=`${XCU_ID} -g "${rootuser}"` +if test "x`echo ${rootgid} | ${EGREP} '^[[0-9]]+$'`" != "x" +then + AC_MSG_RESULT([${rootgid}]) +else + AC_MSG_ERROR([error finding the group id of ${rootuser}]) +fi + +AC_ARG_WITH(offset-prefix, +AC_HELP_STRING([--with-offset-prefix], + [specify the installation prefix for all packages, defaults to an empty string]), + [PORTAGE_EPREFIX=$withval], + [PORTAGE_EPREFIX='']) + +if test "x$PORTAGE_EPREFIX" != "x" +then + PORTAGE_EPREFIX=`${PREFIX_PORTAGE_PYTHON} -c "import os; print(os.path.normpath('$PORTAGE_EPREFIX'))"` +fi + +AC_ARG_WITH(extra-path, +AC_HELP_STRING([--with-extra-path], [specify additional PATHs available to the portage build environment (use with care)]), +[EXTRA_PATH="$withval"], +[EXTRA_PATH=""]) + +AC_SUBST(portageuser) +AC_SUBST(portagegroup) +AC_SUBST(rootuser) +AC_SUBST(rootuid) +AC_SUBST(rootgid) +AC_SUBST(PORTAGE_EPREFIX) +AC_SUBST(EXTRA_PATH) +AC_SUBST(PORTAGE_BASE,['${exec_prefix}/lib/portage']) + +AC_SUBST(PORTAGE_RM) +AC_SUBST(PORTAGE_MV) +AC_SUBST(PORTAGE_BASENAME) +AC_SUBST(PORTAGE_DIRNAME) +AC_SUBST(PORTAGE_BASH) +AC_SUBST(PORTAGE_SED) +AC_SUBST(PORTAGE_WGET) +AC_SUBST(PORTAGE_FIND) +AC_SUBST(PORTAGE_XARGS) +AC_SUBST(PORTAGE_GREP) + +AC_CONFIG_FILES([subst-install], [chmod +x subst-install]) +AC_CONFIG_FILES([ + Makefile + man/Makefile + bin/Makefile + lib/Makefile + cnf/Makefile +]) + +AC_OUTPUT diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 000000000..7d4193cc9 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,41 @@ +SHELL = @PORTAGE_BASH@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +sysconfdir = @sysconfdir@ +libdir = @libdir@ +PYTHON = @PREFIX_PORTAGE_PYTHON@ + +srcdir=@srcdir@ +top_builddir=@top_builddir@ + +portageuser = @portageuser@ +portagegroup = @portagegroup@ + +PORTAGE_PYM = @PORTAGE_BASE@/lib +INSTALL = @INSTALL@ +INSTALL_subst = ${top_builddir}/subst-install + +all: + +install: + $(INSTALL) -d -m 755 -o "$(portageuser)" -g "$(portagegroup)" $(DESTDIR)$(PORTAGE_PYM) + ( cd "$(srcdir)" && find * -type d ) | while read f ; do \ + files=( ) ; \ + shopt -s nullglob ; \ + for t in "$(srcdir)/$${f}"/* ; do \ + [[ -d $${t} ]] && continue ; \ + [[ $${t} == */Makefile* ]] && continue ; \ + files=( "$${files[@]}" "$${t}" ) ; \ + done ; \ + $(INSTALL) -d -m 755 \ + -o "$(portageuser)" -g "$(portagegroup)" \ + "$(DESTDIR)$(PORTAGE_PYM)/$${f}" && \ + [[ $${files[0]} ]] || continue ; \ + $(INSTALL_subst) \ + -o "$(portageuser)" -g "$(portagegroup)" \ + -t "$(DESTDIR)$(PORTAGE_PYM)/$${f}" \ + "$${files[@]}" \ + ; done + +.PHONY: all install diff --git a/lib/_emerge/Package.py b/lib/_emerge/Package.py index 3d7df2437..b2dfc07c1 100644 --- a/lib/_emerge/Package.py +++ b/lib/_emerge/Package.py @@ -48,7 +48,7 @@ class Package(Task): "LICENSE", "MD5", "PDEPEND", "PROVIDES", "RDEPEND", "repository", "REQUIRED_USE", "PROPERTIES", "REQUIRES", "RESTRICT", "SIZE", - "SLOT", "USE", "_mtime_"] + "SLOT", "USE", "_mtime_", "EPREFIX"] _dep_keys = ('BDEPEND', 'DEPEND', 'PDEPEND', 'RDEPEND') _buildtime_keys = ('BDEPEND', 'DEPEND') diff --git a/lib/_emerge/actions.py b/lib/_emerge/actions.py index 392f98d4d..d8e9d7774 100644 --- a/lib/_emerge/actions.py +++ b/lib/_emerge/actions.py @@ -40,6 +40,7 @@ from portage import os from portage import shutil from portage import eapi_is_supported, _encodings, _unicode_decode from portage.cache.cache_errors import CacheError +from portage.const import EPREFIX from portage.const import GLOBAL_CONFIG_PATH, VCS_DIRS, _DEPCLEAN_LIB_CHECK_DEFAULT from portage.const import SUPPORTED_BINPKG_FORMATS, TIMESTAMP_FORMAT from portage.dbapi.dep_expand import dep_expand @@ -2533,12 +2534,23 @@ def getgccversion(chost=None): gcc_ver_command = ['gcc', '-dumpversion'] gcc_ver_prefix = 'gcc-' + clang_ver_command = ['clang', '--version'] + clang_ver_prefix = 'clang-' + + ubinpath = os.path.join('/', portage.const.EPREFIX, 'usr', 'bin') + gcc_not_found_error = red( "!!! No gcc found. You probably need to 'source /etc/profile'\n" + "!!! to update the environment of this terminal and possibly\n" + "!!! other terminals also.\n" ) + def getclangversion(output): + version = re.search('clang version ([0-9.]+) ', output) + if version: + return version.group(1) + return "unknown" + if chost: try: proc = subprocess.Popen(["gcc-config", "-c"], @@ -2566,7 +2578,7 @@ def getgccversion(chost=None): return gcc_ver_prefix + myoutput try: - proc = subprocess.Popen(gcc_ver_command, + proc = subprocess.Popen([ubinpath + "/" + gcc_ver_command[0]] + gcc_ver_command[1:], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError: myoutput = None @@ -2577,6 +2589,32 @@ def getgccversion(chost=None): if mystatus == os.EX_OK: return gcc_ver_prefix + myoutput + if chost: + try: + proc = subprocess.Popen( + [ubinpath + "/" + chost + "-" + clang_ver_command[0]] + clang_ver_command[1:], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + myoutput = None + mystatus = 1 + else: + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n") + mystatus = proc.wait() + if mystatus == os.EX_OK: + return clang_ver_prefix + getclangversion(myoutput) + + try: + proc = subprocess.Popen([ubinpath + "/" + clang_ver_command[0]] + clang_ver_command[1:], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + myoutput = None + mystatus = 1 + else: + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n") + mystatus = proc.wait() + if mystatus == os.EX_OK: + return clang_ver_prefix + getclangversion(myoutput) + portage.writemsg(gcc_not_found_error, noiselevel=-1) return "[unavailable]" diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py index ec90e59df..13c2b658f 100644 --- a/lib/_emerge/depgraph.py +++ b/lib/_emerge/depgraph.py @@ -10209,6 +10209,16 @@ def _get_masking_status(pkg, pkgsettings, root_config, myrepo=None, use=None): mreasons.append(_MaskReason("CHOST", "CHOST: %s" % \ pkg._metadata["CHOST"])) + eprefix = pkgsettings["EPREFIX"] + if len(eprefix.rstrip('/')) > 0 and pkg.built and not pkg.installed: + if not "EPREFIX" in pkg._metadata: + mreasons.append(_MaskReason("EPREFIX", + "missing EPREFIX")) + elif len(pkg._metadata["EPREFIX"].strip()) < len(eprefix): + mreasons.append(_MaskReason("EPREFIX", + "EPREFIX: '%s' too small" % \ + pkg._metadata["EPREFIX"])) + if pkg.invalid: for msgs in pkg.invalid.values(): for msg in msgs: diff --git a/lib/_emerge/emergelog.py b/lib/_emerge/emergelog.py index cba98f395..cb7bf77b3 100644 --- a/lib/_emerge/emergelog.py +++ b/lib/_emerge/emergelog.py @@ -13,12 +13,13 @@ from portage import _unicode_decode from portage import _unicode_encode from portage.data import secpass from portage.output import xtermTitle +from portage.const import EPREFIX # We disable emergelog by default, since it's called from # dblink.merge() and we don't want that to trigger log writes # unless it's really called via emerge. _disable = True -_emerge_log_dir = '/var/log' +_emerge_log_dir = EPREFIX + '/var/log' def emergelog(xterm_titles, mystr, short_msg=None): diff --git a/lib/_emerge/getloadavg.py b/lib/_emerge/getloadavg.py index 6a2794fb1..e4cb009cb 100644 --- a/lib/_emerge/getloadavg.py +++ b/lib/_emerge/getloadavg.py @@ -2,6 +2,7 @@ # Distributed under the terms of the GNU General Public License v2 from portage import os +import platform getloadavg = getattr(os, "getloadavg", None) if getloadavg is None: @@ -11,9 +12,17 @@ if getloadavg is None: Raises OSError if the load average was unobtainable. """ try: - with open('/proc/loadavg') as f: - loadavg_str = f.readline() - except IOError: + if platform.system() in ["AIX", "HP-UX"]: + loadavg_str = os.popen('LANG=C /usr/bin/uptime 2>/dev/null').readline().split() + while loadavg_str[0] != 'load' and loadavg_str[1] != 'average:': + loadavg_str = loadavg_str[1:] + loadavg_str = loadavg_str[2:5] + loadavg_str = [x.rstrip(',') for x in loadavg_str] + loadavg_str = ' '.join(loadavg_str) + else: + with open('/proc/loadavg') as f: + loadavg_str = f.readline() + except (IOError, IndexError): # getloadavg() is only supposed to raise OSError, so convert raise OSError('unknown') loadavg_split = loadavg_str.split() diff --git a/lib/portage/__init__.py b/lib/portage/__init__.py index 60dbea693..ec667e478 100644 --- a/lib/portage/__init__.py +++ b/lib/portage/__init__.py @@ -122,7 +122,8 @@ try: MOVE_BINARY, PRELINK_BINARY, WORLD_FILE, MAKE_CONF_FILE, MAKE_DEFAULTS_FILE, \ DEPRECATED_PROFILE_FILE, USER_VIRTUALS_FILE, EBUILD_SH_ENV_FILE, \ INVALID_ENV_FILE, CUSTOM_MIRRORS_FILE, CONFIG_MEMORY_FILE,\ - INCREMENTALS, EAPI, MISC_SH_BINARY, REPO_NAME_LOC, REPO_NAME_FILE + INCREMENTALS, EAPI, MISC_SH_BINARY, REPO_NAME_LOC, REPO_NAME_FILE, \ + EPREFIX, rootuid except ImportError as e: sys.stderr.write("\n\n") diff --git a/lib/portage/const.py b/lib/portage/const.py index f6be9258f..146808fea 100644 --- a/lib/portage/const.py +++ b/lib/portage/const.py @@ -4,6 +4,11 @@ from __future__ import unicode_literals +# =========================================================================== +# autotool supplied constants. +# =========================================================================== +from portage.const_autotool import * + import os # =========================================================================== @@ -58,20 +63,33 @@ DEPCACHE_PATH = "/var/cache/edb/dep" GLOBAL_CONFIG_PATH = "/usr/share/portage/config" # these variables are not used with target_root or config_root +PORTAGE_BASE_PATH = PORTAGE_BASE # NOTE: Use realpath(__file__) so that python module symlinks in site-packages # are followed back to the real location of the whole portage installation. +#PREFIX: below should work, but I'm not sure how it it affects other places # NOTE: Please keep PORTAGE_BASE_PATH in one line to help substitutions. -PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(os.path.realpath(__file__.rstrip("co")).split(os.sep)[:-3])) +#PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(os.path.realpath(__file__.rstrip("co")).split(os.sep)[:-3])) PORTAGE_BIN_PATH = PORTAGE_BASE_PATH + "/bin" PORTAGE_PYM_PATH = os.path.realpath(os.path.join(__file__, '../..')) LOCALE_DATA_PATH = PORTAGE_BASE_PATH + "/locale" # FIXME: not used EBUILD_SH_BINARY = PORTAGE_BIN_PATH + "/ebuild.sh" MISC_SH_BINARY = PORTAGE_BIN_PATH + "/misc-functions.sh" -SANDBOX_BINARY = "/usr/bin/sandbox" -FAKEROOT_BINARY = "/usr/bin/fakeroot" -BASH_BINARY = "/bin/bash" -MOVE_BINARY = "/bin/mv" +SANDBOX_BINARY = EPREFIX + "/usr/bin/sandbox" +FAKEROOT_BINARY = EPREFIX + "/usr/bin/fakeroot" +BASH_BINARY = PORTAGE_BASH +MOVE_BINARY = PORTAGE_MV PRELINK_BINARY = "/usr/sbin/prelink" +MACOSSANDBOX_BINARY = "/usr/bin/sandbox-exec" +MACOSSANDBOX_PROFILE = '''(version 1) +(allow default) +(deny file-write*) +(allow file-write* file-write-setugid +@@MACOSSANDBOX_PATHS@@) +(allow file-write-data +@@MACOSSANDBOX_PATHS_CONTENT_ONLY@@)''' + +PORTAGE_GROUPNAME = portagegroup +PORTAGE_USERNAME = portageuser INVALID_ENV_FILE = "/etc/spork/is/not/valid/profile.env" MERGING_IDENTIFIER = "-MERGING-" @@ -190,6 +208,7 @@ SUPPORTED_FEATURES = frozenset([ "splitdebug", "split-elog", "split-log", + "stacked-prefix", # PREFIX LOCAL "strict", "strict-keepdir", "stricter", @@ -224,7 +243,9 @@ MANIFEST2_IDENTIFIERS = ("AUX", "MISC", "DIST", "EBUILD") # a config instance (since it's possible to contruct a config instance with # a different EPREFIX). Therefore, the EPREFIX constant should *NOT* be used # in the definition of any other constants within this file. -EPREFIX = "" +# PREFIX LOCAL: rely on EPREFIX from autotools +#EPREFIX = "" +# END PREFIX LOCAL # pick up EPREFIX from the environment if set if "PORTAGE_OVERRIDE_EPREFIX" in os.environ: diff --git a/lib/portage/const_autotool.py b/lib/portage/const_autotool.py new file mode 100644 index 000000000..ee540319c --- /dev/null +++ b/lib/portage/const_autotool.py @@ -0,0 +1,21 @@ +# Copyright: 2005-2009 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +# all vars that are to wind up in portage_const must have their name listed in __all__ + +__all__ = ["EPREFIX", "SYSCONFDIR", "PORTAGE_BASE", + "portageuser", "portagegroup", "rootuser", "rootuid", "rootgid", + "PORTAGE_BASH", "PORTAGE_MV"] + +EPREFIX = "@PORTAGE_EPREFIX@" +SYSCONFDIR = "@sysconfdir@" +PORTAGE_BASE = "@PORTAGE_BASE@" + +portagegroup = "@portagegroup@" +portageuser = "@portageuser@" +rootuser = "@rootuser@" +rootuid = @rootuid@ +rootgid = @rootgid@ + +PORTAGE_BASH = "@PORTAGE_BASH@" +PORTAGE_MV = "@PORTAGE_MV@" diff --git a/lib/portage/data.py b/lib/portage/data.py index f9d67fc3d..20a8d1ba7 100644 --- a/lib/portage/data.py +++ b/lib/portage/data.py @@ -3,6 +3,7 @@ # Distributed under the terms of the GNU General Public License v2 import os, pwd, grp, platform, sys +from portage.const import PORTAGE_GROUPNAME, PORTAGE_USERNAME, EPREFIX import portage portage.proxy.lazyimport.lazyimport(globals(), @@ -15,7 +16,10 @@ from portage.localization import _ ostype = platform.system() userland = None -if ostype == "DragonFly" or ostype.endswith("BSD"): +# Prefix always has USERLAND=GNU, even on +# FreeBSD, OpenBSD and Darwin (thank the lord!). +# Hopefully this entire USERLAND hack can go once +if EPREFIX == "" and (ostype == "DragonFly" or ostype.endswith("BSD")): userland = "BSD" else: userland = "GNU" @@ -147,32 +151,44 @@ def _get_global(k): #Discover the uid and gid of the portage user/group keyerror = False try: - portage_uid = pwd.getpwnam(_get_global('_portage_username')).pw_uid + username = str(_get_global('_portage_username')) + portage_uid = pwd.getpwnam(username).pw_uid except KeyError: - keyerror = True - portage_uid = 0 + # PREFIX LOCAL: some sysadmins are insane, bug #344307 + if username.isdigit(): + portage_uid = int(username) + else: + keyerror = True + portage_uid = 0 + # END PREFIX LOCAL try: - portage_gid = grp.getgrnam(_get_global('_portage_grpname')).gr_gid + grpname = str(_get_global('_portage_grpname')) + portage_gid = grp.getgrnam(grpname).gr_gid except KeyError: - keyerror = True - portage_gid = 0 + # PREFIX LOCAL: some sysadmins are insane, bug #344307 + if grpname.isdigit(): + portage_gid = int(grpname) + else: + keyerror = True + portage_gid = 0 + # END PREFIX LOCAL # Suppress this error message if both PORTAGE_GRPNAME and # PORTAGE_USERNAME are set to "root", for things like # Android (see bug #454060). if keyerror and not (_get_global('_portage_username') == "root" and _get_global('_portage_grpname') == "root"): + # PREFIX LOCAL: we need to fix this one day to distinguish prefix vs non-prefix + writemsg(colorize("BAD", + _("portage: '%s' user or '%s' group missing." % (_get_global('_portage_username'), _get_global('_portage_grpname')))) + "\n", noiselevel=-1) writemsg(colorize("BAD", - _("portage: 'portage' user or group missing.")) + "\n", noiselevel=-1) - writemsg(_( - " For the defaults, line 1 goes into passwd, " - "and 2 into group.\n"), noiselevel=-1) - writemsg(colorize("GOOD", - " portage:x:250:250:portage:/var/tmp/portage:/bin/false") \ - + "\n", noiselevel=-1) - writemsg(colorize("GOOD", " portage::250:portage") + "\n", - noiselevel=-1) + _(" In Prefix Portage this is quite dramatic")) + "\n", noiselevel=-1) + writemsg(colorize("BAD", + _(" since it means you have thrown away yourself.")) + "\n", noiselevel=-1) + writemsg(colorize("BAD", + _(" Re-add yourself or re-bootstrap Gentoo Prefix.")) + "\n", noiselevel=-1) + # END PREFIX LOCAL portage_group_warning() globals()['portage_gid'] = portage_gid @@ -251,7 +267,12 @@ def _get_global(k): v = pwd_struct.pw_name if v is None: - v = 'portage' + # PREFIX LOCAL: use var iso hardwired 'portage' + if k == '_portage_grpname': + v = PORTAGE_GROUPNAME + else: + v = PORTAGE_USERNAME + # END PREFIX LOCAL else: raise AssertionError('unknown name: %s' % k) @@ -288,13 +309,17 @@ def _init(settings): # from grp.getgrnam() with PyPy native_string = platform.python_implementation() == 'PyPy' - v = settings.get('PORTAGE_GRPNAME', 'portage') + # PREFIX LOCAL: use var iso hardwired 'portage' + v = settings.get('PORTAGE_GRPNAME', PORTAGE_GROUPNAME) + # END PREFIX LOCAL if native_string: v = portage._native_string(v) globals()['_portage_grpname'] = v _initialized_globals.add('_portage_grpname') - v = settings.get('PORTAGE_USERNAME', 'portage') + # PREFIX LOCAL: use var iso hardwired 'portage' + v = settings.get('PORTAGE_USERNAME', PORTAGE_USERNAME) + # END PREFIX LOCAL if native_string: v = portage._native_string(v) globals()['_portage_username'] = v diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py index 311c9a78a..2f6c4f343 100644 --- a/lib/portage/dbapi/bintree.py +++ b/lib/portage/dbapi/bintree.py @@ -97,7 +97,7 @@ class bindbapi(fakedbapi): "DEPEND", "EAPI", "IUSE", "KEYWORDS", "LICENSE", "MD5", "PDEPEND", "PROPERTIES", "PROVIDES", "RDEPEND", "repository", "REQUIRES", "RESTRICT", - "SIZE", "SLOT", "USE", "_mtime_" + "SIZE", "SLOT", "USE", "_mtime_", "EPREFIX" ]) self._aux_cache_slot_dict = slot_dict_class(self._aux_cache_keys) self._aux_cache = {} @@ -397,7 +397,7 @@ class binarytree(object): "IUSE", "KEYWORDS", "LICENSE", "PDEPEND", "PKGINDEX_URI", "PROPERTIES", "PROVIDES", "RDEPEND", "repository", "REQUIRES", "RESTRICT", - "SIZE", "SLOT", "USE"] + "SIZE", "SLOT", "USE", "EPREFIX"] self._pkgindex_aux_keys = list(self._pkgindex_aux_keys) self._pkgindex_use_evaluated_keys = \ ("BDEPEND", "DEPEND", "LICENSE", "RDEPEND", @@ -409,7 +409,8 @@ class binarytree(object): "CONFIG_PROTECT", "CONFIG_PROTECT_MASK", "FEATURES", "GENTOO_MIRRORS", "INSTALL_MASK", "IUSE_IMPLICIT", "USE", "USE_EXPAND", "USE_EXPAND_HIDDEN", "USE_EXPAND_IMPLICIT", - "USE_EXPAND_UNPREFIXED"]) + "USE_EXPAND_UNPREFIXED", + "EPREFIX"]) self._pkgindex_default_pkg_data = { "BDEPEND" : "", "BUILD_ID" : "", @@ -430,7 +431,7 @@ class binarytree(object): "SLOT" : "0", "USE" : "", } - self._pkgindex_inherited_keys = ["CHOST", "repository"] + self._pkgindex_inherited_keys = ["CHOST", "repository", "EPREFIX"] # Populate the header with appropriate defaults. self._pkgindex_default_header_data = { diff --git a/lib/portage/dbapi/vartree.py b/lib/portage/dbapi/vartree.py index 3687b471b..d7c8ef3de 100644 --- a/lib/portage/dbapi/vartree.py +++ b/lib/portage/dbapi/vartree.py @@ -42,6 +42,9 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.util._xattr:xattr', 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry', 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap', + 'portage.util._dyn_libs.LinkageMapMachO:LinkageMapMachO', + 'portage.util._dyn_libs.LinkageMapPeCoff:LinkageMapPeCoff', + 'portage.util._dyn_libs.LinkageMapXCoff:LinkageMapXCoff', 'portage.util._dyn_libs.NeededEntry:NeededEntry', 'portage.util._async.SchedulerInterface:SchedulerInterface', 'portage.util._eventloop.EventLoop:EventLoop', @@ -53,7 +56,7 @@ portage.proxy.lazyimport.lazyimport(globals(), ) from portage.const import CACHE_PATH, CONFIG_MEMORY_FILE, \ - MERGING_IDENTIFIER, PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH + MERGING_IDENTIFIER, PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH, EPREFIX from portage.dbapi import dbapi from portage.exception import CommandNotFound, \ InvalidData, InvalidLocation, InvalidPackageName, \ @@ -205,6 +208,17 @@ class vardbapi(dbapi): self._plib_registry = PreservedLibsRegistry(settings["ROOT"], os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry")) self._linkmap = LinkageMap(self) + chost = self.settings.get('CHOST') + if not chost: + chost = 'lunix?' # this happens when profiles are not available + if chost.find('darwin') >= 0: + self._linkmap = LinkageMapMachO(self) + elif chost.find('interix') >= 0 or chost.find('winnt') >= 0: + self._linkmap = LinkageMapPeCoff(self) + elif chost.find('aix') >= 0: + self._linkmap = LinkageMapXCoff(self) + else: + self._linkmap = LinkageMap(self) self._owners = self._owners_db(self) self._cached_counter = None @@ -3255,7 +3269,7 @@ class dblink(object): def path_to_node(path): node = path_node_map.get(path) if node is None: - node = LinkageMap._LibGraphNode(linkmap._obj_key(path)) + node = linkmap._LibGraphNode(linkmap._obj_key(path)) alt_path_node = lib_graph.get(node) if alt_path_node is not None: node = alt_path_node @@ -3432,7 +3446,15 @@ class dblink(object): def path_to_node(path): node = path_node_map.get(path) if node is None: - node = LinkageMap._LibGraphNode(linkmap._obj_key(path)) + chost = self.settings.get('CHOST') + if chost.find('darwin') >= 0: + node = LinkageMapMachO._LibGraphNode(linkmap._obj_key(path)) + elif chost.find('interix') >= 0 or chost.find('winnt') >= 0: + node = LinkageMapPeCoff._LibGraphNode(linkmap._obj_key(path)) + elif chost.find('aix') >= 0: + node = LinkageMapXCoff._LibGraphNode(linkmap._obj_key(path)) + else: + node = LinkageMap._LibGraphNode(linkmap._obj_key(path)) alt_path_node = lib_graph.get(node) if alt_path_node is not None: node = alt_path_node diff --git a/lib/portage/getbinpkg.py b/lib/portage/getbinpkg.py index 14dc149b1..997cd2eab 100644 --- a/lib/portage/getbinpkg.py +++ b/lib/portage/getbinpkg.py @@ -20,6 +20,7 @@ import socket import time import tempfile import base64 +from portage.const import CACHE_PATH import warnings _all_errors = [NotImplementedError, ValueError, socket.error] @@ -587,11 +588,11 @@ def dir_get_metadata(baseurl, conn=None, chunk_size=3000, verbose=1, usingcache= else: keepconnection = 1 - cache_path = "/var/cache/edb" + cache_path = CACHE_PATH metadatafilename = os.path.join(cache_path, 'remote_metadata.pickle') if makepickle is None: - makepickle = "/var/cache/edb/metadata.idx.most_recent" + makepickle = CACHE_PATH+"/metadata.idx.most_recent" try: conn = create_conn(baseurl, conn)[0] diff --git a/lib/portage/package/ebuild/_config/special_env_vars.py b/lib/portage/package/ebuild/_config/special_env_vars.py index 440dd00b2..12d701c9a 100644 --- a/lib/portage/package/ebuild/_config/special_env_vars.py +++ b/lib/portage/package/ebuild/_config/special_env_vars.py @@ -81,6 +81,9 @@ environ_whitelist += [ "ROOT", "ROOTPATH", "SANDBOX_LOG", "SYSROOT", "T", "TMP", "TMPDIR", "USE_EXPAND", "USE_ORDER", "WORKDIR", "XARGS", "__PORTAGE_TEST_HARDLINK_LOCKS", + # PREFIX LOCAL + "EXTRA_PATH", "PORTAGE_GROUP", "PORTAGE_USER", + # END PREFIX LOCAL ] # user config variables @@ -113,11 +116,13 @@ environ_whitelist += [ ] # other variables inherited from the calling environment +# UNIXMODE is necessary for MiNT environ_whitelist += [ "CVS_RSH", "ECHANGELOG_USER", "GPG_AGENT_INFO", "SSH_AGENT_PID", "SSH_AUTH_SOCK", "STY", "WINDOW", "XAUTHORITY", + "UNIXMODE", ] environ_whitelist = frozenset(environ_whitelist) @@ -138,6 +143,10 @@ environ_filter += [ # misc variables inherited from the calling environment environ_filter += [ "INFOPATH", "MANPATH", "USER", + "HOST", "GROUP", "LOGNAME", "MAIL", "REMOTEHOST", + "SECURITYSESSIONID", + "TERMINFO", "TERM_PROGRAM", "TERM_PROGRAM_VERSION", + "VENDOR", "__CF_USER_TEXT_ENCODING", ] # variables that break bash diff --git a/lib/portage/package/ebuild/config.py b/lib/portage/package/ebuild/config.py index 47c180c12..c76474354 100644 --- a/lib/portage/package/ebuild/config.py +++ b/lib/portage/package/ebuild/config.py @@ -45,7 +45,7 @@ from portage.exception import InvalidDependString, IsADirectory, \ PortageException from portage.localization import _ from portage.output import colorize -from portage.process import fakeroot_capable, sandbox_capable +from portage.process import fakeroot_capable, sandbox_capable, macossandbox_capable from portage.repository.config import load_repository_config from portage.util import ensure_dirs, getconfig, grabdict, \ grabdict_package, grabfile, grabfile_package, LazyItemsDict, \ @@ -898,38 +898,44 @@ class config(object): "PORTAGE_INST_UID": "0", } + # PREFIX LOCAL: inventing UID/GID based on a path is a very + # bad idea, it breaks almost everything since group ids + # don't have to match, when a user has many + # This in particularly breaks the configure-set portage + # group and user (in portage/data.py) eroot_or_parent = first_existing(eroot) - unprivileged = False - try: - eroot_st = os.stat(eroot_or_parent) - except OSError: - pass - else: - - if portage.data._unprivileged_mode( - eroot_or_parent, eroot_st): - unprivileged = True - - default_inst_ids["PORTAGE_INST_GID"] = str(eroot_st.st_gid) - default_inst_ids["PORTAGE_INST_UID"] = str(eroot_st.st_uid) - - if "PORTAGE_USERNAME" not in self: - try: - pwd_struct = pwd.getpwuid(eroot_st.st_uid) - except KeyError: - pass - else: - self["PORTAGE_USERNAME"] = pwd_struct.pw_name - self.backup_changes("PORTAGE_USERNAME") - - if "PORTAGE_GRPNAME" not in self: - try: - grp_struct = grp.getgrgid(eroot_st.st_gid) - except KeyError: - pass - else: - self["PORTAGE_GRPNAME"] = grp_struct.gr_name - self.backup_changes("PORTAGE_GRPNAME") + unprivileged = True +# try: +# eroot_st = os.stat(eroot_or_parent) +# except OSError: +# pass +# else: +# +# if portage.data._unprivileged_mode( +# eroot_or_parent, eroot_st): +# unprivileged = True +# +# default_inst_ids["PORTAGE_INST_GID"] = str(eroot_st.st_gid) +# default_inst_ids["PORTAGE_INST_UID"] = str(eroot_st.st_uid) +# +# if "PORTAGE_USERNAME" not in self: +# try: +# pwd_struct = pwd.getpwuid(eroot_st.st_uid) +# except KeyError: +# pass +# else: +# self["PORTAGE_USERNAME"] = pwd_struct.pw_name +# self.backup_changes("PORTAGE_USERNAME") +# +# if "PORTAGE_GRPNAME" not in self: +# try: +# grp_struct = grp.getgrgid(eroot_st.st_gid) +# except KeyError: +# pass +# else: +# self["PORTAGE_GRPNAME"] = grp_struct.gr_name +# self.backup_changes("PORTAGE_GRPNAME") + # END PREFIX LOCAL for var, default_val in default_inst_ids.items(): try: @@ -1187,7 +1193,7 @@ class config(object): writemsg("!!! /etc/portage/profile/virtuals. Please move it to\n") writemsg("!!! this new location.\n\n") - if not sandbox_capable and \ + if not sandbox_capable and not macossandbox_capable and \ ("sandbox" in self.features or "usersandbox" in self.features): if self.profile_path is not None and \ os.path.realpath(self.profile_path) == \ diff --git a/lib/portage/package/ebuild/doebuild.py b/lib/portage/package/ebuild/doebuild.py index 2bff94cb1..7d685dbe4 100644 --- a/lib/portage/package/ebuild/doebuild.py +++ b/lib/portage/package/ebuild/doebuild.py @@ -24,6 +24,7 @@ from textwrap import wrap import time import warnings import zlib +import platform import portage portage.proxy.lazyimport.lazyimport(globals(), @@ -51,7 +52,7 @@ from portage import bsd_chflags, \ unmerge, _encodings, _os_merge, \ _shell_quote, _unicode_decode, _unicode_encode from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \ - EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY, PORTAGE_PYM_PACKAGES + EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY, PORTAGE_PYM_PACKAGES, EPREFIX, MACOSSANDBOX_PROFILE from portage.data import portage_gid, portage_uid, secpass, \ uid, userpriv_groups from portage.dbapi.porttree import _parse_uri_map @@ -255,6 +256,12 @@ def _doebuild_path(settings, eapi=None): path.append(x_abs) path.extend(rootpath) + + # PREFIX LOCAL: append EXTRA_PATH from make.globals + extrapath = [x for x in settings.get("EXTRA_PATH", "").split(":") if x] + path.extend(extrapath) + # END PREFIX LOCAL + settings["PATH"] = ":".join(path) def doebuild_environment(myebuild, mydo, myroot=None, settings=None, @@ -1369,7 +1376,8 @@ def _spawn_actionmap(settings): "userpriv" not in restrict and \ "nouserpriv" not in restrict) - if not portage.process.sandbox_capable: + if not (portage.process.sandbox_capable or \ + portage.process.macossandbox_capable): nosandbox = True sesandbox = settings.selinux_enabled() and \ @@ -1613,6 +1621,10 @@ def spawn(mystring, mysettings, debug=False, free=False, droppriv=False, user = "root" elif portage_build_uid == portage_uid: user = portage.data._portage_username + # PREFIX LOCAL: accept numeric uid + else: + user = portage_uid + # END PREFIX LOCAL if user is not None: mysettings["PORTAGE_BUILD_USER"] = user @@ -1625,6 +1637,10 @@ def spawn(mystring, mysettings, debug=False, free=False, droppriv=False, group = "root" elif portage_build_gid == portage_gid: group = portage.data._portage_grpname + # PREFIX LOCAL: accept numeric gid + else: + group = portage_gid + # END PREFIX LOCAL if group is not None: mysettings["PORTAGE_BUILD_GROUP"] = group @@ -1633,7 +1649,8 @@ def spawn(mystring, mysettings, debug=False, free=False, droppriv=False, (not droppriv and "sandbox" not in features and \ "usersandbox" not in features and not fakeroot)) - if not free and not (fakeroot or portage.process.sandbox_capable): + if not free and not (fakeroot or portage.process.sandbox_capable or \ + portage.process.macossandbox_capable): free = True if mysettings.mycpv is not None: @@ -1649,6 +1666,77 @@ def spawn(mystring, mysettings, debug=False, free=False, droppriv=False, keywords["opt_name"] += " fakeroot" keywords["fakeroot_state"] = os.path.join(mysettings["T"], "fakeroot.state") spawn_func = portage.process.spawn_fakeroot + elif "sandbox" in features and platform.system() == 'Darwin': + keywords["opt_name"] += " macossandbox" + sbprofile = MACOSSANDBOX_PROFILE + + # determine variable names from profile: split + # "text@@VARNAME@@moretext@@OTHERVAR@@restoftext" into + # ("text", # "VARNAME", "moretext", "OTHERVAR", "restoftext") + # and extract variable named by reading every second item. + variables = [] + for line in sbprofile.split("\n"): + variables.extend(line.split("@@")[1:-1:2]) + + for var in variables: + paths = "" + if var in mysettings: + paths = mysettings[var] + else: + writemsg("Warning: sandbox profile references variable %s " + "which is not set.\nThe rule using it will have no " + "effect, which is most likely not the intended " + "result.\nPlease check make.conf/make.globals.\n" % + var) + + # not set or empty value + if not paths: + sbprofile = sbprofile.replace("@@%s@@" % var, "") + continue + + rules_literal = "" + rules_regex = "" + + # FIXME: Allow for quoting inside the variable + # to allow paths with spaces in them? + for path in paths.split(" "): + # do a second round of token + # replacements to be able to reference + # settings like EPREFIX or + # PORTAGE_BUILDDIR. + for token in path.split("@@")[1:-1:2]: + if token not in mysettings: + continue + + path = path.replace("@@%s@@" % token, mysettings[token]) + + if "@@" in path: + # unreplaced tokens left - + # silently ignore path - needed + # for PORTAGE_ACTUAL_DISTDIR + # which isn't always set + pass + elif path[-1] == os.sep: + # path ends in slash - make it a + # regex and allow access + # recursively. + path = path.replace(r'+', r'\+') + path = path.replace(r'*', r'\*') + path = path.replace(r'[', r'\[') + path = path.replace(r']', r'\]') + rules_regex += " #\"^%s\"\n" % path + else: + rules_literal += " #\"%s\"\n" % path + + rules = "" + if rules_literal: + rules += " (literal\n" + rules_literal + " )\n" + if rules_regex: + rules += " (regex\n" + rules_regex + " )\n" + sbprofile = sbprofile.replace("@@%s@@" % var, rules) + + keywords["profile"] = sbprofile + spawn_func = portage.process.spawn_macossandbox else: keywords["opt_name"] += " sandbox" spawn_func = portage.process.spawn_sandbox @@ -1751,6 +1839,7 @@ _post_phase_cmds = { ( {}, [ + "preinst_aix", "preinst_sfperms", "preinst_suid_scan", "preinst_qa_check", @@ -1758,6 +1847,7 @@ _post_phase_cmds = { ), ), "postinst" : [ + "postinst_aix", "postinst_qa_check"], } diff --git a/lib/portage/package/ebuild/fetch.py b/lib/portage/package/ebuild/fetch.py index 9682fea89..11b13fe56 100644 --- a/lib/portage/package/ebuild/fetch.py +++ b/lib/portage/package/ebuild/fetch.py @@ -51,6 +51,7 @@ from portage.checksum import (get_valid_checksum_keys, perform_md5, verify_all, checksum_str) from portage.const import BASH_BINARY, CUSTOM_MIRRORS_FILE, \ GLOBAL_CONFIG_PATH +from portage.const import rootgid from portage.data import portage_gid, portage_uid, userpriv_groups from portage.exception import FileNotFound, OperationNotPermitted, \ PortageException, TryAgain @@ -209,7 +210,7 @@ def _ensure_distdir(settings, distdir): # to have root's gid. Therefore, use root's gid instead of # portage's gid to avoid spurrious permissions adjustments # when inside fakeroot. - dir_gid = 0 + dir_gid = rootgid userfetch = portage.data.secpass >= 2 and "userfetch" in settings.features userpriv = portage.data.secpass >= 2 and "userpriv" in settings.features diff --git a/lib/portage/process.py b/lib/portage/process.py index ceb454030..3e5d2e4ef 100644 --- a/lib/portage/process.py +++ b/lib/portage/process.py @@ -23,7 +23,7 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.util:dump_traceback,writemsg', ) -from portage.const import BASH_BINARY, SANDBOX_BINARY, FAKEROOT_BINARY +from portage.const import BASH_BINARY, SANDBOX_BINARY, MACOSSANDBOX_BINARY, FAKEROOT_BINARY from portage.exception import CommandNotFound from portage.util._ctypes import find_library, LoadLibrary, ctypes @@ -99,6 +99,8 @@ sandbox_capable = (os.path.isfile(SANDBOX_BINARY) and fakeroot_capable = (os.path.isfile(FAKEROOT_BINARY) and os.access(FAKEROOT_BINARY, os.X_OK)) +macossandbox_capable = (os.path.isfile(MACOSSANDBOX_BINARY) and + os.access(MACOSSANDBOX_BINARY, os.X_OK)) def sanitize_fds(): """ @@ -172,6 +174,19 @@ def spawn_fakeroot(mycommand, fakeroot_state=None, opt_name=None, **keywords): args.append(mycommand) return spawn(args, opt_name=opt_name, **keywords) +def spawn_macossandbox(mycommand, profile=None, opt_name=None, **keywords): + if not macossandbox_capable: + return spawn_bash(mycommand, opt_name=opt_name, **keywords) + args=[MACOSSANDBOX_BINARY] + if not opt_name: + opt_name = os.path.basename(mycommand.split()[0]) + args.append("-p") + args.append(profile) + args.append(BASH_BINARY) + args.append("-c") + args.append(mycommand) + return spawn(args, opt_name=opt_name, **keywords) + _exithandlers = [] def atexit_register(func, *args, **kargs): """Wrapper around atexit.register that is needed in order to track diff --git a/lib/portage/tests/lazyimport/test_lazy_import_portage_baseline.py b/lib/portage/tests/lazyimport/test_lazy_import_portage_baseline.py index 080cf3f98..2bc54698a 100644 --- a/lib/portage/tests/lazyimport/test_lazy_import_portage_baseline.py +++ b/lib/portage/tests/lazyimport/test_lazy_import_portage_baseline.py @@ -20,6 +20,7 @@ class LazyImportPortageBaselineTestCase(TestCase): 'portage.proxy', 'portage.proxy.lazyimport', 'portage.proxy.objectproxy', 'portage._selinux', + 'portage.const_autotool', ]) _baseline_import_cmd = [portage._python_interpreter, '-c', ''' diff --git a/lib/portage/tests/resolver/ResolverPlayground.py b/lib/portage/tests/resolver/ResolverPlayground.py index de80a0cc1..0751e392e 100644 --- a/lib/portage/tests/resolver/ResolverPlayground.py +++ b/lib/portage/tests/resolver/ResolverPlayground.py @@ -286,6 +286,7 @@ class ResolverPlayground(object): metadata["repository"] = repo metadata["CATEGORY"] = cat metadata["PF"] = pf + metadata["EPREFIX"] = self.eprefix repo_dir = self.pkgdir category_dir = os.path.join(repo_dir, cat) diff --git a/lib/portage/tests/runTests.py b/lib/portage/tests/runTests.py index d4d1f7c76..2f9a7ad47 100755 --- a/lib/portage/tests/runTests.py +++ b/lib/portage/tests/runTests.py @@ -1,4 +1,4 @@ -#!/usr/bin/python -bWd +#!@PREFIX_PORTAGE_PYTHON@ -bWd # runTests.py -- Portage Unit Test Functionality # Copyright 2006-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -24,8 +24,14 @@ signal.signal(debug_signum, debug_signal) # Pretend that the current user's uid/gid are the 'portage' uid/gid, # so things go smoothly regardless of the current user and global # user/group configuration. -os.environ["PORTAGE_USERNAME"] = pwd.getpwuid(os.getuid()).pw_name -os.environ["PORTAGE_GRPNAME"] = grp.getgrgid(os.getgid()).gr_name +try: + os.environ["PORTAGE_USERNAME"] = pwd.getpwuid(os.getuid()).pw_name +except KeyError: + os.environ["PORTAGE_USERNAME"] = str(os.getuid()) +try: + os.environ["PORTAGE_GRPNAME"] = grp.getgrgid(os.getgid()).gr_name +except KeyError: + os.environ["PORTAGE_GRPNAME"] = str(os.getgid()) # Insert our parent dir so we can do shiny import "tests" # This line courtesy of Marienz and Pkgcore ;) diff --git a/lib/portage/util/__init__.py b/lib/portage/util/__init__.py index 154431a53..6bff97fb7 100644 --- a/lib/portage/util/__init__.py +++ b/lib/portage/util/__init__.py @@ -48,6 +48,7 @@ from portage.exception import InvalidAtom, PortageException, FileNotFound, \ from portage.localization import _ from portage.proxy.objectproxy import ObjectProxy from portage.cache.mappings import UserDict +from portage.const import EPREFIX if sys.hexversion >= 0x3000000: _unicode = str @@ -1837,10 +1838,22 @@ def getlibpaths(root, env=None): """ Return a list of paths that are used for library lookups """ if env is None: env = os.environ + + # PREFIX HACK: LD_LIBRARY_PATH isn't portable, and considered + # harmfull, so better not use it. We don't need any host OS lib + # paths either, so do Prefix case. + if EPREFIX != '': + rval = [] + rval.append(EPREFIX + "/usr/lib") + rval.append(EPREFIX + "/lib") + # we don't know the CHOST here, so it's a bit hard to guess + # where GCC's and ld's libs are. Though, GCC's libs should be + # in lib and usr/lib, binutils' libs rarely used + else: # the following is based on the information from ld.so(8) - rval = env.get("LD_LIBRARY_PATH", "").split(":") - rval.extend(read_ld_so_conf(os.path.join(root, "etc", "ld.so.conf"))) - rval.append("/usr/lib") - rval.append("/lib") + rval = env.get("LD_LIBRARY_PATH", "").split(":") + rval.extend(read_ld_so_conf(os.path.join(root, "etc", "ld.so.conf"))) + rval.append("/usr/lib") + rval.append("/lib") return [normalize_path(x) for x in rval if x] diff --git a/lib/portage/util/_dyn_libs/LinkageMapMachO.py b/lib/portage/util/_dyn_libs/LinkageMapMachO.py new file mode 100644 index 000000000..e74f0c5ba --- /dev/null +++ b/lib/portage/util/_dyn_libs/LinkageMapMachO.py @@ -0,0 +1,773 @@ +# Copyright 1998-2019 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +import errno +import logging +import subprocess + +import portage +from portage import _encodings +from portage import _os_merge +from portage import _unicode_decode +from portage import _unicode_encode +from portage.cache.mappings import slot_dict_class +from portage.exception import CommandNotFound +from portage.localization import _ +from portage.util import getlibpaths +from portage.util import grabfile +from portage.util import normalize_path +from portage.util import writemsg_level +from portage.const import EPREFIX + +class LinkageMapMachO(object): + + """Models dynamic linker dependencies.""" + + _needed_aux_key = "NEEDED.MACHO.3" + _installname_map_class = slot_dict_class( + ("consumers", "providers"), prefix="") + + class _obj_properties_class(object): + + __slots__ = ("arch", "needed", "install_name", "alt_paths", + "owner",) + + def __init__(self, arch, needed, install_name, alt_paths, owner): + self.arch = arch + self.needed = needed + self.install_name = install_name + self.alt_paths = alt_paths + self.owner = owner + + def __init__(self, vardbapi): + self._dbapi = vardbapi + self._root = self._dbapi.settings['ROOT'] + self._libs = {} + self._obj_properties = {} + self._obj_key_cache = {} + self._path_key_cache = {} + + def _clear_cache(self): + self._libs.clear() + self._obj_properties.clear() + self._obj_key_cache.clear() + self._path_key_cache.clear() + + def _path_key(self, path): + key = self._path_key_cache.get(path) + if key is None: + key = self._ObjectKey(path, self._root) + self._path_key_cache[path] = key + return key + + def _obj_key(self, path): + key = self._obj_key_cache.get(path) + if key is None: + key = self._ObjectKey(path, self._root) + self._obj_key_cache[path] = key + return key + + class _ObjectKey(object): + + """Helper class used as _obj_properties keys for objects.""" + + __slots__ = ("_key",) + + def __init__(self, obj, root): + """ + This takes a path to an object. + + @param object: path to a file + @type object: string (example: '/usr/bin/bar') + + """ + self._key = self._generate_object_key(obj, root) + + def __hash__(self): + return hash(self._key) + + def __eq__(self, other): + return self._key == other._key + + def _generate_object_key(self, obj, root): + """ + Generate object key for a given object. + + @param object: path to a file + @type object: string (example: '/usr/bin/bar') + @rtype: 2-tuple of types (long, int) if object exists. string if + object does not exist. + @return: + 1. 2-tuple of object's inode and device from a stat call, if object + exists. + 2. realpath of object if object does not exist. + + """ + + os = _os_merge + + try: + _unicode_encode(obj, + encoding=_encodings['merge'], errors='strict') + except UnicodeEncodeError: + # The package appears to have been merged with a + # different value of sys.getfilesystemencoding(), + # so fall back to utf_8 if appropriate. + try: + _unicode_encode(obj, + encoding=_encodings['fs'], errors='strict') + except UnicodeEncodeError: + pass + else: + os = portage.os + + abs_path = os.path.join(root, obj.lstrip(os.sep)) + try: + object_stat = os.stat(abs_path) + except OSError: + # Use the realpath as the key if the file does not exists on the + # filesystem. + return os.path.realpath(abs_path) + # Return a tuple of the device and inode. + return (object_stat.st_dev, object_stat.st_ino) + + def file_exists(self): + """ + Determine if the file for this key exists on the filesystem. + + @rtype: Boolean + @return: + 1. True if the file exists. + 2. False if the file does not exist or is a broken symlink. + + """ + return isinstance(self._key, tuple) + + class _LibGraphNode(_ObjectKey): + __slots__ = ("alt_paths",) + + def __init__(self, key): + """ + Create a _LibGraphNode from an existing _ObjectKey. + This re-uses the _key attribute in order to avoid repeating + any previous stat calls, which helps to avoid potential race + conditions due to inconsistent stat results when the + file system is being modified concurrently. + """ + self._key = key._key + self.alt_paths = set() + + def __str__(self): + return str(sorted(self.alt_paths)) + + def rebuild(self, exclude_pkgs=None, include_file=None, + preserve_paths=None): + """ + Raises CommandNotFound if there are preserved libs + and the scanmacho binary is not available. + + @param exclude_pkgs: A set of packages that should be excluded from + the LinkageMap, since they are being unmerged and their NEEDED + entries are therefore irrelevant and would only serve to corrupt + the LinkageMap. + @type exclude_pkgs: set + @param include_file: The path of a file containing NEEDED entries for + a package which does not exist in the vardbapi yet because it is + currently being merged. + @type include_file: String + @param preserve_paths: Libraries preserved by a package instance that + is currently being merged. They need to be explicitly passed to the + LinkageMap, since they are not registered in the + PreservedLibsRegistry yet. + @type preserve_paths: set + """ + + os = _os_merge + root = self._root + root_len = len(root) - 1 + self._clear_cache() + libs = self._libs + obj_properties = self._obj_properties + + lines = [] + + # Data from include_file is processed first so that it + # overrides any data from previously installed files. + if include_file is not None: + for line in grabfile(include_file): + lines.append((None, include_file, line)) + + aux_keys = [self._needed_aux_key] + can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK) + if can_lock: + self._dbapi.lock() + try: + for cpv in self._dbapi.cpv_all(): + if exclude_pkgs is not None and cpv in exclude_pkgs: + continue + needed_file = self._dbapi.getpath(cpv, + filename=self._needed_aux_key) + for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines(): + lines.append((cpv, needed_file, line)) + finally: + if can_lock: + self._dbapi.unlock() + + # have to call scanmacho for preserved libs here as they aren't + # registered in NEEDED.MACHO.3 files + plibs = {} + if preserve_paths is not None: + plibs.update((x, None) for x in preserve_paths) + if self._dbapi._plib_registry and \ + self._dbapi._plib_registry.hasEntries(): + for cpv, items in \ + self._dbapi._plib_registry.getPreservedLibs().items(): + if exclude_pkgs is not None and cpv in exclude_pkgs: + # These preserved libs will either be unmerged, + # rendering them irrelevant, or they will be + # preserved in the replacement package and are + # already represented via the preserve_paths + # parameter. + continue + plibs.update((x, cpv) for x in items) + if plibs: + args = [os.path.join(EPREFIX or "/", "usr/bin/scanmacho"), "-qF", "%a;%F;%S;%n"] + args.extend(os.path.join(root, x.lstrip("." + os.sep)) \ + for x in plibs) + try: + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + raise CommandNotFound(args[0]) + else: + for l in proc.stdout: + try: + l = _unicode_decode(l, + encoding=_encodings['content'], errors='strict') + except UnicodeDecodeError: + l = _unicode_decode(l, + encoding=_encodings['content'], errors='replace') + writemsg_level(_("\nError decoding characters " \ + "returned from scanmacho: %s\n\n") % (l,), + level=logging.ERROR, noiselevel=-1) + l = l.rstrip("\n") + if not l: + continue + fields = l.split(";") + if len(fields) < 4: + writemsg_level("\nWrong number of fields " + \ + "returned from scanmacho: %s\n\n" % (l,), + level=logging.ERROR, noiselevel=-1) + continue + fields[1] = fields[1][root_len:] + owner = plibs.pop(fields[1], None) + lines.append((owner, "scanmacho", ";".join(fields))) + proc.wait() + proc.stdout.close() + + if plibs: + # Preserved libraries that did not appear in the scanmacho output. + # This is known to happen with statically linked libraries. + # Generate dummy lines for these, so we can assume that every + # preserved library has an entry in self._obj_properties. This + # is important in order to prevent findConsumers from raising + # an unwanted KeyError. + for x, cpv in plibs.items(): + lines.append((cpv, "plibs", ";".join(['', x, '', '', '']))) + + # Share identical frozenset instances when available, + # in order to conserve memory. + frozensets = {} + + for owner, location, l in lines: + l = l.rstrip("\n") + if not l: + continue + fields = l.split(";") + if len(fields) < 4: + writemsg_level(_("\nWrong number of fields " \ + "in %s: %s\n\n") % (location, l), + level=logging.ERROR, noiselevel=-1) + continue + arch = fields[0] + obj = fields[1] + install_name = os.path.normpath(fields[2]) + needed = frozenset(x for x in fields[3].split(",") if x) + needed = frozensets.setdefault(needed, needed) + + obj_key = self._obj_key(obj) + indexed = True + myprops = obj_properties.get(obj_key) + if myprops is None: + indexed = False + myprops = self._obj_properties_class( + arch, needed, install_name, [], owner) + obj_properties[obj_key] = myprops + # All object paths are added into the obj_properties tuple. + myprops.alt_paths.append(obj) + + # Don't index the same file more that once since only one + # set of data can be correct and therefore mixing data + # may corrupt the index (include_file overrides previously + # installed). + if indexed: + continue + + arch_map = libs.get(arch) + if arch_map is None: + arch_map = {} + libs[arch] = arch_map + if install_name: + installname_map = arch_map.get(install_name) + if installname_map is None: + installname_map = self._installname_map_class( + providers=[], consumers=[]) + arch_map[install_name] = installname_map + installname_map.providers.append(obj_key) + for needed_installname in needed: + installname_map = arch_map.get(needed_installname) + if installname_map is None: + installname_map = self._installname_map_class( + providers=[], consumers=[]) + arch_map[needed_installname] = installname_map + installname_map.consumers.append(obj_key) + + for arch, install_names in libs.items(): + for install_name_node in install_names.values(): + install_name_node.providers = tuple(set(install_name_node.providers)) + install_name_node.consumers = tuple(set(install_name_node.consumers)) + + def listBrokenBinaries(self, debug=False): + """ + Find binaries and their needed install_names, which have no providers. + + @param debug: Boolean to enable debug output + @type debug: Boolean + @rtype: dict (example: {'/usr/bin/foo': set(['/usr/lib/libbar.dylib'])}) + @return: The return value is an object -> set-of-install_names mapping, where + object is a broken binary and the set consists of install_names needed by + object that have no corresponding libraries to fulfill the dependency. + + """ + + os = _os_merge + + class _LibraryCache(object): + + """ + Caches properties associated with paths. + + The purpose of this class is to prevent multiple instances of + _ObjectKey for the same paths. + + """ + + def __init__(cache_self): + cache_self.cache = {} + + def get(cache_self, obj): + """ + Caches and returns properties associated with an object. + + @param obj: absolute path (can be symlink) + @type obj: string (example: '/usr/lib/libfoo.dylib') + @rtype: 4-tuple with types + (string or None, string or None, 2-tuple, Boolean) + @return: 4-tuple with the following components: + 1. arch as a string or None if it does not exist, + 2. soname as a string or None if it does not exist, + 3. obj_key as 2-tuple, + 4. Boolean representing whether the object exists. + (example: ('libfoo.1.dylib', (123L, 456L), True)) + + """ + if obj in cache_self.cache: + return cache_self.cache[obj] + else: + obj_key = self._obj_key(obj) + # Check that the library exists on the filesystem. + if obj_key.file_exists(): + # Get the install_name from LinkageMapMachO._obj_properties if + # it exists. Otherwise, None. + obj_props = self._obj_properties.get(obj_key) + if obj_props is None: + arch = None + install_name = None + else: + arch = obj_props.arch + install_name = obj_props.install_name + return cache_self.cache.setdefault(obj, \ + (arch, install_name, obj_key, True)) + else: + return cache_self.cache.setdefault(obj, \ + (None, None, obj_key, False)) + + rValue = {} + cache = _LibraryCache() + providers = self.listProviders() + + # Iterate over all obj_keys and their providers. + for obj_key, install_names in providers.items(): + obj_props = self._obj_properties[obj_key] + arch = obj_props.arch + objs = obj_props.alt_paths + # Iterate over each needed install_name and the set of + # library paths that fulfill the install_name to determine + # if the dependency is broken. + for install_name, libraries in install_names.items(): + # validLibraries is used to store libraries, which + # satisfy install_name, so if no valid libraries are + # found, the install_name is not satisfied for obj_key. + # If unsatisfied, objects associated with obj_key must + # be emerged. + validLibrary = set() # for compat with LinkageMap + cachedArch, cachedInstallname, cachedKey, cachedExists = \ + cache.get(install_name) + # Check that the this library provides the needed soname. Doing + # this, however, will cause consumers of libraries missing + # sonames to be unnecessarily emerged. (eg libmix.so) + if cachedInstallname == install_name and cachedArch == arch: + validLibrary.add(cachedKey) + if debug and cachedKey not in \ + set(map(self._obj_key_cache.get, libraries)): + # XXX This is most often due to soname symlinks not in + # a library's directory. We could catalog symlinks in + # LinkageMap to avoid checking for this edge case here. + print(_("Found provider outside of findProviders:"), \ + install_name, "->", cachedRealpath) + if debug and cachedArch == arch and \ + cachedKey in self._obj_properties: + print(_("Broken symlink or missing/bad install_name:"), \ + install_name, '->', cachedRealpath, \ + "with install_name", cachedInstallname, "but expecting", install_name) + # This conditional checks if there are no libraries to + # satisfy the install_name (empty set). + if not validLibrary: + for obj in objs: + rValue.setdefault(obj, set()).add(install_name) + # If no valid libraries have been found by this + # point, then the install_name does not exist in the + # filesystem, but if there are libraries (from the + # providers mapping), it is likely that soname + # symlinks or the actual libraries are missing or + # broken. Thus those libraries are added to rValue + # in order to emerge corrupt library packages. + for lib in libraries: + rValue.setdefault(lib, set()).add(install_name) + if debug: + if not os.path.isfile(lib): + writemsg_level(_("Missing library:") + " %s\n" % (lib,), + level=logging.DEBUG, + noiselevel=-1) + else: + writemsg_level(_("Possibly missing symlink:") + \ + "%s\n" % (os.path.join(os.path.dirname(lib), soname)), + level=logging.DEBUG, + noiselevel=-1) + return rValue + + def listProviders(self): + """ + Find the providers for all object keys in LinkageMap. + + @rtype: dict (example: + {(123L, 456L): {'libbar.dylib': set(['/lib/libbar.1.5.dylib'])}}) + @return: The return value is an object -> providers mapping, where + providers is a mapping of install_name -> set-of-library-paths returned + from the findProviders method. + + """ + rValue = {} + if not self._libs: + self.rebuild() + # Iterate over all object keys within LinkageMap. + for obj_key in self._obj_properties: + rValue.setdefault(obj_key, self.findProviders(obj_key)) + return rValue + + def isMasterLink(self, obj): + """ + Determine whether an object is a "master" symlink, which means + that its basename is the same as the beginning part of the + install_name and it lacks the install_name's version component. + + Examples: + + install_name | master symlink name + ----------------------------------------------- + libarchive.2.8.4.dylib | libarchive.dylib + (typically the install_name is libarchive.2.dylib) + + @param obj: absolute path to an object + @type obj: string (example: '/usr/bin/foo') + @rtype: Boolean + @return: + 1. True if obj is a master link + 2. False if obj is not a master link + + """ + os = _os_merge + obj_key = self._obj_key(obj) + if obj_key not in self._obj_properties: + raise KeyError("%s (%s) not in object list" % (obj_key, obj)) + basename = os.path.basename(obj) + install_name = self._obj_properties[obj_key].install_name + return (len(basename) < len(os.path.basename(install_name)) and \ + basename.endswith(".dylib") and \ + os.path.basename(install_name).startswith(basename[:-6])) + + def listLibraryObjects(self): + """ + Return a list of library objects. + + Known limitation: library objects lacking an soname are not included. + + @rtype: list of strings + @return: list of paths to all providers + + """ + rValue = [] + if not self._libs: + self.rebuild() + for arch_map in self._libs.values(): + for soname_map in arch_map.values(): + for obj_key in soname_map.providers: + rValue.extend(self._obj_properties[obj_key].alt_paths) + return rValue + + def getOwners(self, obj): + """ + Return the package(s) associated with an object. Raises KeyError + if the object is unknown. Returns an empty tuple if the owner(s) + are unknown. + + NOTE: For preserved libraries, the owner(s) may have been + previously uninstalled, but these uninstalled owners can be + returned by this method since they are registered in the + PreservedLibsRegistry. + + @param obj: absolute path to an object + @type obj: string (example: '/usr/bin/bar') + @rtype: tuple + @return: a tuple of cpv + """ + if not self._libs: + self.rebuild() + if isinstance(obj, self._ObjectKey): + obj_key = obj + else: + obj_key = self._obj_key_cache.get(obj) + if obj_key is None: + raise KeyError("%s not in object list" % obj) + obj_props = self._obj_properties.get(obj_key) + if obj_props is None: + raise KeyError("%s not in object list" % obj_key) + if obj_props.owner is None: + return () + return (obj_props.owner,) + + def getSoname(self, obj): + """ + Return the install_name associated with an object. To match + soname behaviour, the leading path is stripped. + + @param obj: absolute path to an object + @type obj: string (example: '/usr/bin/bar') + @rtype: string + @return: install_name basename as a string + + """ + os = _os_merge + if not self._libs: + self.rebuild() + if isinstance(obj, self._ObjectKey): + obj_key = obj + if obj_key not in self._obj_properties: + raise KeyError("%s not in object list" % obj_key) + return os.path.basename(self._obj_properties[obj_key].install_name) + if obj not in self._obj_key_cache: + raise KeyError("%s not in object list" % obj) + return os.path.basename( + self._obj_properties[self._obj_key_cache[obj]].install_name) + + def findProviders(self, obj): + """ + Find providers for an object or object key. + + This method may be called with a key from _obj_properties. + + In some cases, not all valid libraries are returned. This may occur when + an soname symlink referencing a library is in an object's runpath while + the actual library is not. We should consider cataloging symlinks within + LinkageMap as this would avoid those cases and would be a better model of + library dependencies (since the dynamic linker actually searches for + files named with the soname in the runpaths). + + @param obj: absolute path to an object or a key from _obj_properties + @type obj: string (example: '/usr/bin/bar') or _ObjectKey + @rtype: dict (example: {'libbar.dylib': set(['/lib/libbar.1.5.dylib'])}) + @return: The return value is a install_name -> set-of-library-paths, where + set-of-library-paths satisfy install_name. + + """ + + os = _os_merge + + rValue = {} + + if not self._libs: + self.rebuild() + + # Determine the obj_key from the arguments. + if isinstance(obj, self._ObjectKey): + obj_key = obj + if obj_key not in self._obj_properties: + raise KeyError("%s not in object list" % obj_key) + else: + obj_key = self._obj_key(obj) + if obj_key not in self._obj_properties: + raise KeyError("%s (%s) not in object list" % (obj_key, obj)) + + obj_props = self._obj_properties[obj_key] + arch = obj_props.arch + needed = obj_props.needed + install_name = obj_props.install_name + for install_name in needed: + rValue[install_name] = set() + if arch not in self._libs or install_name not in self._libs[arch]: + continue + # For each potential provider of the install_name, add it to + # rValue if it exists. (Should be one) + for provider_key in self._libs[arch][install_name].providers: + providers = self._obj_properties[provider_key].alt_paths + for provider in providers: + if os.path.exists(provider): + rValue[install_name].add(provider) + return rValue + + def findConsumers(self, obj, exclude_providers=None, greedy=True): + """ + Find consumers of an object or object key. + + This method may be called with a key from _obj_properties. If this + method is going to be called with an object key, to avoid not catching + shadowed libraries, do not pass new _ObjectKey instances to this method. + Instead pass the obj as a string. + + In some cases, not all consumers are returned. This may occur when + an soname symlink referencing a library is in an object's runpath while + the actual library is not. For example, this problem is noticeable for + binutils since it's libraries are added to the path via symlinks that + are gemerated in the /usr/$CHOST/lib/ directory by binutils-config. + Failure to recognize consumers of these symlinks makes preserve-libs + fail to preserve binutils libs that are needed by these unrecognized + consumers. + + Note that library consumption via dlopen (common for kde plugins) is + currently undetected. However, it is possible to use the + corresponding libtool archive (*.la) files to detect such consumers + (revdep-rebuild is able to detect them). + + The exclude_providers argument is useful for determining whether + removal of one or more packages will create unsatisfied consumers. When + this option is given, consumers are excluded from the results if there + is an alternative provider (which is not excluded) of the required + soname such that the consumers will remain satisfied if the files + owned by exclude_providers are removed. + + @param obj: absolute path to an object or a key from _obj_properties + @type obj: string (example: '/usr/bin/bar') or _ObjectKey + @param exclude_providers: A collection of callables that each take a + single argument referring to the path of a library (example: + '/usr/lib/libssl.0.9.8.dylib'), and return True if the library is + owned by a provider which is planned for removal. + @type exclude_providers: collection + @param greedy: If True, then include consumers that are satisfied + by alternative providers, otherwise omit them. Default is True. + @type greedy: Boolean + @rtype: set of strings (example: set(['/bin/foo', '/usr/bin/bar'])) + @return: The return value is a install_name -> set-of-library-paths, where + set-of-library-paths satisfy install_name. + + """ + + os = _os_merge + + if not self._libs: + self.rebuild() + + # Determine the obj_key and the set of objects matching the arguments. + if isinstance(obj, self._ObjectKey): + obj_key = obj + if obj_key not in self._obj_properties: + raise KeyError("%s not in object list" % obj_key) + objs = self._obj_properties[obj_key].alt_paths + else: + objs = set([obj]) + obj_key = self._obj_key(obj) + if obj_key not in self._obj_properties: + raise KeyError("%s (%s) not in object list" % (obj_key, obj)) + + # If there is another version of this lib with the + # same install_name and the install_name symlink points to that + # other version, this lib will be shadowed and won't + # have any consumers. + if not isinstance(obj, self._ObjectKey): + install_name = self._obj_properties[obj_key].install_name + master_link = os.path.join(self._root, + install_name.lstrip(os.path.sep)) + obj_path = os.path.join(self._root, obj.lstrip(os.sep)) + try: + master_st = os.stat(master_link) + obj_st = os.stat(obj_path) + except OSError: + pass + else: + if (obj_st.st_dev, obj_st.st_ino) != \ + (master_st.st_dev, master_st.st_ino): + return set() + + obj_props = self._obj_properties[obj_key] + arch = obj_props.arch + install_name = obj_props.install_name + + install_name_node = None + arch_map = self._libs.get(arch) + if arch_map is not None: + install_name_node = arch_map.get(install_name) + + satisfied_consumer_keys = set() + if install_name_node is not None: + if exclude_providers is not None and not greedy: + relevant_dir_keys = set() + for provider_key in install_name_node.providers: + if not greedy and provider_key == obj_key: + continue + provider_objs = self._obj_properties[provider_key].alt_paths + for p in provider_objs: + provider_excluded = False + if exclude_providers is not None: + for excluded_provider_isowner in exclude_providers: + if excluded_provider_isowner(p): + provider_excluded = True + break + if not provider_excluded: + # This provider is not excluded. It will + # satisfy a consumer of this install_name. + relevant_dir_keys.add(self._path_key(p)) + + if relevant_dir_keys: + for consumer_key in install_name_node.consumers: + satisfied_consumer_keys.add(consumer_key) + + rValue = set() + if install_name_node is not None: + # For each potential consumer, add it to rValue. + for consumer_key in install_name_node.consumers: + if consumer_key in satisfied_consumer_keys: + continue + consumer_props = self._obj_properties[consumer_key] + consumer_objs = consumer_props.alt_paths + rValue.update(consumer_objs) + return rValue diff --git a/lib/portage/util/_dyn_libs/LinkageMapPeCoff.py b/lib/portage/util/_dyn_libs/LinkageMapPeCoff.py new file mode 100644 index 000000000..fd0ab6ee8 --- /dev/null +++ b/lib/portage/util/_dyn_libs/LinkageMapPeCoff.py @@ -0,0 +1,286 @@ +# Copyright 1998-2011 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import errno +import logging +import subprocess + +import portage +from portage import _encodings +from portage import _os_merge +from portage import _unicode_decode +from portage import _unicode_encode +from portage.cache.mappings import slot_dict_class +from portage.exception import CommandNotFound +from portage.localization import _ +from portage.util import getlibpaths +from portage.util import grabfile +from portage.util import normalize_path +from portage.util import writemsg_level +from portage.const import EPREFIX +from portage.util._dyn_libs.LinkageMapELF import LinkageMapELF + +class LinkageMapPeCoff(LinkageMapELF): + + """Models dynamic linker dependencies.""" + + # NEEDED.PECOFF.1 has effectively the _same_ format as NEEDED.ELF.2, + # but we keep up the relation "scanelf" -> "NEEDED.ELF", "readpecoff" -> + # "NEEDED.PECOFF", "scanmacho" -> "NEEDED.MACHO", etc. others will follow. + _needed_aux_key = "NEEDED.PECOFF.1" + + class _ObjectKey(LinkageMapELF._ObjectKey): + + """Helper class used as _obj_properties keys for objects.""" + + def _generate_object_key(self, obj, root): + """ + Generate object key for a given object. This is different from the + Linux implementation, since some systems (e.g. interix) don't have + "inodes", thus the inode field is always zero, or a random value, + making it inappropriate for identifying a file... :) + + @param object: path to a file + @type object: string (example: '/usr/bin/bar') + @rtype: 2-tuple of types (bool, string) + @return: + 2-tuple of boolean indicating existance, and absolut path + """ + + os = _os_merge + + try: + _unicode_encode(obj, + encoding=_encodings['merge'], errors='strict') + except UnicodeEncodeError: + # The package appears to have been merged with a + # different value of sys.getfilesystemencoding(), + # so fall back to utf_8 if appropriate. + try: + _unicode_encode(obj, + encoding=_encodings['fs'], errors='strict') + except UnicodeEncodeError: + pass + else: + os = portage.os + + abs_path = os.path.join(root, obj.lstrip(os.sep)) + try: + object_stat = os.stat(abs_path) + except OSError: + return (False, os.path.realpath(abs_path)) + # On Interix, the inode field may always be zero, since the + # filesystem (NTFS) has no inodes ... + return (True, os.path.realpath(abs_path)) + + def file_exists(self): + """ + Determine if the file for this key exists on the filesystem. + + @rtype: Boolean + @return: + 1. True if the file exists. + 2. False if the file does not exist or is a broken symlink. + + """ + return self._key[0] + + class _LibGraphNode(_ObjectKey): + __slots__ = ("alt_paths",) + + def __init__(self, key): + """ + Create a _LibGraphNode from an existing _ObjectKey. + This re-uses the _key attribute in order to avoid repeating + any previous stat calls, which helps to avoid potential race + conditions due to inconsistent stat results when the + file system is being modified concurrently. + """ + self._key = key._key + self.alt_paths = set() + + def __str__(self): + return str(sorted(self.alt_paths)) + + def rebuild(self, exclude_pkgs=None, include_file=None, + preserve_paths=None): + """ + Raises CommandNotFound if there are preserved libs + and the readpecoff binary is not available. + + @param exclude_pkgs: A set of packages that should be excluded from + the LinkageMap, since they are being unmerged and their NEEDED + entries are therefore irrelevant and would only serve to corrupt + the LinkageMap. + @type exclude_pkgs: set + @param include_file: The path of a file containing NEEDED entries for + a package which does not exist in the vardbapi yet because it is + currently being merged. + @type include_file: String + @param preserve_paths: Libraries preserved by a package instance that + is currently being merged. They need to be explicitly passed to the + LinkageMap, since they are not registered in the + PreservedLibsRegistry yet. + @type preserve_paths: set + """ + + os = _os_merge + root = self._root + root_len = len(root) - 1 + self._clear_cache() + self._defpath.update(getlibpaths(self._root, env=self._dbapi.settings)) + libs = self._libs + obj_properties = self._obj_properties + + lines = [] + + # Data from include_file is processed first so that it + # overrides any data from previously installed files. + if include_file is not None: + for line in grabfile(include_file): + lines.append((None, include_file, line)) + + aux_keys = [self._needed_aux_key] + can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK) + if can_lock: + self._dbapi.lock() + try: + for cpv in self._dbapi.cpv_all(): + if exclude_pkgs is not None and cpv in exclude_pkgs: + continue + needed_file = self._dbapi.getpath(cpv, + filename=self._needed_aux_key) + for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines(): + lines.append((cpv, needed_file, line)) + finally: + if can_lock: + self._dbapi.unlock() + + # have to call readpecoff for preserved libs here as they aren't + # registered in NEEDED.PECOFF.1 files + plibs = {} + if preserve_paths is not None: + plibs.update((x, None) for x in preserve_paths) + if self._dbapi._plib_registry and \ + self._dbapi._plib_registry.hasEntries(): + for cpv, items in \ + self._dbapi._plib_registry.getPreservedLibs().items(): + if exclude_pkgs is not None and cpv in exclude_pkgs: + # These preserved libs will either be unmerged, + # rendering them irrelevant, or they will be + # preserved in the replacement package and are + # already represented via the preserve_paths + # parameter. + continue + plibs.update((x, cpv) for x in items) + if plibs: + args = ["readpecoff", self._dbapi.settings.get('CHOST')] + args.extend(os.path.join(root, x.lstrip("." + os.sep)) \ + for x in plibs) + try: + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + raise CommandNotFound(args[0]) + else: + for l in proc.stdout: + try: + l = _unicode_decode(l, + encoding=_encodings['content'], errors='strict') + except UnicodeDecodeError: + l = _unicode_decode(l, + encoding=_encodings['content'], errors='replace') + writemsg_level(_("\nError decoding characters " \ + "returned from readpecoff: %s\n\n") % (l,), + level=logging.ERROR, noiselevel=-1) + l = l[3:].rstrip("\n") + if not l: + continue + fields = l.split(";") + if len(fields) < 5: + writemsg_level(_("\nWrong number of fields " \ + "returned from readpecoff: %s\n\n") % (l,), + level=logging.ERROR, noiselevel=-1) + continue + fields[1] = fields[1][root_len:] + owner = plibs.pop(fields[1], None) + lines.append((owner, "readpecoff", ";".join(fields))) + proc.wait() + + if plibs: + # Preserved libraries that did not appear in the scanelf output. + # This is known to happen with statically linked libraries. + # Generate dummy lines for these, so we can assume that every + # preserved library has an entry in self._obj_properties. This + # is important in order to prevent findConsumers from raising + # an unwanted KeyError. + for x, cpv in plibs.items(): + lines.append((cpv, "plibs", ";".join(['', x, '', '', '']))) + + # Share identical frozenset instances when available, + # in order to conserve memory. + frozensets = {} + + for owner, location, l in lines: + l = l.rstrip("\n") + if not l: + continue + fields = l.split(";") + if len(fields) < 5: + writemsg_level(_("\nWrong number of fields " \ + "in %s: %s\n\n") % (location, l), + level=logging.ERROR, noiselevel=-1) + continue + arch = fields[0] + obj = fields[1] + soname = fields[2] + path = frozenset(normalize_path(x) \ + for x in filter(None, fields[3].replace( + "${ORIGIN}", os.path.dirname(obj)).replace( + "$ORIGIN", os.path.dirname(obj)).split(":"))) + path = frozensets.setdefault(path, path) + needed = frozenset(x for x in fields[4].split(",") if x) + needed = frozensets.setdefault(needed, needed) + + obj_key = self._obj_key(obj) + indexed = True + myprops = obj_properties.get(obj_key) + if myprops is None: + indexed = False + myprops = self._obj_properties_class( + arch, needed, path, soname, [], owner) + obj_properties[obj_key] = myprops + # All object paths are added into the obj_properties tuple. + myprops.alt_paths.append(obj) + + # Don't index the same file more that once since only one + # set of data can be correct and therefore mixing data + # may corrupt the index (include_file overrides previously + # installed). + if indexed: + continue + + arch_map = libs.get(arch) + if arch_map is None: + arch_map = {} + libs[arch] = arch_map + if soname: + soname_map = arch_map.get(soname) + if soname_map is None: + soname_map = self._soname_map_class( + providers=[], consumers=[]) + arch_map[soname] = soname_map + soname_map.providers.append(obj_key) + for needed_soname in needed: + soname_map = arch_map.get(needed_soname) + if soname_map is None: + soname_map = self._soname_map_class( + providers=[], consumers=[]) + arch_map[needed_soname] = soname_map + soname_map.consumers.append(obj_key) + + for arch, sonames in libs.items(): + for soname_node in sonames.values(): + soname_node.providers = tuple(set(soname_node.providers)) + soname_node.consumers = tuple(set(soname_node.consumers)) diff --git a/lib/portage/util/_dyn_libs/LinkageMapXCoff.py b/lib/portage/util/_dyn_libs/LinkageMapXCoff.py new file mode 100644 index 000000000..6c4c994b5 --- /dev/null +++ b/lib/portage/util/_dyn_libs/LinkageMapXCoff.py @@ -0,0 +1,312 @@ +# Copyright 1998-2011 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import errno +import logging +import subprocess + +import portage +from portage import _encodings +from portage import _os_merge +from portage import _unicode_decode +from portage import _unicode_encode +from portage.cache.mappings import slot_dict_class +from portage.exception import CommandNotFound +from portage.localization import _ +from portage.util import getlibpaths +from portage.util import grabfile +from portage.util import normalize_path +from portage.util import writemsg_level +from portage.const import EPREFIX, BASH_BINARY +from portage.util._dyn_libs.LinkageMapELF import LinkageMapELF + +class LinkageMapXCoff(LinkageMapELF): + + """Models dynamic linker dependencies.""" + + _needed_aux_key = "NEEDED.XCOFF.1" + + class _ObjectKey(LinkageMapELF._ObjectKey): + + def __init__(self, obj, root): + LinkageMapELF._ObjectKey.__init__(self, obj, root) + + def _generate_object_key(self, obj, root): + """ + Generate object key for a given object. + + @param object: path to a file + @type object: string (example: '/usr/bin/bar') + @rtype: 2-tuple of types (long, int) if object exists. string if + object does not exist. + @return: + 1. 2-tuple of object's inode and device from a stat call, if object + exists. + 2. realpath of object if object does not exist. + + """ + + os = _os_merge + + try: + _unicode_encode(obj, + encoding=_encodings['merge'], errors='strict') + except UnicodeEncodeError: + # The package appears to have been merged with a + # different value of sys.getfilesystemencoding(), + # so fall back to utf_8 if appropriate. + try: + _unicode_encode(obj, + encoding=_encodings['fs'], errors='strict') + except UnicodeEncodeError: + pass + else: + os = portage.os + + abs_path = os.path.join(root, obj.lstrip(os.sep)) + try: + object_stat = os.stat(abs_path) + except OSError: + # Use the realpath as the key if the file does not exists on the + # filesystem. + return os.path.realpath(abs_path) + # Return a tuple of the device and inode, as well as the basename, + # because of hardlinks (notably for the .libNAME[shr.o] helpers) + # the device and inode might be identical. + return (object_stat.st_dev, object_stat.st_ino, os.path.basename(abs_path.rstrip(os.sep))) + + class _LibGraphNode(_ObjectKey): + __slots__ = ("alt_paths",) + + def __init__(self, key): + """ + Create a _LibGraphNode from an existing _ObjectKey. + This re-uses the _key attribute in order to avoid repeating + any previous stat calls, which helps to avoid potential race + conditions due to inconsistent stat results when the + file system is being modified concurrently. + """ + self._key = key._key + self.alt_paths = set() + + def __str__(self): + return str(sorted(self.alt_paths)) + + def rebuild(self, exclude_pkgs=None, include_file=None, + preserve_paths=None): + """ + Raises CommandNotFound if there are preserved libs + and the scanelf binary is not available. + + @param exclude_pkgs: A set of packages that should be excluded from + the LinkageMap, since they are being unmerged and their NEEDED + entries are therefore irrelevant and would only serve to corrupt + the LinkageMap. + @type exclude_pkgs: set + @param include_file: The path of a file containing NEEDED entries for + a package which does not exist in the vardbapi yet because it is + currently being merged. + @type include_file: String + @param preserve_paths: Libraries preserved by a package instance that + is currently being merged. They need to be explicitly passed to the + LinkageMap, since they are not registered in the + PreservedLibsRegistry yet. + @type preserve_paths: set + """ + + os = _os_merge + root = self._root + root_len = len(root) - 1 + self._clear_cache() + self._defpath.update(getlibpaths(self._root, env=self._dbapi.settings)) + libs = self._libs + obj_properties = self._obj_properties + + lines = [] + + # Data from include_file is processed first so that it + # overrides any data from previously installed files. + if include_file is not None: + for line in grabfile(include_file): + lines.append((None, include_file, line)) + + aux_keys = [self._needed_aux_key] + can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK) + if can_lock: + self._dbapi.lock() + try: + for cpv in self._dbapi.cpv_all(): + if exclude_pkgs is not None and cpv in exclude_pkgs: + continue + needed_file = self._dbapi.getpath(cpv, + filename=self._needed_aux_key) + for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines(): + lines.append((cpv, needed_file, line)) + finally: + if can_lock: + self._dbapi.unlock() + + # have to call scanelf for preserved libs here as they aren't + # registered in NEEDED.XCOFF.1 files + plibs = {} + if preserve_paths is not None: + plibs.update((x, None) for x in preserve_paths) + if self._dbapi._plib_registry and \ + self._dbapi._plib_registry.hasEntries(): + for cpv, items in \ + self._dbapi._plib_registry.getPreservedLibs().items(): + if exclude_pkgs is not None and cpv in exclude_pkgs: + # These preserved libs will either be unmerged, + # rendering them irrelevant, or they will be + # preserved in the replacement package and are + # already represented via the preserve_paths + # parameter. + continue + plibs.update((x, cpv) for x in items) + if plibs: + args = [BASH_BINARY , "-c" , ':' + + '; for member in "$@"' + + '; do archive=${member}' + + '; if [[ ${member##*/} == .*"["*"]" ]]' + + '; then member=${member%/.*}/${member##*/.}' + + '; archive=${member%[*}' + + '; fi' + + '; member=${member#${archive}}' + + '; [[ -r ${archive} ]] || chmod a+r "${archive}"' + + '; eval $(aixdll-query "${archive}${member}" FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS)' + + '; [[ -n ${member} ]] && needed=${FILE##*/} || needed=' + + '; for deplib in ${DEPLIBS}' + + '; do eval deplib=${deplib}' + + '; if [[ ${deplib} != "." && ${deplib} != ".." ]]' + + '; then needed="${needed}${needed:+,}${deplib}"' + + '; fi' + + '; done' + + '; [[ -n ${MEMBER} ]] && MEMBER="[${MEMBER}]"' + + '; [[ " ${FLAGS} " == *" SHROBJ "* ]] && soname=${FILE##*/}${MEMBER} || soname=' + + '; case ${member:+y}:${MEMBER:+y}' + # member requested, member found: show shared archive member + + ' in y:y) echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}}${MEMBER};${soname};${RUNPATH};${needed}"' + # no member requested, member found: show archive + + ' ;; :y) echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}};${FILE##*/};;"' + # no member requested, no member found: show standalone shared object + + ' ;; : ) echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}};${FILE##*/};${RUNPATH};${needed}"' + # member requested, no member found: ignore archive replaced by standalone shared object + + ' ;; y: )' + + ' ;; esac' + + '; done' + , 'aixdll-query' + ] + args.extend(os.path.join(root, x.lstrip("." + os.sep)) \ + for x in plibs) + try: + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + raise CommandNotFound(args[0]) + else: + for l in proc.stdout: + try: + l = _unicode_decode(l, + encoding=_encodings['content'], errors='strict') + except UnicodeDecodeError: + l = _unicode_decode(l, + encoding=_encodings['content'], errors='replace') + writemsg_level(_("\nError decoding characters " \ + "returned from aixdll-query: %s\n\n") % (l,), + level=logging.ERROR, noiselevel=-1) + l = l.rstrip("\n") + if not l: + continue + fields = l.split(";") + if len(fields) < 5: + writemsg_level(_("\nWrong number of fields " \ + "returned from aixdll-query: %s\n\n") % (l,), + level=logging.ERROR, noiselevel=-1) + continue + fields[1] = fields[1][root_len:] + owner = plibs.pop(fields[1], None) + lines.append((owner, "aixdll-query", ";".join(fields))) + proc.wait() + proc.stdout.close() + + # Share identical frozenset instances when available, + # in order to conserve memory. + frozensets = {} + + for owner, location, l in lines: + l = l.rstrip("\n") + if not l: + continue + fields = l.split(";") + if len(fields) < 5: + writemsg_level(_("\nWrong number of fields " \ + "in %s: %s\n\n") % (location, l), + level=logging.ERROR, noiselevel=-1) + continue + arch = fields[0] + + def as_contentmember(obj): + if obj.endswith("]"): + if obj.find("/") >= 0: + if obj[obj.rfind("/")+1] == ".": + return obj + return obj[:obj.rfind("/")] + "/." + obj[obj.rfind("/")+1:] + if obj[0] == ".": + return obj + return "." + obj + return obj + + obj = as_contentmember(fields[1]) + soname = as_contentmember(fields[2]) + path = frozenset(normalize_path(x) \ + for x in filter(None, fields[3].replace( + "${ORIGIN}", os.path.dirname(obj)).replace( + "$ORIGIN", os.path.dirname(obj)).split(":"))) + path = frozensets.setdefault(path, path) + needed = frozenset(as_contentmember(x) for x in fields[4].split(",") if x) + needed = frozensets.setdefault(needed, needed) + + obj_key = self._obj_key(obj) + indexed = True + myprops = obj_properties.get(obj_key) + if myprops is None: + indexed = False + myprops = self._obj_properties_class( + arch, needed, path, soname, [], owner) + obj_properties[obj_key] = myprops + # All object paths are added into the obj_properties tuple. + myprops.alt_paths.append(obj) + + # Don't index the same file more that once since only one + # set of data can be correct and therefore mixing data + # may corrupt the index (include_file overrides previously + # installed). + if indexed: + continue + + arch_map = libs.get(arch) + if arch_map is None: + arch_map = {} + libs[arch] = arch_map + if soname: + soname_map = arch_map.get(soname) + if soname_map is None: + soname_map = self._soname_map_class( + providers=[], consumers=[]) + arch_map[soname] = soname_map + soname_map.providers.append(obj_key) + for needed_soname in needed: + soname_map = arch_map.get(needed_soname) + if soname_map is None: + soname_map = self._soname_map_class( + providers=[], consumers=[]) + arch_map[needed_soname] = soname_map + soname_map.consumers.append(obj_key) + + for arch, sonames in libs.items(): + for soname_node in sonames.values(): + soname_node.providers = tuple(set(soname_node.providers)) + soname_node.consumers = tuple(set(soname_node.consumers)) + + pass diff --git a/lib/portage/util/_info_files.py b/lib/portage/util/_info_files.py index fabf74b0f..de44b0fdc 100644 --- a/lib/portage/util/_info_files.py +++ b/lib/portage/util/_info_files.py @@ -9,16 +9,17 @@ import subprocess import portage from portage import os +from portage.const import EPREFIX def chk_updated_info_files(root, infodirs, prev_mtimes): - if os.path.exists("/usr/bin/install-info"): + if os.path.exists(EPREFIX + "/usr/bin/install-info"): out = portage.output.EOutput() regen_infodirs = [] for z in infodirs: if z == '': continue - inforoot = portage.util.normalize_path(root + z) + inforoot = portage.util.normalize_path(root + EPREFIX + z) if os.path.isdir(inforoot) and \ not [x for x in os.listdir(inforoot) \ if x.startswith('.keepinfodir')]: @@ -78,7 +79,7 @@ def chk_updated_info_files(root, infodirs, prev_mtimes): processed_count += 1 try: proc = subprocess.Popen( - ['/usr/bin/install-info', + ['%s/usr/bin/install-info' % EPREFIX, '--dir-file=%s' % os.path.join(inforoot, "dir"), os.path.join(inforoot, x)], env=dict(os.environ, LANG="C", LANGUAGE="C"), diff --git a/lib/portage/util/_pty.py b/lib/portage/util/_pty.py index 11c8b92af..a92f57543 100644 --- a/lib/portage/util/_pty.py +++ b/lib/portage/util/_pty.py @@ -9,12 +9,12 @@ from portage import os from portage.output import get_term_size, set_term_size from portage.util import writemsg -# Disable the use of openpty on Solaris as it seems Python's openpty -# implementation doesn't play nice on Solaris with Portage's -# behaviour causing hangs/deadlocks. +# Disable the use of openpty on Solaris (and others) as it seems Python's +# openpty implementation doesn't play nice with Portage's behaviour, +# causing hangs/deadlocks. # Additional note for the future: on Interix, pipes do NOT work, so # _disable_openpty on Interix must *never* be True -_disable_openpty = platform.system() in ("SunOS",) +_disable_openpty = platform.system() in ("AIX","FreeMiNT","HP-UX","SunOS",) _fbsd_test_pty = platform.system() == 'FreeBSD' diff --git a/lib/portage/util/env_update.py b/lib/portage/util/env_update.py index 032101043..a69114d80 100644 --- a/lib/portage/util/env_update.py +++ b/lib/portage/util/env_update.py @@ -88,7 +88,7 @@ def _env_update(makelinks, target_root, prev_mtimes, contents, env, else: settings = env - eprefix = settings.get("EPREFIX", "") + eprefix = settings.get("EPREFIX", portage.const.EPREFIX) eprefix_lstrip = eprefix.lstrip(os.sep) eroot = normalize_path(os.path.join(target_root, eprefix_lstrip)).rstrip(os.sep) + os.sep envd_dir = os.path.join(eroot, "etc", "env.d") @@ -340,8 +340,8 @@ def _env_update(makelinks, target_root, prev_mtimes, contents, env, penvnotice = "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" penvnotice += "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" cenvnotice = penvnotice[:] - penvnotice += "# GO INTO /etc/profile NOT /etc/profile.env\n\n" - cenvnotice += "# GO INTO /etc/csh.cshrc NOT /etc/csh.env\n\n" + penvnotice += "# GO INTO " + eprefix + "/etc/profile NOT /etc/profile.env\n\n" + cenvnotice += "# GO INTO " + eprefix + "/etc/csh.cshrc NOT /etc/csh.env\n\n" #create /etc/profile.env for bash support outfile = atomic_ofstream(os.path.join(eroot, "etc", "profile.env")) diff --git a/lib/portage/versions.py b/lib/portage/versions.py index 0c21373cc..0b1d50e7c 100644 --- a/lib/portage/versions.py +++ b/lib/portage/versions.py @@ -51,7 +51,9 @@ _pkg = { } _v = r'(\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)' -_rev = r'\d+' +# PREFIX_LOCAL hack: -r(\d+) -> -r(\d+|\d+\.\d+) (see below) +_rev = r'(\d+|\d+\.\d+)' +# END_PREFIX_LOCAL _vr = _v + '(-r(' + _rev + '))?' _cp = { @@ -250,15 +252,47 @@ def vercmp(ver1, ver2, silent=1): if rval: return rval - # the suffix part is equal to, so finally check the revision + # PREFIX_LOCAL + # The suffix part is equal too, so finally check the revision + # Prefix hack: historically a revision starting with 0 was an + # 'inter-revision', which means that it is possible to create + # revisions on revisions. An example is -r01.1 which is the + # first revision of -r1. Note that a period (.) is used to + # separate the real revision and the secondary revision number. + # In the current state, the leading 0 is no longer used, and + # versions just can have a dot, which means the version is an + # inter-revision. + # This trick is in use to allow revision bumps in ebuilds synced + # from the main tree for Prefix changes, while still staying in + # the main tree versioning scheme. As such it can be used in + # any other overlay where ebuilds from the another tree are + # shadowed. if match1.group(9): - r1 = int(match1.group(9)) + if '.' in match1.group(9): + t = match1.group(9).split(".") + r1 = int(t[0]) + r3 = int(t[1]) + else: + r1 = int(match1.group(9)) + r3 = 0 else: r1 = 0 + r3 = 0 if match2.group(9): - r2 = int(match2.group(9)) + if '.' in match2.group(9): + t = match2.group(9).split(".") + r2 = int(t[0]) + r4 = int(t[1]) + else: + r2 = int(match2.group(9)) + r4 = 0 + # END_PREFIX_LOCAL else: r2 = 0 + r4 = 0 + if r1 == r2 and (r3 != 0 or r4 != 0): + r1 = r3 + r2 = r4 rval = (r1 > r2) - (r1 < r2) return rval diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 000000000..4034c99ba --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,17 @@ +SHELL = @PORTAGE_BASH@ + +man_MANS = \ + color.map.5 \ + dispatch-conf.1 \ + ebuild.1 \ + ebuild.5 \ + egencache.1 \ + emaint.1 \ + emerge.1 \ + env-update.1 \ + etc-update.1 \ + make.conf.5 \ + portage.5 \ + quickpkg.1 + +EXTRA_DIST = $(man_MANS) diff --git a/man/ebuild.5 b/man/ebuild.5 index e955907f7..4ca3f3a15 100644 --- a/man/ebuild.5 +++ b/man/ebuild.5 @@ -852,6 +852,12 @@ characters. This variable is intended to be used on files of binary packages which ignore CFLAGS, CXXFLAGS, FFLAGS, FCFLAGS, and LDFLAGS variables. .TP +.B QA_IGNORE_INSTALL_NAME_FILES +This should contain a list of file names (without path) that should be +ignored in the install_name check. That is, if these files point to +something not available in the image directory or live filesystem, these +files are ignored, albeit being broken. +.TP .B QA_MULTILIB_PATHS This should contain a list of file paths, relative to the image directory, of files that should be ignored for the multilib\-strict checks. diff --git a/man/emerge.1 b/man/emerge.1 index 28b7f79f5..aa28ab337 100644 --- a/man/emerge.1 +++ b/man/emerge.1 @@ -1410,6 +1410,12 @@ add this to \fBmake.conf\fR(5): Tools such as dispatch\-conf, cfg\-update, and etc\-update are also available to aid in the merging of these files. They provide interactive merging and can auto\-merge trivial changes. +.LP +When an offset prefix (\fBEPREFIX\fR) is active, all paths in +\fBCONFIG_PROTECT\fR and \fBCONFIG_PROTECT_MASK\fR are prefixed with the +offset by Portage before they are considered. Hence, these paths never +contain the offset prefix, and the variables can be defined in +offset-unaware locations, such as the profiles. .SH "REPORTING BUGS" Please report any bugs you encounter through our website: .LP @@ -1429,6 +1435,7 @@ Marius Mauch <genone@gentoo.org> Jason Stubbs <jstubbs@gentoo.org> Brian Harring <ferringb@gmail.com> Zac Medico <zmedico@gentoo.org> +Fabian Groffen <grobian@gentoo.org> Arfrever Frehtes Taifersar Arahesis <arfrever@apache.org> .fi .SH "FILES" diff --git a/man/make.conf.5 b/man/make.conf.5 index a3bd662ae..ab00cb7d7 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -193,6 +193,9 @@ Defaults to "/lib/modules/* *.py[co]". All files and/or directories that are defined here will have "config file protection" enabled for them. See the \fBCONFIGURATION FILES\fR section of \fBemerge\fR(1) for more information. +Note that if an offset prefix (\fBEPREFIX\fR) is activated, all paths defined +in \fBCONFIG_PROTECT\fR are prefixed by Portage with the offset before +they are used. .TP \fBCONFIG_PROTECT_MASK\fR = \fI[space delimited list of files and/or \ directories]\fR @@ -613,6 +616,9 @@ dependencies. .TP .B sandbox Enable sandbox\-ing when running \fBemerge\fR(1) and \fBebuild\fR(1). +On Mac OS X platforms that have /usr/bin/sandbox-exec available (10.5 +and later), this particular sandbox implementation is used instead of +sys-apps/sandbox. .TP .B sesandbox Enable SELinux sandbox\-ing. Do not toggle this \fBFEATURE\fR yourself. diff --git a/misc/emerge-delta-webrsync b/misc/emerge-delta-webrsync index 082e15e52..d459a2386 100755 --- a/misc/emerge-delta-webrsync +++ b/misc/emerge-delta-webrsync @@ -1,4 +1,4 @@ -#!/bin/bash +#!@PORTAGE_BASH@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # Author: Brian Harring <ferringb@gentoo.org>, karltk@gentoo.org originally. @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # Copyright 2010-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # diff --git a/subst-install.in b/subst-install.in new file mode 100644 index 000000000..e9f375d76 --- /dev/null +++ b/subst-install.in @@ -0,0 +1,74 @@ +#!@PORTAGE_BASH@ + +# for expansion below we need some things to be defined +prefix="@prefix@" +exec_prefix="@exec_prefix@" + +# For bug #279550 we have to do some nasty trick to make sure that sed +# doesn't strip the backslash in the replacement value (because it can +# be a backreference) and hence escape those. Eventually in strings we +# need to escape the backslash too, such that the single backslash +# doesn't get lost when considered an invalid escape +rootuser='@rootuser@' +portagegroup='@portagegroup@' +portageuser='@portageuser@' +rootuser=${rootuser//\\/\\\\} +portagegroup=${portagegroup//\\/\\\\\\\\} +portageuser=${portageuser//\\/\\\\\\\\} + +# there are many ways to do this all dynamic, but we only care for raw +# speed here, so let configure fill in this list and be done with it +at='@' +sedexp=( + -e "s,${at}EXTRA_PATH${at},@EXTRA_PATH@,g" + -e "s,${at}PORTAGE_BASE${at},@PORTAGE_BASE@,g" + -e "s,${at}PORTAGE_BASH${at},@PORTAGE_BASH@,g" + -e "s,${at}PORTAGE_EPREFIX${at},@PORTAGE_EPREFIX@,g" + -e "s,${at}PORTAGE_MV${at},@PORTAGE_MV@,g" + -e "s,${at}PREFIX_PORTAGE_PYTHON${at},@PREFIX_PORTAGE_PYTHON@,g" + -e "s,${at}datadir${at},@datadir@,g" + -e "s,${at}portagegroup${at},${portagegroup},g" + -e "s,${at}portageuser${at},${portageuser},g" + -e "s,${at}rootgid${at},@rootgid@,g" + -e "s,${at}rootuid${at},@rootuid@,g" + -e "s,${at}rootuser${at},${rootuser},g" + -e "s,${at}sysconfdir${at},@sysconfdir@,g" +) + +sources=( ) +target= +args=( "$@" ) + +while [[ ${#@} != 0 ]] ; do + case "$1" in + -t) + [[ -n ${target} ]] && sources=( "${sources[@]}" "${target##*/}" ) + shift + target=":${1}" + ;; + -*) + shift + ;; + *) + if [[ -z ${target} ]] ; then + target="${1}" + elif [[ ${target} != ":"* ]] ; then + sources=( "${sources[@]}" "${target##*/}" ) + target="${1}" + else + sources=( "${sources[@]}" "${1##*/}" ) + fi + ;; + esac + shift +done + +target=${target#:} +INSTALL="@INSTALL@" +echo @INSTALL_DATA@ "${args[@]}" +if [[ ! -d ${target} ]] ; then + # either install will die, or it was just a single file copy + @INSTALL_DATA@ "${args[@]}" && sed -i "${sedexp[@]}" "${target}" +else + @INSTALL_DATA@ "${args[@]}" && sed -i "${sedexp[@]}" "${sources[@]/#/${target}/}" +fi diff --git a/tabcheck.py b/tabcheck.py index a28ad93d9..fe5227ca7 100755 --- a/tabcheck.py +++ b/tabcheck.py @@ -1,6 +1,7 @@ -#!/usr/bin/python -b +#!/usr/bin/env python import tabnanny,sys for x in sys.argv: + print ("Tabchecking " + x) tabnanny.check(x) diff --git a/tarball.sh b/tarball.sh new file mode 100755 index 000000000..e67e7244c --- /dev/null +++ b/tarball.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +if [ -z "$1" ]; then + echo + echo "You need to have the version specified." + echo "e.g.: $0 2.0.39-r37" + echo + exit 0 +fi + +export PKG="prefix-portage" +export TMP="/var/tmp" +export V="$1" +export DEST="${TMP}/${PKG}-${V}" + +if [[ -e ${DEST} ]]; then + echo ${DEST} already exists, please remove first + exit 1 +fi + +./tabcheck.py $( + find ./ -name .git -o -name .hg -prune -o -type f ! -name '*.py' -print \ + | xargs grep -l "#\!@PREFIX_PORTAGE_PYTHON@" \ + | grep -v "^\./repoman/" + find ./ -name .git -o -name .hg -prune -o -type f -name '*.py' -print \ + | grep -v "^\./repoman/" + +) + +install -d -m0755 ${DEST} +rsync -a --exclude='.git' --exclude='.hg' --exclude="repoman/" . ${DEST} +sed -i -e '/^VERSION\s*=/s/^.*$/VERSION = "'${V}-prefix'"/' \ + ${DEST}/lib/portage/__init__.py +sed -i -e "/version = /s/'[^']\+'/'${V}-prefix'/" ${DEST}/setup.py +sed -i -e "1s/VERSION/${V}-prefix/" ${DEST}/man/{,ru/}*.[15] +sed -i -e "s/@version@/${V}/" ${DEST}/configure.ac + +cd ${DEST} +find -name '*~' | xargs --no-run-if-empty rm -f +find -name '*.pyc' | xargs --no-run-if-empty rm -f +find -name '*.pyo' | xargs --no-run-if-empty rm -f +cd $TMP +rm -f \ + ${PKG}-${V}/bin/emerge.py \ + ${PKG}-${V}/bin/{pmake,sandbox} \ + ${PKG}-${V}/{bin,lib}/'.#'* \ + ${PKG}-${V}/{bin,lib}/*.{orig,diff} \ + ${PKG}-${V}/{bin,lib}/*.py[oc] +cd $TMP/${PKG}-${V} +chmod a+x autogen.sh && ./autogen.sh || { echo "autogen failed!"; exit -1; }; +rm -f autogen.sh tabcheck.py tarball.sh commit +cd $TMP +tar --numeric-owner -jcf ${TMP}/${PKG}-${V}.tar.bz2 ${PKG}-${V} +rm -R ${TMP}/${PKG}-${V} +ls -la ${TMP}/${PKG}-${V}.tar.bz2 diff --git a/travis.sh b/travis.sh new file mode 100755 index 000000000..bcb95a9cb --- /dev/null +++ b/travis.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# this script runs the tests as Travis would do (.travis.yml) and can be +# used to test the Prefix branch of portage on a non-Prefix system + +: ${TMPDIR=/var/tmp} + +HERE=$(dirname $(realpath ${BASH_SOURCE[0]})) +REPO=${HERE##*/}.$$ + +cd ${TMPDIR} +git clone ${HERE} ${REPO} + +cd ${REPO} +printf "[build_ext]\nportage-ext-modules=true" >> setup.cfg +find . -type f -exec \ + sed -e "s|@PORTAGE_EPREFIX@||" \ + -e "s|@PORTAGE_BASE@|${PWD}|" \ + -e "s|@PORTAGE_MV@|$(type -P mv)|" \ + -e "s|@PORTAGE_BASH@|$(type -P bash)|" \ + -e "s|@PREFIX_PORTAGE_PYTHON@|$(type -P python)|" \ + -e "s|@EXTRA_PATH@|${EPREFIX}/usr/sbin:${EPREFIX}/sbin|" \ + -e "s|@portagegroup@|$(id -gn)|" \ + -e "s|@portageuser@|$(id -un)|" \ + -e "s|@rootuser@|$(id -un)|" \ + -e "s|@rootuid@|$(id -u)|" \ + -e "s|@rootgid@|$(id -g)|" \ + -e "s|@sysconfdir@|${EPREFIX}/etc|" \ + -i '{}' + +unset EPREFIX +./setup.py test |