1 |
Since variables like A and AA can contain extremely large values which |
2 |
may trigger E2BIG errors during attempts to execute subprocesses, delay |
3 |
export until the last moment, and unexport when appropriate. |
4 |
|
5 |
Bug: https://bugs.gentoo.org/720180 |
6 |
Signed-off-by: Zac Medico <zmedico@g.o> |
7 |
--- |
8 |
bin/eapi.sh | 9 +++++ |
9 |
bin/isolated-functions.sh | 34 ++++++++++++++++ |
10 |
bin/phase-functions.sh | 13 +++++++ |
11 |
.../ebuild/_config/special_env_vars.py | 7 +++- |
12 |
lib/portage/package/ebuild/config.py | 39 ++++++++++++++----- |
13 |
5 files changed, 91 insertions(+), 11 deletions(-) |
14 |
|
15 |
diff --git a/bin/eapi.sh b/bin/eapi.sh |
16 |
index 29dfb008c..f56468e4a 100644 |
17 |
--- a/bin/eapi.sh |
18 |
+++ b/bin/eapi.sh |
19 |
@@ -26,6 +26,15 @@ ___eapi_has_S_WORKDIR_fallback() { |
20 |
|
21 |
# VARIABLES |
22 |
|
23 |
+___eapi_exports_A() { |
24 |
+ # https://bugs.gentoo.org/721088 |
25 |
+ true |
26 |
+} |
27 |
+ |
28 |
+___eapi_exports_AA() { |
29 |
+ [[ ${1-${EAPI-0}} =~ ^(0|1|2|3)$ ]] |
30 |
+} |
31 |
+ |
32 |
___eapi_has_prefix_variables() { |
33 |
[[ ! ${1-${EAPI-0}} =~ ^(0|1|2)$ || " ${FEATURES} " == *" force-prefix "* ]] |
34 |
} |
35 |
diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh |
36 |
index fde684013..973450d86 100644 |
37 |
--- a/bin/isolated-functions.sh |
38 |
+++ b/bin/isolated-functions.sh |
39 |
@@ -107,6 +107,39 @@ __bashpid() { |
40 |
sh -c 'echo ${PPID}' |
41 |
} |
42 |
|
43 |
+# @FUNCTION: ___eapi_vars_export |
44 |
+# @DESCRIPTION: |
45 |
+# Export variables for the current EAPI. Calls to this function should |
46 |
+# be delayed until the last moment, since exporting these variables |
47 |
+# may trigger E2BIG errors suring attempts to execute subprocesses. |
48 |
+___eapi_vars_export() { |
49 |
+ source "${T}/environment.unexported" || die |
50 |
+ |
51 |
+ if ___eapi_exports_A; then |
52 |
+ export A |
53 |
+ fi |
54 |
+ |
55 |
+ if ___eapi_exports_AA; then |
56 |
+ export AA |
57 |
+ fi |
58 |
+} |
59 |
+ |
60 |
+# @FUNCTION: ___eapi_vars_unexport |
61 |
+# @DESCRIPTION: |
62 |
+# Unexport variables that were exported for the current EAPI. This |
63 |
+# function should be called after an ebuild phase, in order to unexport |
64 |
+# variables that may trigger E2BIG errors during attempts to execute |
65 |
+# subprocesses. |
66 |
+___eapi_vars_unexport() { |
67 |
+ if ___eapi_exports_A; then |
68 |
+ export -n A |
69 |
+ fi |
70 |
+ |
71 |
+ if ___eapi_exports_AA; then |
72 |
+ export -n AA |
73 |
+ fi |
74 |
+} |
75 |
+ |
76 |
__helpers_die() { |
77 |
if ___eapi_helpers_can_die && [[ ${PORTAGE_NONFATAL} != 1 ]]; then |
78 |
die "$@" |
79 |
@@ -122,6 +155,7 @@ die() { |
80 |
|
81 |
set +x # tracing only produces useless noise here |
82 |
local IFS=$' \t\n' |
83 |
+ ___eapi_vars_unexport |
84 |
|
85 |
if ___eapi_die_can_respect_nonfatal && [[ $1 == -n ]]; then |
86 |
shift |
87 |
diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh |
88 |
index 90e622e75..df2c0d8de 100644 |
89 |
--- a/bin/phase-functions.sh |
90 |
+++ b/bin/phase-functions.sh |
91 |
@@ -146,6 +146,7 @@ __filter_readonly_variables() { |
92 |
fi |
93 |
fi |
94 |
|
95 |
+ ___eapi_vars_unexport |
96 |
"${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${filtered_vars}" || die "filter-bash-environment.py failed" |
97 |
} |
98 |
|
99 |
@@ -212,6 +213,7 @@ __ebuild_phase() { |
100 |
|
101 |
__ebuild_phase_with_hooks() { |
102 |
local x phase_name=${1} |
103 |
+ ___eapi_vars_export |
104 |
for x in {pre_,,post_}${phase_name} ; do |
105 |
__ebuild_phase ${x} |
106 |
done |
107 |
@@ -223,6 +225,7 @@ __dyn_pretend() { |
108 |
__vecho ">>> Remove '$PORTAGE_BUILDDIR/.pretended' to force pretend." |
109 |
return 0 |
110 |
fi |
111 |
+ ___eapi_vars_export |
112 |
__ebuild_phase pre_pkg_pretend |
113 |
__ebuild_phase pkg_pretend |
114 |
>> "$PORTAGE_BUILDDIR/.pretended" || \ |
115 |
@@ -236,6 +239,7 @@ __dyn_setup() { |
116 |
__vecho ">>> Remove '$PORTAGE_BUILDDIR/.setuped' to force setup." |
117 |
return 0 |
118 |
fi |
119 |
+ ___eapi_vars_export |
120 |
__ebuild_phase pre_pkg_setup |
121 |
__ebuild_phase pkg_setup |
122 |
>> "$PORTAGE_BUILDDIR/.setuped" || \ |
123 |
@@ -252,6 +256,7 @@ __dyn_unpack() { |
124 |
install -m${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'" |
125 |
fi |
126 |
cd "${WORKDIR}" || die "Directory change failed: \`cd '${WORKDIR}'\`" |
127 |
+ ___eapi_vars_export |
128 |
__ebuild_phase pre_src_unpack |
129 |
__vecho ">>> Unpacking source..." |
130 |
__ebuild_phase src_unpack |
131 |
@@ -386,6 +391,7 @@ __dyn_prepare() { |
132 |
|
133 |
trap __abort_prepare SIGINT SIGQUIT |
134 |
|
135 |
+ ___eapi_vars_export |
136 |
__ebuild_phase pre_src_prepare |
137 |
__vecho ">>> Preparing source in $PWD ..." |
138 |
__ebuild_phase src_prepare |
139 |
@@ -423,6 +429,7 @@ __dyn_configure() { |
140 |
|
141 |
trap __abort_configure SIGINT SIGQUIT |
142 |
|
143 |
+ ___eapi_vars_export |
144 |
__ebuild_phase pre_src_configure |
145 |
|
146 |
__vecho ">>> Configuring source in $PWD ..." |
147 |
@@ -456,6 +463,7 @@ __dyn_compile() { |
148 |
|
149 |
trap __abort_compile SIGINT SIGQUIT |
150 |
|
151 |
+ ___eapi_vars_export |
152 |
__ebuild_phase pre_src_compile |
153 |
|
154 |
__vecho ">>> Compiling source in $PWD ..." |
155 |
@@ -500,6 +508,7 @@ __dyn_test() { |
156 |
else |
157 |
local save_sp=${SANDBOX_PREDICT} |
158 |
addpredict / |
159 |
+ ___eapi_vars_export |
160 |
__ebuild_phase pre_src_test |
161 |
|
162 |
__vecho ">>> Test phase: ${CATEGORY}/${PF}" |
163 |
@@ -553,6 +562,7 @@ __dyn_install() { |
164 |
eval "[[ -n \$QA_PRESTRIPPED_${ARCH/-/_} ]] && \ |
165 |
export QA_PRESTRIPPED_${ARCH/-/_}" |
166 |
|
167 |
+ ___eapi_vars_export |
168 |
__ebuild_phase pre_src_install |
169 |
|
170 |
if ___eapi_has_prefix_variables; then |
171 |
@@ -695,6 +705,7 @@ __dyn_install() { |
172 |
--filter-path --filter-sandbox --allow-extra-vars > \ |
173 |
"${PORTAGE_BUILDDIR}"/build-info/environment |
174 |
assert "__save_ebuild_env failed" |
175 |
+ ___eapi_vars_unexport |
176 |
cd "${PORTAGE_BUILDDIR}"/build-info || die |
177 |
|
178 |
${PORTAGE_BZIP2_COMMAND} -f9 environment |
179 |
@@ -1087,11 +1098,13 @@ __ebuild_main() { |
180 |
__save_ebuild_env | __filter_readonly_variables \ |
181 |
--filter-features > "$T/environment" |
182 |
assert "__save_ebuild_env failed" |
183 |
+ ___eapi_vars_unexport |
184 |
chgrp "${PORTAGE_GRPNAME:-portage}" "$T/environment" |
185 |
chmod g+w "$T/environment" |
186 |
fi |
187 |
[[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE" |
188 |
if [[ -n $PORTAGE_IPC_DAEMON ]] ; then |
189 |
+ ___eapi_vars_unexport |
190 |
[[ ! -s $SANDBOX_LOG ]] |
191 |
"$PORTAGE_BIN_PATH"/ebuild-ipc exit $? |
192 |
fi |
193 |
diff --git a/lib/portage/package/ebuild/_config/special_env_vars.py b/lib/portage/package/ebuild/_config/special_env_vars.py |
194 |
index 440dd00b2..92824e15f 100644 |
195 |
--- a/lib/portage/package/ebuild/_config/special_env_vars.py |
196 |
+++ b/lib/portage/package/ebuild/_config/special_env_vars.py |
197 |
@@ -89,7 +89,7 @@ environ_whitelist += [ |
198 |
] |
199 |
|
200 |
environ_whitelist += [ |
201 |
- "A", "AA", "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR" |
202 |
+ "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR" |
203 |
] |
204 |
|
205 |
# misc variables inherited from the calling environment |
206 |
@@ -124,6 +124,10 @@ environ_whitelist = frozenset(environ_whitelist) |
207 |
|
208 |
environ_whitelist_re = re.compile(r'^(CCACHE_|DISTCC_).*') |
209 |
|
210 |
+environ_unexported = frozenset([ |
211 |
+ 'A', 'AA', |
212 |
+]) |
213 |
+ |
214 |
# Filter selected variables in the config.environ() method so that |
215 |
# they don't needlessly propagate down into the ebuild environment. |
216 |
environ_filter = [] |
217 |
@@ -131,6 +135,7 @@ environ_filter = [] |
218 |
# Exclude anything that could be extremely long here (like SRC_URI) |
219 |
# since that could cause execve() calls to fail with E2BIG errors. For |
220 |
# example, see bug #262647. |
221 |
+environ_filter.extend(environ_unexported) |
222 |
environ_filter += [ |
223 |
'DEPEND', 'RDEPEND', 'PDEPEND', 'SRC_URI', |
224 |
] |
225 |
diff --git a/lib/portage/package/ebuild/config.py b/lib/portage/package/ebuild/config.py |
226 |
index 47c180c12..a386dc031 100644 |
227 |
--- a/lib/portage/package/ebuild/config.py |
228 |
+++ b/lib/portage/package/ebuild/config.py |
229 |
@@ -10,6 +10,7 @@ __all__ = [ |
230 |
import copy |
231 |
from itertools import chain |
232 |
import grp |
233 |
+import io |
234 |
import logging |
235 |
import platform |
236 |
import pwd |
237 |
@@ -29,7 +30,7 @@ portage.proxy.lazyimport.lazyimport(globals(), |
238 |
'portage.util.locale:check_locale,split_LC_ALL', |
239 |
) |
240 |
from portage import bsd_chflags, \ |
241 |
- load_mod, os, selinux, _unicode_decode |
242 |
+ load_mod, os, selinux, _encodings, _unicode_decode |
243 |
from portage.const import CACHE_PATH, \ |
244 |
DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \ |
245 |
MODULES_FILE_PATH, PORTAGE_BASE_PATH, \ |
246 |
@@ -2755,14 +2756,36 @@ class config(object): |
247 |
eapi_attrs = _get_eapi_attrs(eapi) |
248 |
phase = self.get('EBUILD_PHASE') |
249 |
emerge_from = self.get('EMERGE_FROM') |
250 |
+ temp_dir = None |
251 |
filter_calling_env = False |
252 |
if self.mycpv is not None and \ |
253 |
- not (emerge_from == 'ebuild' and phase == 'setup') and \ |
254 |
+ 'PORTAGE_BUILDDIR_LOCKED' in self and \ |
255 |
phase not in ('clean', 'cleanrm', 'depend', 'fetch'): |
256 |
- temp_dir = self.get('T') |
257 |
- if temp_dir is not None and \ |
258 |
- os.path.exists(os.path.join(temp_dir, 'environment')): |
259 |
- filter_calling_env = True |
260 |
+ temp_dir = self['T'] |
261 |
+ # These variables will exported by ebuild.sh if appropriate |
262 |
+ # for the current EAPI, but export is delayed since large |
263 |
+ # values may trigger E2BIG errors during attempts to spawn |
264 |
+ # subprocesses. |
265 |
+ unexported = [] |
266 |
+ for key in special_env_vars.environ_unexported: |
267 |
+ # Don't export AA for EAPIs that forbid it. |
268 |
+ if key == 'AA' and not eapi_exports_AA(eapi): |
269 |
+ continue |
270 |
+ value = self.get(key) |
271 |
+ if value is not None: |
272 |
+ unexported.append((key, value)) |
273 |
+ |
274 |
+ # Write this file even if it's empty, so that ebuild.sh can |
275 |
+ # rely on its existence. |
276 |
+ with io.open(os.path.join(temp_dir, 'environment.unexported'), |
277 |
+ mode='wt', encoding=_encodings['repo.content']) as f: |
278 |
+ for key, value in unexported: |
279 |
+ f.write('%s="%s"\n' % (key, value.replace('"', '\\"'))) |
280 |
+ |
281 |
+ if temp_dir is not None and \ |
282 |
+ not (emerge_from == 'ebuild' and phase == 'setup') and \ |
283 |
+ os.path.exists(os.path.join(temp_dir, 'environment')): |
284 |
+ filter_calling_env = True |
285 |
|
286 |
environ_whitelist = self._environ_whitelist |
287 |
for x, myvalue in self.iteritems(): |
288 |
@@ -2805,10 +2828,6 @@ class config(object): |
289 |
# Filtered by IUSE and implicit IUSE. |
290 |
mydict["USE"] = self.get("PORTAGE_USE", "") |
291 |
|
292 |
- # Don't export AA to the ebuild environment in EAPIs that forbid it |
293 |
- if not eapi_exports_AA(eapi): |
294 |
- mydict.pop("AA", None) |
295 |
- |
296 |
if not eapi_exports_merge_type(eapi): |
297 |
mydict.pop("MERGE_TYPE", None) |
298 |
|
299 |
-- |
300 |
2.25.3 |