Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not export PMS variables in EAPI 9 #1407

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions bin/isolated-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ if ___eapi_has_version_functions; then
source "${PORTAGE_BIN_PATH}/eapi7-ver-funcs.sh" || exit 1
fi

if [[ -v PORTAGE_EBUILD_EXTRA_SOURCE ]]; then
source "${PORTAGE_EBUILD_EXTRA_SOURCE}" || exit 1
# We deliberately do not unset PORTABE_EBUILD_EXTRA_SOURCE, so
# that it keeps being exported in the environment of this
# process and its child processes. There, for example portage
# helper like doins, can pick it up and set the PMS variables
# (usually by sourcing isolated-functions.sh).
fi

# We need this next line for "die" and "assert". It expands
# It _must_ preceed all the calls to die and assert.
shopt -s expand_aliases
Expand Down
13 changes: 13 additions & 0 deletions bin/phase-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ PORTAGE_READONLY_VARS="D EBUILD EBUILD_PHASE EBUILD_PHASE_FUNC \
PORTAGE_BUILD_USER PORTAGE_BUNZIP2_COMMAND \
PORTAGE_BZIP2_COMMAND PORTAGE_COLORMAP PORTAGE_CONFIGROOT \
PORTAGE_DEBUG PORTAGE_DEPCACHEDIR PORTAGE_EBUILD_EXIT_FILE \
PORTAGE_EBUILD_EXTRA_SOURCE \
PORTAGE_ECLASS_LOCATIONS PORTAGE_EXPLICIT_INHERIT \
PORTAGE_GID PORTAGE_GRPNAME PORTAGE_INST_GID PORTAGE_INST_UID \
PORTAGE_INTERNAL_CALLER PORTAGE_IPC_DAEMON PORTAGE_IUSE PORTAGE_LOG_FILE \
Expand Down Expand Up @@ -962,6 +963,18 @@ __ebuild_main() {
export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)}
trap 'exit 1' SIGTERM

if [[ -v PORTAGE_EBUILD_EXTRA_SOURCE &&
${PORTAGE_EBUILD_EXTRA_SOURCE} != ${T}/* ]]; then
# Cleanup PORTAGE_EBUILD_EXTRA_SOURCE after ebuild.sh
# (__ebuild_main()) finishes if PORTAGE_EBUILD_EXTRA_SOURCE is
# not under T.
__portage_ebuild_exit() {
rm "${PORTAGE_EBUILD_EXTRA_SOURCE}" ||
die "failed to remove PORTAGE_EBUILD_EXTRA_SOURCE file (${PORTAGE_EBUILD_EXTRA_SOURCE})"
}
trap __portage_ebuild_exit EXIT
fi

Flowdalic marked this conversation as resolved.
Show resolved Hide resolved
# A reasonable default for ${S}
[[ -z ${S} ]] && export S=${WORKDIR}/${P}

Expand Down
2 changes: 1 addition & 1 deletion cnf/make.globals
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ FEATURES="assume-digests binpkg-docompress binpkg-dostrip binpkg-logs
network-sandbox news parallel-fetch pkgdir-index-trusted pid-sandbox
preserve-libs protect-owned qa-unresolved-soname-deps sandbox strict
unknown-features-warn unmerge-logs unmerge-orphans userfetch
userpriv usersandbox usersync"
userpriv usersandbox usersync export-pms-vars"

# Ignore file collisions in /lib/modules since files inside this directory
# are never unmerged, and therefore collisions must be ignored in order for
Expand Down
7 changes: 7 additions & 0 deletions lib/_emerge/EbuildMetadataPhase.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class EbuildMetadataPhase(SubProcess):
"repo_path",
"settings",
"deallocate_config",
"portage_ebuild_extra_source",
"write_auxdb",
) + (
"_eapi",
Expand Down Expand Up @@ -165,6 +166,10 @@ def _async_start_done(self, future):
self.cancel()
self._was_cancelled()

self.portage_ebuild_extra_source = self.settings.get(
"PORTAGE_EBUILD_EXTRA_SOURCE"
)

if self.deallocate_config is not None and not self.deallocate_config.done():
self.deallocate_config.set_result(self.settings)

Expand All @@ -191,6 +196,8 @@ def _unregister(self):
if self._files is not None:
self.scheduler.remove_reader(self._files.ebuild)
SubProcess._unregister(self)
if self.portage_ebuild_extra_source:
os.unlink(self.portage_ebuild_extra_source)

def _async_waitpid_cb(self, *args, **kwargs):
"""
Expand Down
1 change: 1 addition & 0 deletions lib/portage/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
"distlocks",
"downgrade-backup",
"ebuild-locks",
"export-pms-vars",
"fail-clean",
"fakeroot",
"fixlafiles",
Expand Down
8 changes: 8 additions & 0 deletions lib/portage/eapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ def eapi_supports_prefix(eapi: str) -> bool:
return _get_eapi_attrs(eapi).prefix


def eapi_exports_pms_vars(eapi: str) -> bool:
return _get_eapi_attrs(eapi).exports_pms_vars


def eapi_exports_AA(eapi: str) -> bool:
return _get_eapi_attrs(eapi).exports_AA

Expand Down Expand Up @@ -157,6 +161,7 @@ def eapi_has_sysroot(eapi: str) -> bool:
"exports_ECLASSDIR",
"exports_KV",
"exports_merge_type",
"exports_pms_vars",
"exports_PORTDIR",
"exports_replace_vars",
"feature_flag_test",
Expand Down Expand Up @@ -197,6 +202,7 @@ class Eapi:
"6",
"7",
"8",
"9",
)

_eapi_val: int = -1
Expand Down Expand Up @@ -235,6 +241,7 @@ def _get_eapi_attrs(eapi_str: Optional[str]) -> _eapi_attrs:
exports_ECLASSDIR=False,
exports_KV=False,
exports_merge_type=True,
exports_pms_vars=True,
exports_PORTDIR=True,
exports_replace_vars=True,
feature_flag_test=False,
Expand Down Expand Up @@ -274,6 +281,7 @@ def _get_eapi_attrs(eapi_str: Optional[str]) -> _eapi_attrs:
exports_ECLASSDIR=eapi <= Eapi("6"),
exports_KV=eapi <= Eapi("3"),
exports_merge_type=eapi >= Eapi("4"),
exports_pms_vars=eapi <= Eapi("8"),
exports_PORTDIR=eapi <= Eapi("6"),
exports_replace_vars=eapi >= Eapi("4"),
feature_flag_test=False,
Expand Down
132 changes: 131 additions & 1 deletion lib/portage/package/ebuild/doebuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
from portage.eapi import (
eapi_exports_KV,
eapi_exports_merge_type,
eapi_exports_pms_vars,
eapi_exports_replace_vars,
eapi_has_required_use,
eapi_has_src_prepare_and_src_configure,
Expand Down Expand Up @@ -189,6 +190,57 @@
"RESTRICT",
)

# The following is a set of PMS § 11.1 and § 7.4 without
# - TMPDIR
# - HOME
# because these variables are often assumed to be exported and
# therefore consumed by child processes.
_unexported_pms_vars = frozenset(
# fmt: off
[
# PMS § 11.1 Defined Variables
"P",
"PF",
"PN",
"CATEGORY",
"PV",
"PR",
"PVR",
"A",
"AA",
"FILESDIR",
"DISTDIR",
"WORKDIR",
"S",
"PORTDIR",
"ECLASSDIR",
"ROOT",
"EROOT",
"SYSROOT",
"ESYSROOT",
"BROOT",
"T",
# "TMPDIR", # EXPORTED: often assumed to be exported and available to child processes
# "HOME", # EXPORTED: often assumed to be exported and available to child processes
"EPREFIX",
"D",
"ED",
"DESTTREE",
"INSDESTTREE",
"EBUILD_PHASE",
"EBUILD_PHASE_FUNC",
"KV",
"MERGE_TYPE",
"REPLACING_VERSIONS",
"REPLACED_BY_VERSION",
# PMS § 7.4 Magic Ebuild-defined Variables
"ECLASS",
"INHERITED",
"DEFINED_PHASES",
]
# fmt: on
)


def _doebuild_spawn(phase, settings, actionmap=None, **kwargs):
"""
Expand Down Expand Up @@ -1922,6 +1974,8 @@ def __init__(self, mydb):
# XXX This would be to replace getstatusoutput completely.
# XXX Issue: cannot block execution. Deadlock condition.

_emerge_tmpdir = None


def spawn(
mystring,
Expand Down Expand Up @@ -2133,9 +2187,85 @@ def spawn(
logname_backup = mysettings.configdict["env"].get("LOGNAME")
mysettings.configdict["env"]["LOGNAME"] = logname

eapi = mysettings["EAPI"]

unexported_env_vars = None
if "export-pms-vars" not in mysettings.features or not eapi_exports_pms_vars(eapi):
unexported_env_vars = _unexported_pms_vars

if unexported_env_vars:
# Starting with EAPI 9 (or if FEATURES="-export-pms-vars"),
# PMS variables should not longer be exported.

phase = mysettings.get("EBUILD_PHASE")
is_pms_ebuild_phase = phase in _phase_func_map.keys()
# 'None' phase is MiscFunctionsProcess, e.g., where the qa checks run
is_ebuild_phase_with_t = phase in [None, "package", "instprep"]
# Copy the environment since we are removing the PMS variables from it.
env = mysettings.environ().copy()

# There are three cases to consider when it comes to managing
# the life cycle of the PORTAGE_EBUILD_EXTRA_SOURCE file we
# are going to create now.
# A) phase function with T available (potentially unprivileged)
# B) privileged phase function
# C) phase=depend (potentially unprivileged with T unavailable and __ebuild_main not called)
#
# Case A is easy to solve, since we shove
# PORTAGE_EBUILD_EXTRA_SOURCE simply in T which will
# eventually get claned any way.
# Case B requires that we use an extra temp directory to store
# PORTAGE_EBUILD_EXTRA_SOURCE. We install an EXIT trap in
# __ebuild_main() that will remove PORTAGE_EBUILD_EXTRA_SOURCE
# once ebuild.sh finishes.
# Case C requires that delete PORTAGE_EBUILD_EXTRA_SOURCE once
# the depend phase for that ebuild finished. This is done in
# EbuildMetadataPhase._unregister().
if is_pms_ebuild_phase or is_ebuild_phase_with_t: # case A
t = env["T"]
ebuild_extra_source_path = os.path.join(
t, f".portage-ebuild-extra-source-{phase}"
)
else: # case B and C
global _emerge_tmpdir
if _emerge_tmpdir is None:
_emerge_tmpdir = tempfile.mkdtemp(
prefix=f"portage-tmpdir-{portage.getpid()}-"
)
Flowdalic marked this conversation as resolved.
Show resolved Hide resolved
os.chmod(_emerge_tmpdir, 0o1775)
os.chown(_emerge_tmpdir, -1, int(portage_gid))
portage.process.atexit_register(shutil.rmtree, _emerge_tmpdir)
ebuild_extra_source_fd, ebuild_extra_source_path = tempfile.mkstemp(
prefix=f"portage-ebuild-extra-source-{phase}-",
dir=_emerge_tmpdir,
)
zmedico marked this conversation as resolved.
Show resolved Hide resolved
try:
# Make sure that the file can be writen by us (done below)
# and that it is world readable.
os.fchmod(ebuild_extra_source_fd, 0o644)
finally:
os.close(ebuild_extra_source_fd)
if phase == "depend": # case C
# The file will be deleted by EbuildMetadataPhase._unregister()
mysettings["PORTAGE_EBUILD_EXTRA_SOURCE"] = ebuild_extra_source_path

with open(ebuild_extra_source_path, mode="w") as f:
for var_name in unexported_env_vars:
var_value = mysettings.environ().get(var_name)
if var_value is None:
continue
quoted_var_value = shlex.quote(var_value)
f.write(f"{var_name}={quoted_var_value}\n")
del env[var_name]

env["PORTAGE_EBUILD_EXTRA_SOURCE"] = str(ebuild_extra_source_path)
else:
# Pre EAPI 9 behavior, all PMS variables are simply exported into the ebuild's environment.
env = mysettings.environ()

try:
if keywords.get("returnpid") or keywords.get("returnproc"):
return spawn_func(mystring, env=mysettings.environ(), **keywords)
return spawn_func(mystring, env=env, **keywords)

proc = EbuildSpawnProcess(
background=False,
Expand Down
Loading