Add QA_AM_MAINTAINER_MODE for bug #450278.
[portage.git] / pym / portage / package / ebuild / doebuild.py
1 # Copyright 2010-2013 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 __all__ = ['doebuild', 'doebuild_environment', 'spawn', 'spawnebuild']
5
6 import grp
7 import gzip
8 import errno
9 import io
10 from itertools import chain
11 import logging
12 import os as _os
13 import pwd
14 import re
15 import signal
16 import stat
17 import sys
18 import tempfile
19 from textwrap import wrap
20 import time
21 import warnings
22 import zlib
23
24 import portage
25 portage.proxy.lazyimport.lazyimport(globals(),
26         'portage.package.ebuild.config:check_config_instance',
27         'portage.package.ebuild.digestcheck:digestcheck',
28         'portage.package.ebuild.digestgen:digestgen',
29         'portage.package.ebuild.fetch:fetch',
30         'portage.package.ebuild._ipc.QueryCommand:QueryCommand',
31         'portage.dep._slot_operator:evaluate_slot_operator_equal_deps',
32         'portage.package.ebuild._spawn_nofetch:spawn_nofetch',
33         'portage.util._desktop_entry:validate_desktop_entry',
34         'portage.util._async.SchedulerInterface:SchedulerInterface',
35         'portage.util._eventloop.EventLoop:EventLoop',
36         'portage.util._eventloop.global_event_loop:global_event_loop',
37         'portage.util.ExtractKernelVersion:ExtractKernelVersion'
38 )
39
40 from portage import auxdbkeys, bsd_chflags, \
41         eapi_is_supported, merge, os, selinux, shutil, \
42         unmerge, _encodings, _os_merge, \
43         _shell_quote, _unicode_decode, _unicode_encode
44 from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \
45         EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY
46 from portage.data import portage_gid, portage_uid, secpass, \
47         uid, userpriv_groups
48 from portage.dbapi.porttree import _parse_uri_map
49 from portage.dep import Atom, check_required_use, \
50         human_readable_required_use, paren_enclose, use_reduce
51 from portage.eapi import eapi_exports_KV, eapi_exports_merge_type, \
52         eapi_exports_replace_vars, eapi_exports_REPOSITORY, \
53         eapi_has_required_use, eapi_has_src_prepare_and_src_configure, \
54         eapi_has_pkg_pretend, _get_eapi_attrs
55 from portage.elog import elog_process, _preload_elog_modules
56 from portage.elog.messages import eerror, eqawarn
57 from portage.exception import DigestException, FileNotFound, \
58         IncorrectParameter, InvalidDependString, PermissionDenied, \
59         UnsupportedAPIException
60 from portage.localization import _
61 from portage.output import colormap
62 from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
63 from portage.util import apply_recursive_permissions, \
64         apply_secpass_permissions, noiselimit, normalize_path, \
65         writemsg, writemsg_stdout, write_atomic
66 from portage.util.lafilefixer import rewrite_lafile     
67 from portage.versions import _pkgsplit
68 from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
69 from _emerge.EbuildBuildDir import EbuildBuildDir
70 from _emerge.EbuildPhase import EbuildPhase
71 from _emerge.EbuildSpawnProcess import EbuildSpawnProcess
72 from _emerge.Package import Package
73 from _emerge.RootConfig import RootConfig
74
75 _unsandboxed_phases = frozenset([
76         "clean", "cleanrm", "config",
77         "help", "info", "postinst",
78         "preinst", "pretend", "postrm",
79         "prerm", "setup"
80 ])
81
82 _phase_func_map = {
83         "config": "pkg_config",
84         "setup": "pkg_setup",
85         "nofetch": "pkg_nofetch",
86         "unpack": "src_unpack",
87         "prepare": "src_prepare",
88         "configure": "src_configure",
89         "compile": "src_compile",
90         "test": "src_test",
91         "install": "src_install",
92         "preinst": "pkg_preinst",
93         "postinst": "pkg_postinst",
94         "prerm": "pkg_prerm",
95         "postrm": "pkg_postrm",
96         "info": "pkg_info",
97         "pretend": "pkg_pretend",
98 }
99
100 _vdb_use_conditional_keys = Package._dep_keys + \
101         ('LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',)
102
103 def _doebuild_spawn(phase, settings, actionmap=None, **kwargs):
104         """
105         All proper ebuild phases which execute ebuild.sh are spawned
106         via this function. No exceptions.
107         """
108
109         if phase in _unsandboxed_phases:
110                 kwargs['free'] = True
111
112         if phase == 'depend':
113                 kwargs['droppriv'] = 'userpriv' in settings.features
114                 # It's not necessary to close_fds for this phase, since
115                 # it should not spawn any daemons, and close_fds is
116                 # best avoided since it can interact badly with some
117                 # garbage collectors (see _setup_pipes docstring).
118                 kwargs['close_fds'] = False
119
120         if actionmap is not None and phase in actionmap:
121                 kwargs.update(actionmap[phase]["args"])
122                 cmd = actionmap[phase]["cmd"] % phase
123         else:
124                 if phase == 'cleanrm':
125                         ebuild_sh_arg = 'clean'
126                 else:
127                         ebuild_sh_arg = phase
128
129                 cmd = "%s %s" % (_shell_quote(
130                         os.path.join(settings["PORTAGE_BIN_PATH"],
131                         os.path.basename(EBUILD_SH_BINARY))),
132                         ebuild_sh_arg)
133
134         settings['EBUILD_PHASE'] = phase
135         try:
136                 return spawn(cmd, settings, **kwargs)
137         finally:
138                 settings.pop('EBUILD_PHASE', None)
139
140 def _spawn_phase(phase, settings, actionmap=None, **kwargs):
141         if kwargs.get('returnpid'):
142                 return _doebuild_spawn(phase, settings, actionmap=actionmap, **kwargs)
143
144         ebuild_phase = EbuildPhase(actionmap=actionmap, background=False,
145                 phase=phase, scheduler=SchedulerInterface(portage._internal_caller and
146                         global_event_loop() or EventLoop(main=False)),
147                 settings=settings)
148         ebuild_phase.start()
149         ebuild_phase.wait()
150         return ebuild_phase.returncode
151
152 def _doebuild_path(settings, eapi=None):
153         """
154         Generate the PATH variable.
155         """
156
157         # Note: PORTAGE_BIN_PATH may differ from the global constant
158         # when portage is reinstalling itself.
159         portage_bin_path = settings["PORTAGE_BIN_PATH"]
160         eprefix = settings["EPREFIX"]
161         prerootpath = [x for x in settings.get("PREROOTPATH", "").split(":") if x]
162         rootpath = [x for x in settings.get("ROOTPATH", "").split(":") if x]
163
164         prefixes = []
165         if eprefix:
166                 prefixes.append(eprefix)
167         prefixes.append("/")
168
169         path = []
170
171         if eprefix and uid != 0 and "fakeroot" not in settings.features:
172                 path.append(os.path.join(portage_bin_path,
173                         "ebuild-helpers", "unprivileged"))
174
175         if settings.get("USERLAND", "GNU") != "GNU":
176                 path.append(os.path.join(portage_bin_path, "ebuild-helpers", "bsd"))
177
178         path.append(os.path.join(portage_bin_path, "ebuild-helpers"))
179         path.extend(prerootpath)
180
181         for prefix in prefixes:
182                 for x in ("usr/local/sbin", "usr/local/bin", "usr/sbin", "usr/bin", "sbin", "bin"):
183                         path.append(os.path.join(prefix, x))
184
185         path.extend(rootpath)
186         settings["PATH"] = ":".join(path)
187
188 def doebuild_environment(myebuild, mydo, myroot=None, settings=None,
189         debug=False, use_cache=None, db=None):
190         """
191         Create and store environment variable in the config instance
192         that's passed in as the "settings" parameter. This will raise
193         UnsupportedAPIException if the given ebuild has an unsupported
194         EAPI. All EAPI dependent code comes last, so that essential
195         variables like PORTAGE_BUILDDIR are still initialized even in
196         cases when UnsupportedAPIException needs to be raised, which
197         can be useful when uninstalling a package that has corrupt
198         EAPI metadata.
199         The myroot and use_cache parameters are unused.
200         """
201         myroot = None
202         use_cache = None
203
204         if settings is None:
205                 raise TypeError("settings argument is required")
206
207         if db is None:
208                 raise TypeError("db argument is required")
209
210         mysettings = settings
211         mydbapi = db
212         ebuild_path = os.path.abspath(myebuild)
213         pkg_dir     = os.path.dirname(ebuild_path)
214         mytree = os.path.dirname(os.path.dirname(pkg_dir))
215         mypv = os.path.basename(ebuild_path)[:-7]
216         mysplit = _pkgsplit(mypv, eapi=mysettings.configdict["pkg"].get("EAPI"))
217         if mysplit is None:
218                 raise IncorrectParameter(
219                         _("Invalid ebuild path: '%s'") % myebuild)
220
221         if mysettings.mycpv is not None and \
222                 mysettings.configdict["pkg"].get("PF") == mypv and \
223                 "CATEGORY" in mysettings.configdict["pkg"]:
224                 # Assume that PF is enough to assume that we've got
225                 # the correct CATEGORY, though this is not really
226                 # a solid assumption since it's possible (though
227                 # unlikely) that two packages in different
228                 # categories have the same PF. Callers should call
229                 # setcpv or create a clean clone of a locked config
230                 # instance in order to ensure that this assumption
231                 # does not fail like in bug #408817.
232                 cat = mysettings.configdict["pkg"]["CATEGORY"]
233                 mycpv = mysettings.mycpv
234         elif os.path.basename(pkg_dir) in (mysplit[0], mypv):
235                 # portdbapi or vardbapi
236                 cat = os.path.basename(os.path.dirname(pkg_dir))
237                 mycpv = cat + "/" + mypv
238         else:
239                 raise AssertionError("unable to determine CATEGORY")
240
241         # Make a backup of PORTAGE_TMPDIR prior to calling config.reset()
242         # so that the caller can override it.
243         tmpdir = mysettings["PORTAGE_TMPDIR"]
244
245         if mydo == 'depend':
246                 if mycpv != mysettings.mycpv:
247                         # Don't pass in mydbapi here since the resulting aux_get
248                         # call would lead to infinite 'depend' phase recursion.
249                         mysettings.setcpv(mycpv)
250         else:
251                 # If EAPI isn't in configdict["pkg"], it means that setcpv()
252                 # hasn't been called with the mydb argument, so we have to
253                 # call it here (portage code always calls setcpv properly,
254                 # but api consumers might not).
255                 if mycpv != mysettings.mycpv or \
256                         "EAPI" not in mysettings.configdict["pkg"]:
257                         # Reload env.d variables and reset any previous settings.
258                         mysettings.reload()
259                         mysettings.reset()
260                         mysettings.setcpv(mycpv, mydb=mydbapi)
261
262         # config.reset() might have reverted a change made by the caller,
263         # so restore it to its original value. Sandbox needs canonical
264         # paths, so realpath it.
265         mysettings["PORTAGE_TMPDIR"] = os.path.realpath(tmpdir)
266
267         mysettings.pop("EBUILD_PHASE", None) # remove from backupenv
268         mysettings["EBUILD_PHASE"] = mydo
269
270         # Set requested Python interpreter for Portage helpers.
271         mysettings['PORTAGE_PYTHON'] = portage._python_interpreter
272
273         # This is used by assert_sigpipe_ok() that's used by the ebuild
274         # unpack() helper. SIGPIPE is typically 13, but its better not
275         # to assume that.
276         mysettings['PORTAGE_SIGPIPE_STATUS'] = str(128 + signal.SIGPIPE)
277
278         # We are disabling user-specific bashrc files.
279         mysettings["BASH_ENV"] = INVALID_ENV_FILE
280
281         if debug: # Otherwise it overrides emerge's settings.
282                 # We have no other way to set debug... debug can't be passed in
283                 # due to how it's coded... Don't overwrite this so we can use it.
284                 mysettings["PORTAGE_DEBUG"] = "1"
285
286         mysettings["EBUILD"]   = ebuild_path
287         mysettings["O"]        = pkg_dir
288         mysettings.configdict["pkg"]["CATEGORY"] = cat
289         mysettings["FILESDIR"] = pkg_dir+"/files"
290         mysettings["PF"]       = mypv
291
292         if hasattr(mydbapi, 'repositories'):
293                 repo = mydbapi.repositories.get_repo_for_location(mytree)
294                 mysettings['PORTDIR'] = repo.eclass_db.porttrees[0]
295                 mysettings['PORTDIR_OVERLAY'] = ' '.join(repo.eclass_db.porttrees[1:])
296                 mysettings.configdict["pkg"]["PORTAGE_REPO_NAME"] = repo.name
297
298         mysettings["PORTDIR"] = os.path.realpath(mysettings["PORTDIR"])
299         mysettings["DISTDIR"] = os.path.realpath(mysettings["DISTDIR"])
300         mysettings["RPMDIR"]  = os.path.realpath(mysettings["RPMDIR"])
301
302         mysettings["ECLASSDIR"]   = mysettings["PORTDIR"]+"/eclass"
303         mysettings["SANDBOX_LOG"] = mycpv.replace("/", "_-_")
304
305         mysettings["PROFILE_PATHS"] = "\n".join(mysettings.profiles)
306         mysettings["P"]  = mysplit[0]+"-"+mysplit[1]
307         mysettings["PN"] = mysplit[0]
308         mysettings["PV"] = mysplit[1]
309         mysettings["PR"] = mysplit[2]
310
311         if noiselimit < 0:
312                 mysettings["PORTAGE_QUIET"] = "1"
313
314         if mysplit[2] == "r0":
315                 mysettings["PVR"]=mysplit[1]
316         else:
317                 mysettings["PVR"]=mysplit[1]+"-"+mysplit[2]
318
319         # All temporary directories should be subdirectories of
320         # $PORTAGE_TMPDIR/portage, since it's common for /tmp and /var/tmp
321         # to be mounted with the "noexec" option (see bug #346899).
322         mysettings["BUILD_PREFIX"] = mysettings["PORTAGE_TMPDIR"]+"/portage"
323         mysettings["PKG_TMPDIR"]   = mysettings["BUILD_PREFIX"]+"/._unmerge_"
324
325         # Package {pre,post}inst and {pre,post}rm may overlap, so they must have separate
326         # locations in order to prevent interference.
327         if mydo in ("unmerge", "prerm", "postrm", "cleanrm"):
328                 mysettings["PORTAGE_BUILDDIR"] = os.path.join(
329                         mysettings["PKG_TMPDIR"],
330                         mysettings["CATEGORY"], mysettings["PF"])
331         else:
332                 mysettings["PORTAGE_BUILDDIR"] = os.path.join(
333                         mysettings["BUILD_PREFIX"],
334                         mysettings["CATEGORY"], mysettings["PF"])
335
336         mysettings["HOME"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "homedir")
337         mysettings["WORKDIR"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "work")
338         mysettings["D"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "image") + os.sep
339         mysettings["T"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "temp")
340
341         # Prefix forward compatability
342         eprefix_lstrip = mysettings["EPREFIX"].lstrip(os.sep)
343         mysettings["ED"] = os.path.join(
344                 mysettings["D"], eprefix_lstrip).rstrip(os.sep) + os.sep
345
346         mysettings["PORTAGE_BASHRC"] = os.path.join(
347                 mysettings["PORTAGE_CONFIGROOT"], EBUILD_SH_ENV_FILE)
348         mysettings["PM_EBUILD_HOOK_DIR"] = os.path.join(
349                 mysettings["PORTAGE_CONFIGROOT"], EBUILD_SH_ENV_DIR)
350
351         # Allow color.map to control colors associated with einfo, ewarn, etc...
352         mysettings["PORTAGE_COLORMAP"] = colormap()
353
354         if "COLUMNS" not in mysettings:
355                 # Set COLUMNS, in order to prevent unnecessary stty calls
356                 # inside the set_colors function of isolated-functions.sh.
357                 # We cache the result in os.environ, in order to avoid
358                 # multiple stty calls in cases when get_term_size() falls
359                 # back to stty due to a missing or broken curses module.
360                 columns = os.environ.get("COLUMNS")
361                 if columns is None:
362                         rows, columns = portage.output.get_term_size()
363                         if columns < 1:
364                                 # Force a sane value for COLUMNS, so that tools
365                                 # like ls don't complain (see bug #394091).
366                                 columns = 80
367                         columns = str(columns)
368                         os.environ["COLUMNS"] = columns
369                 mysettings["COLUMNS"] = columns
370
371         # EAPI is always known here, even for the "depend" phase, because
372         # EbuildMetadataPhase gets it from _parse_eapi_ebuild_head().
373         eapi = mysettings.configdict['pkg']['EAPI']
374         _doebuild_path(mysettings, eapi=eapi)
375
376         # All EAPI dependent code comes last, so that essential variables like
377         # PATH and PORTAGE_BUILDDIR are still initialized even in cases when
378         # UnsupportedAPIException needs to be raised, which can be useful
379         # when uninstalling a package that has corrupt EAPI metadata.
380         if not eapi_is_supported(eapi):
381                 raise UnsupportedAPIException(mycpv, eapi)
382
383         if eapi_exports_REPOSITORY(eapi) and "PORTAGE_REPO_NAME" in mysettings.configdict["pkg"]:
384                 mysettings.configdict["pkg"]["REPOSITORY"] = mysettings.configdict["pkg"]["PORTAGE_REPO_NAME"]
385
386         if mydo != "depend":
387                 if hasattr(mydbapi, "getFetchMap") and \
388                         ("A" not in mysettings.configdict["pkg"] or \
389                         "AA" not in mysettings.configdict["pkg"]):
390                         src_uri, = mydbapi.aux_get(mysettings.mycpv,
391                                 ["SRC_URI"], mytree=mytree)
392                         metadata = {
393                                 "EAPI"    : eapi,
394                                 "SRC_URI" : src_uri,
395                         }
396                         use = frozenset(mysettings["PORTAGE_USE"].split())
397                         try:
398                                 uri_map = _parse_uri_map(mysettings.mycpv, metadata, use=use)
399                         except InvalidDependString:
400                                 mysettings.configdict["pkg"]["A"] = ""
401                         else:
402                                 mysettings.configdict["pkg"]["A"] = " ".join(uri_map)
403
404                         try:
405                                 uri_map = _parse_uri_map(mysettings.mycpv, metadata)
406                         except InvalidDependString:
407                                 mysettings.configdict["pkg"]["AA"] = ""
408                         else:
409                                 mysettings.configdict["pkg"]["AA"] = " ".join(uri_map)
410
411                 ccache = "ccache" in mysettings.features
412                 distcc = "distcc" in mysettings.features
413                 if ccache or distcc:
414                         # Use default ABI libdir in accordance with bug #355283.
415                         libdir = None
416                         default_abi = mysettings.get("DEFAULT_ABI")
417                         if default_abi:
418                                 libdir = mysettings.get("LIBDIR_" + default_abi)
419                         if not libdir:
420                                 libdir = "lib"
421
422                         if distcc:
423                                 mysettings["PATH"] = os.path.join(os.sep, eprefix_lstrip,
424                                          "usr", libdir, "distcc", "bin") + ":" + mysettings["PATH"]
425
426                         if ccache:
427                                 mysettings["PATH"] = os.path.join(os.sep, eprefix_lstrip,
428                                          "usr", libdir, "ccache", "bin") + ":" + mysettings["PATH"]
429
430                 if not eapi_exports_KV(eapi):
431                         # Discard KV for EAPIs that don't support it. Cached KV is restored
432                         # from the backupenv whenever config.reset() is called.
433                         mysettings.pop('KV', None)
434                 elif 'KV' not in mysettings and \
435                         mydo in ('compile', 'config', 'configure', 'info',
436                         'install', 'nofetch', 'postinst', 'postrm', 'preinst',
437                         'prepare', 'prerm', 'setup', 'test', 'unpack'):
438                         mykv, err1 = ExtractKernelVersion(
439                                 os.path.join(mysettings['EROOT'], "usr/src/linux"))
440                         if mykv:
441                                 # Regular source tree
442                                 mysettings["KV"] = mykv
443                         else:
444                                 mysettings["KV"] = ""
445                         mysettings.backup_changes("KV")
446
447 _doebuild_manifest_cache = None
448 _doebuild_broken_ebuilds = set()
449 _doebuild_broken_manifests = set()
450 _doebuild_commands_without_builddir = (
451         'clean', 'cleanrm', 'depend', 'digest',
452         'fetch', 'fetchall', 'help', 'manifest'
453 )
454
455 def doebuild(myebuild, mydo, _unused=None, settings=None, debug=0, listonly=0,
456         fetchonly=0, cleanup=0, dbkey=None, use_cache=1, fetchall=0, tree=None,
457         mydbapi=None, vartree=None, prev_mtimes=None,
458         fd_pipes=None, returnpid=False):
459         """
460         Wrapper function that invokes specific ebuild phases through the spawning
461         of ebuild.sh
462         
463         @param myebuild: name of the ebuild to invoke the phase on (CPV)
464         @type myebuild: String
465         @param mydo: Phase to run
466         @type mydo: String
467         @param _unused: Deprecated (use settings["ROOT"] instead)
468         @type _unused: String
469         @param settings: Portage Configuration
470         @type settings: instance of portage.config
471         @param debug: Turns on various debug information (eg, debug for spawn)
472         @type debug: Boolean
473         @param listonly: Used to wrap fetch(); passed such that fetch only lists files required.
474         @type listonly: Boolean
475         @param fetchonly: Used to wrap fetch(); passed such that files are only fetched (no other actions)
476         @type fetchonly: Boolean
477         @param cleanup: Passed to prepare_build_dirs (TODO: what does it do?)
478         @type cleanup: Boolean
479         @param dbkey: A file path where metadata generated by the 'depend' phase
480                 will be written.
481         @type dbkey: String
482         @param use_cache: Enables the cache
483         @type use_cache: Boolean
484         @param fetchall: Used to wrap fetch(), fetches all URIs (even ones invalid due to USE conditionals)
485         @type fetchall: Boolean
486         @param tree: Which tree to use ('vartree','porttree','bintree', etc..), defaults to 'porttree'
487         @type tree: String
488         @param mydbapi: a dbapi instance to pass to various functions; this should be a portdbapi instance.
489         @type mydbapi: portdbapi instance
490         @param vartree: A instance of vartree; used for aux_get calls, defaults to db[myroot]['vartree']
491         @type vartree: vartree instance
492         @param prev_mtimes: A dict of { filename:mtime } keys used by merge() to do config_protection
493         @type prev_mtimes: dictionary
494         @param fd_pipes: A dict of mapping for pipes, { '0': stdin, '1': stdout }
495                 for example.
496         @type fd_pipes: Dictionary
497         @param returnpid: Return a list of process IDs for a successful spawn, or
498                 an integer value if spawn is unsuccessful. NOTE: This requires the
499                 caller clean up all returned PIDs.
500         @type returnpid: Boolean
501         @rtype: Boolean
502         @return:
503         1. 0 for success
504         2. 1 for error
505         
506         Most errors have an accompanying error message.
507         
508         listonly and fetchonly are only really necessary for operations involving 'fetch'
509         prev_mtimes are only necessary for merge operations.
510         Other variables may not be strictly required, many have defaults that are set inside of doebuild.
511         
512         """
513
514         if settings is None:
515                 raise TypeError("settings parameter is required")
516         mysettings = settings
517         myroot = settings['EROOT']
518
519         if _unused is not None and _unused != mysettings['EROOT']:
520                 warnings.warn("The third parameter of the "
521                         "portage.doebuild() is now unused. Use "
522                         "settings['ROOT'] instead.",
523                         DeprecationWarning, stacklevel=2)
524
525         if not tree:
526                 writemsg("Warning: tree not specified to doebuild\n")
527                 tree = "porttree"
528         
529         # chunked out deps for each phase, so that ebuild binary can use it 
530         # to collapse targets down.
531         actionmap_deps={
532         "pretend"  : [],
533         "setup":  ["pretend"],
534         "unpack": ["setup"],
535         "prepare": ["unpack"],
536         "configure": ["prepare"],
537         "compile":["configure"],
538         "test":   ["compile"],
539         "install":["test"],
540         "rpm":    ["install"],
541         "package":["install"],
542         "merge"  :["install"],
543         }
544         
545         if mydbapi is None:
546                 mydbapi = portage.db[myroot][tree].dbapi
547
548         if vartree is None and mydo in ("merge", "qmerge", "unmerge"):
549                 vartree = portage.db[myroot]["vartree"]
550
551         features = mysettings.features
552
553         clean_phases = ("clean", "cleanrm")
554         validcommands = ["help","clean","prerm","postrm","cleanrm","preinst","postinst",
555                         "config", "info", "setup", "depend", "pretend",
556                         "fetch", "fetchall", "digest",
557                         "unpack", "prepare", "configure", "compile", "test",
558                         "install", "rpm", "qmerge", "merge",
559                         "package","unmerge", "manifest"]
560
561         if mydo not in validcommands:
562                 validcommands.sort()
563                 writemsg("!!! doebuild: '%s' is not one of the following valid commands:" % mydo,
564                         noiselevel=-1)
565                 for vcount in range(len(validcommands)):
566                         if vcount%6 == 0:
567                                 writemsg("\n!!! ", noiselevel=-1)
568                         writemsg(validcommands[vcount].ljust(11), noiselevel=-1)
569                 writemsg("\n", noiselevel=-1)
570                 return 1
571
572         if returnpid and mydo != 'depend':
573                 warnings.warn("portage.doebuild() called " + \
574                         "with returnpid parameter enabled. This usage will " + \
575                         "not be supported in the future.",
576                         DeprecationWarning, stacklevel=2)
577
578         if mydo == "fetchall":
579                 fetchall = 1
580                 mydo = "fetch"
581
582         parallel_fetchonly = mydo in ("fetch", "fetchall") and \
583                 "PORTAGE_PARALLEL_FETCHONLY" in mysettings
584
585         if mydo not in clean_phases and not os.path.exists(myebuild):
586                 writemsg("!!! doebuild: %s not found for %s\n" % (myebuild, mydo),
587                         noiselevel=-1)
588                 return 1
589
590         global _doebuild_manifest_cache
591         pkgdir = os.path.dirname(myebuild)
592         manifest_path = os.path.join(pkgdir, "Manifest")
593         if tree == "porttree":
594                 repo_config = mysettings.repositories.get_repo_for_location(
595                         os.path.dirname(os.path.dirname(pkgdir)))
596         else:
597                 repo_config = None
598
599         mf = None
600         if "strict" in features and \
601                 "digest" not in features and \
602                 tree == "porttree" and \
603                 not repo_config.thin_manifest and \
604                 mydo not in ("digest", "manifest", "help") and \
605                 not portage._doebuild_manifest_exempt_depend and \
606                 not (repo_config.allow_missing_manifest and not os.path.exists(manifest_path)):
607                 # Always verify the ebuild checksums before executing it.
608                 global _doebuild_broken_ebuilds
609
610                 if myebuild in _doebuild_broken_ebuilds:
611                         return 1
612
613                 # Avoid checking the same Manifest several times in a row during a
614                 # regen with an empty cache.
615                 if _doebuild_manifest_cache is None or \
616                         _doebuild_manifest_cache.getFullname() != manifest_path:
617                         _doebuild_manifest_cache = None
618                         if not os.path.exists(manifest_path):
619                                 out = portage.output.EOutput()
620                                 out.eerror(_("Manifest not found for '%s'") % (myebuild,))
621                                 _doebuild_broken_ebuilds.add(myebuild)
622                                 return 1
623                         mf = repo_config.load_manifest(pkgdir, mysettings["DISTDIR"])
624
625                 else:
626                         mf = _doebuild_manifest_cache
627
628                 try:
629                         mf.checkFileHashes("EBUILD", os.path.basename(myebuild))
630                 except KeyError:
631                         if not (mf.allow_missing and
632                                 os.path.basename(myebuild) not in mf.fhashdict["EBUILD"]):
633                                 out = portage.output.EOutput()
634                                 out.eerror(_("Missing digest for '%s'") % (myebuild,))
635                                 _doebuild_broken_ebuilds.add(myebuild)
636                                 return 1
637                 except FileNotFound:
638                         out = portage.output.EOutput()
639                         out.eerror(_("A file listed in the Manifest "
640                                 "could not be found: '%s'") % (myebuild,))
641                         _doebuild_broken_ebuilds.add(myebuild)
642                         return 1
643                 except DigestException as e:
644                         out = portage.output.EOutput()
645                         out.eerror(_("Digest verification failed:"))
646                         out.eerror("%s" % e.value[0])
647                         out.eerror(_("Reason: %s") % e.value[1])
648                         out.eerror(_("Got: %s") % e.value[2])
649                         out.eerror(_("Expected: %s") % e.value[3])
650                         _doebuild_broken_ebuilds.add(myebuild)
651                         return 1
652
653                 if mf.getFullname() in _doebuild_broken_manifests:
654                         return 1
655
656                 if mf is not _doebuild_manifest_cache and not mf.allow_missing:
657
658                         # Make sure that all of the ebuilds are
659                         # actually listed in the Manifest.
660                         for f in os.listdir(pkgdir):
661                                 pf = None
662                                 if f[-7:] == '.ebuild':
663                                         pf = f[:-7]
664                                 if pf is not None and not mf.hasFile("EBUILD", f):
665                                         f = os.path.join(pkgdir, f)
666                                         if f not in _doebuild_broken_ebuilds:
667                                                 out = portage.output.EOutput()
668                                                 out.eerror(_("A file is not listed in the "
669                                                         "Manifest: '%s'") % (f,))
670                                         _doebuild_broken_manifests.add(manifest_path)
671                                         return 1
672
673                 # We cache it only after all above checks succeed.
674                 _doebuild_manifest_cache = mf
675
676         logfile=None
677         builddir_lock = None
678         tmpdir = None
679         tmpdir_orig = None
680
681         try:
682                 if mydo in ("digest", "manifest", "help"):
683                         # Temporarily exempt the depend phase from manifest checks, in case
684                         # aux_get calls trigger cache generation.
685                         portage._doebuild_manifest_exempt_depend += 1
686
687                 # If we don't need much space and we don't need a constant location,
688                 # we can temporarily override PORTAGE_TMPDIR with a random temp dir
689                 # so that there's no need for locking and it can be used even if the
690                 # user isn't in the portage group.
691                 if mydo in ("info",):
692                         tmpdir = tempfile.mkdtemp()
693                         tmpdir_orig = mysettings["PORTAGE_TMPDIR"]
694                         mysettings["PORTAGE_TMPDIR"] = tmpdir
695
696                 doebuild_environment(myebuild, mydo, myroot, mysettings, debug,
697                         use_cache, mydbapi)
698
699                 if mydo in clean_phases:
700                         builddir_lock = None
701                         if not returnpid and \
702                                 'PORTAGE_BUILDDIR_LOCKED' not in mysettings:
703                                 builddir_lock = EbuildBuildDir(
704                                         scheduler=(portage._internal_caller and
705                                                 global_event_loop() or EventLoop(main=False)),
706                                         settings=mysettings)
707                                 builddir_lock.lock()
708                         try:
709                                 return _spawn_phase(mydo, mysettings,
710                                         fd_pipes=fd_pipes, returnpid=returnpid)
711                         finally:
712                                 if builddir_lock is not None:
713                                         builddir_lock.unlock()
714
715                 # get possible slot information from the deps file
716                 if mydo == "depend":
717                         writemsg("!!! DEBUG: dbkey: %s\n" % str(dbkey), 2)
718                         if returnpid:
719                                 return _spawn_phase(mydo, mysettings,
720                                         fd_pipes=fd_pipes, returnpid=returnpid)
721                         elif isinstance(dbkey, dict):
722                                 warnings.warn("portage.doebuild() called " + \
723                                         "with dict dbkey argument. This usage will " + \
724                                         "not be supported in the future.",
725                                         DeprecationWarning, stacklevel=2)
726                                 mysettings["dbkey"] = ""
727                                 pr, pw = os.pipe()
728                                 fd_pipes = {
729                                         0:portage._get_stdin().fileno(),
730                                         1:sys.__stdout__.fileno(),
731                                         2:sys.__stderr__.fileno(),
732                                         9:pw}
733                                 mypids = _spawn_phase(mydo, mysettings, returnpid=True,
734                                         fd_pipes=fd_pipes)
735                                 os.close(pw) # belongs exclusively to the child process now
736                                 f = os.fdopen(pr, 'rb', 0)
737                                 for k, v in zip(auxdbkeys,
738                                         (_unicode_decode(line).rstrip('\n') for line in f)):
739                                         dbkey[k] = v
740                                 f.close()
741                                 retval = os.waitpid(mypids[0], 0)[1]
742                                 portage.process.spawned_pids.remove(mypids[0])
743                                 # If it got a signal, return the signal that was sent, but
744                                 # shift in order to distinguish it from a return value. (just
745                                 # like portage.process.spawn() would do).
746                                 if retval & 0xff:
747                                         retval = (retval & 0xff) << 8
748                                 else:
749                                         # Otherwise, return its exit code.
750                                         retval = retval >> 8
751                                 if retval == os.EX_OK and len(dbkey) != len(auxdbkeys):
752                                         # Don't trust bash's returncode if the
753                                         # number of lines is incorrect.
754                                         retval = 1
755                                 return retval
756                         elif dbkey:
757                                 mysettings["dbkey"] = dbkey
758                         else:
759                                 mysettings["dbkey"] = \
760                                         os.path.join(mysettings.depcachedir, "aux_db_key_temp")
761
762                         return _spawn_phase(mydo, mysettings,
763                                 fd_pipes=fd_pipes, returnpid=returnpid)
764
765                 # Validate dependency metadata here to ensure that ebuilds with invalid
766                 # data are never installed via the ebuild command. Don't bother when
767                 # returnpid == True since there's no need to do this every time emerge
768                 # executes a phase.
769                 if tree == "porttree":
770                         rval = _validate_deps(mysettings, myroot, mydo, mydbapi)
771                         if rval != os.EX_OK:
772                                 return rval
773
774                 else:
775                         # FEATURES=noauto only makes sense for porttree, and we don't want
776                         # it to trigger redundant sourcing of the ebuild for API consumers
777                         # that are using binary packages
778                         if "noauto" in mysettings.features:
779                                 mysettings.features.discard("noauto")
780
781                 # The info phase is special because it uses mkdtemp so and
782                 # user (not necessarily in the portage group) can run it.
783                 if mydo not in ('info',) and \
784                         mydo not in _doebuild_commands_without_builddir:
785                         rval = _check_temp_dir(mysettings)
786                         if rval != os.EX_OK:
787                                 return rval
788
789                 if mydo == "unmerge":
790                         return unmerge(mysettings["CATEGORY"],
791                                 mysettings["PF"], myroot, mysettings, vartree=vartree)
792
793                 phases_to_run = set()
794                 if "noauto" in mysettings.features or \
795                         mydo not in actionmap_deps:
796                         phases_to_run.add(mydo)
797                 else:
798                         phase_stack = [mydo]
799                         while phase_stack:
800                                 x = phase_stack.pop()
801                                 if x in phases_to_run:
802                                         continue
803                                 phases_to_run.add(x)
804                                 phase_stack.extend(actionmap_deps.get(x, []))
805                         del phase_stack
806
807                 alist = set(mysettings.configdict["pkg"].get("A", "").split())
808
809                 unpacked = False
810                 if tree != "porttree":
811                         pass
812                 elif "unpack" not in phases_to_run:
813                         unpacked = os.path.exists(os.path.join(
814                                 mysettings["PORTAGE_BUILDDIR"], ".unpacked"))
815                 else:
816                         try:
817                                 workdir_st = os.stat(mysettings["WORKDIR"])
818                         except OSError:
819                                 pass
820                         else:
821                                 newstuff = False
822                                 if not os.path.exists(os.path.join(
823                                         mysettings["PORTAGE_BUILDDIR"], ".unpacked")):
824                                         writemsg_stdout(_(
825                                                 ">>> Not marked as unpacked; recreating WORKDIR...\n"))
826                                         newstuff = True
827                                 else:
828                                         for x in alist:
829                                                 writemsg_stdout(">>> Checking %s's mtime...\n" % x)
830                                                 try:
831                                                         x_st = os.stat(os.path.join(
832                                                                 mysettings["DISTDIR"], x))
833                                                 except OSError:
834                                                         # file not fetched yet
835                                                         x_st = None
836
837                                                 if x_st is None or x_st.st_mtime > workdir_st.st_mtime:
838                                                         writemsg_stdout(_(">>> Timestamp of "
839                                                                 "%s has changed; recreating WORKDIR...\n") % x)
840                                                         newstuff = True
841                                                         break
842
843                                 if newstuff:
844                                         if builddir_lock is None and \
845                                                 'PORTAGE_BUILDDIR_LOCKED' not in mysettings:
846                                                 builddir_lock = EbuildBuildDir(
847                                                         scheduler=(portage._internal_caller and
848                                                                 global_event_loop() or EventLoop(main=False)),
849                                                         settings=mysettings)
850                                                 builddir_lock.lock()
851                                         try:
852                                                 _spawn_phase("clean", mysettings)
853                                         finally:
854                                                 if builddir_lock is not None:
855                                                         builddir_lock.unlock()
856                                                         builddir_lock = None
857                                 else:
858                                         writemsg_stdout(_(">>> WORKDIR is up-to-date, keeping...\n"))
859                                         unpacked = True
860
861                 # Build directory creation isn't required for any of these.
862                 # In the fetch phase, the directory is needed only for RESTRICT=fetch
863                 # in order to satisfy the sane $PWD requirement (from bug #239560)
864                 # when pkg_nofetch is spawned.
865                 have_build_dirs = False
866                 if not parallel_fetchonly and \
867                         mydo not in ('digest', 'fetch', 'help', 'manifest'):
868                         if not returnpid and \
869                                 'PORTAGE_BUILDDIR_LOCKED' not in mysettings:
870                                 builddir_lock = EbuildBuildDir(
871                                         scheduler=(portage._internal_caller and
872                                                 global_event_loop() or EventLoop(main=False)),
873                                         settings=mysettings)
874                                 builddir_lock.lock()
875                         mystatus = prepare_build_dirs(myroot, mysettings, cleanup)
876                         if mystatus:
877                                 return mystatus
878                         have_build_dirs = True
879
880                         # emerge handles logging externally
881                         if not returnpid:
882                                 # PORTAGE_LOG_FILE is set by the
883                                 # above prepare_build_dirs() call.
884                                 logfile = mysettings.get("PORTAGE_LOG_FILE")
885
886                 if have_build_dirs:
887                         rval = _prepare_env_file(mysettings)
888                         if rval != os.EX_OK:
889                                 return rval
890
891                 if eapi_exports_merge_type(mysettings["EAPI"]) and \
892                         "MERGE_TYPE" not in mysettings.configdict["pkg"]:
893                         if tree == "porttree":
894                                 mysettings.configdict["pkg"]["EMERGE_FROM"] = "ebuild"
895                                 mysettings.configdict["pkg"]["MERGE_TYPE"] = "source"
896                         elif tree == "bintree":
897                                 mysettings.configdict["pkg"]["EMERGE_FROM"] = "binary"
898                                 mysettings.configdict["pkg"]["MERGE_TYPE"] = "binary"
899
900                 # NOTE: It's not possible to set REPLACED_BY_VERSION for prerm
901                 #       and postrm here, since we don't necessarily know what
902                 #       versions are being installed. This could be a problem
903                 #       for API consumers if they don't use dblink.treewalk()
904                 #       to execute prerm and postrm.
905                 if eapi_exports_replace_vars(mysettings["EAPI"]) and \
906                         (mydo in ("postinst", "preinst", "pretend", "setup") or \
907                         ("noauto" not in features and not returnpid and \
908                         (mydo in actionmap_deps or mydo in ("merge", "package", "qmerge")))):
909                         if not vartree:
910                                 writemsg("Warning: vartree not given to doebuild. " + \
911                                         "Cannot set REPLACING_VERSIONS in pkg_{pretend,setup}\n")
912                         else:
913                                 vardb = vartree.dbapi
914                                 cpv = mysettings.mycpv
915                                 cpv_slot = "%s%s%s" % \
916                                         (cpv.cp, portage.dep._slot_separator, cpv.slot)
917                                 mysettings["REPLACING_VERSIONS"] = " ".join(
918                                         set(portage.versions.cpv_getversion(match) \
919                                                 for match in vardb.match(cpv_slot) + \
920                                                 vardb.match('='+cpv)))
921
922                 # if any of these are being called, handle them -- running them out of
923                 # the sandbox -- and stop now.
924                 if mydo in ("config", "help", "info", "postinst",
925                         "preinst", "pretend", "postrm", "prerm"):
926                         if mydo in ("preinst", "postinst"):
927                                 env_file = os.path.join(os.path.dirname(mysettings["EBUILD"]),
928                                         "environment.bz2")
929                                 if os.path.isfile(env_file):
930                                         mysettings["PORTAGE_UPDATE_ENV"] = env_file
931                         try:
932                                 return _spawn_phase(mydo, mysettings,
933                                         fd_pipes=fd_pipes, logfile=logfile, returnpid=returnpid)
934                         finally:
935                                 mysettings.pop("PORTAGE_UPDATE_ENV", None)
936
937                 mycpv = "/".join((mysettings["CATEGORY"], mysettings["PF"]))
938
939                 # Only try and fetch the files if we are going to need them ...
940                 # otherwise, if user has FEATURES=noauto and they run `ebuild clean
941                 # unpack compile install`, we will try and fetch 4 times :/
942                 need_distfiles = tree == "porttree" and not unpacked and \
943                         (mydo in ("fetch", "unpack") or \
944                         mydo not in ("digest", "manifest") and "noauto" not in features)
945                 if need_distfiles:
946
947                         src_uri, = mydbapi.aux_get(mysettings.mycpv,
948                                 ["SRC_URI"], mytree=os.path.dirname(os.path.dirname(
949                                 os.path.dirname(myebuild))))
950                         metadata = {
951                                 "EAPI"    : mysettings["EAPI"],
952                                 "SRC_URI" : src_uri,
953                         }
954                         use = frozenset(mysettings["PORTAGE_USE"].split())
955                         try:
956                                 alist = _parse_uri_map(mysettings.mycpv, metadata, use=use)
957                                 aalist = _parse_uri_map(mysettings.mycpv, metadata)
958                         except InvalidDependString as e:
959                                 writemsg("!!! %s\n" % str(e), noiselevel=-1)
960                                 writemsg(_("!!! Invalid SRC_URI for '%s'.\n") % mycpv,
961                                         noiselevel=-1)
962                                 del e
963                                 return 1
964
965                         if "mirror" in features or fetchall:
966                                 fetchme = aalist
967                         else:
968                                 fetchme = alist
969
970                         dist_digests = None
971                         if mf is not None:
972                                 dist_digests = mf.getTypeDigests("DIST")
973                         if not fetch(fetchme, mysettings, listonly=listonly,
974                                 fetchonly=fetchonly, allow_missing_digests=True,
975                                 digests=dist_digests):
976                                 spawn_nofetch(mydbapi, myebuild, settings=mysettings)
977                                 if listonly:
978                                         # The convention for listonly mode is to report
979                                         # success in any case, even though fetch() may
980                                         # return unsuccessfully in order to trigger the
981                                         # nofetch phase.
982                                         return 0
983                                 return 1
984
985                 if need_distfiles:
986                         # Files are already checked inside fetch(),
987                         # so do not check them again.
988                         checkme = []
989                 elif unpacked:
990                         # The unpack phase is marked as complete, so it
991                         # would be wasteful to check distfiles again.
992                         checkme = []
993                 else:
994                         checkme = alist
995
996                 if mydo == "fetch" and listonly:
997                         return 0
998
999                 try:
1000                         if mydo == "manifest":
1001                                 mf = None
1002                                 _doebuild_manifest_cache = None
1003                                 return not digestgen(mysettings=mysettings, myportdb=mydbapi)
1004                         elif mydo == "digest":
1005                                 mf = None
1006                                 _doebuild_manifest_cache = None
1007                                 return not digestgen(mysettings=mysettings, myportdb=mydbapi)
1008                         elif mydo != 'fetch' and \
1009                                 "digest" in mysettings.features:
1010                                 # Don't do this when called by emerge or when called just
1011                                 # for fetch (especially parallel-fetch) since it's not needed
1012                                 # and it can interfere with parallel tasks.
1013                                 mf = None
1014                                 _doebuild_manifest_cache = None
1015                                 digestgen(mysettings=mysettings, myportdb=mydbapi)
1016                 except PermissionDenied as e:
1017                         writemsg(_("!!! Permission Denied: %s\n") % (e,), noiselevel=-1)
1018                         if mydo in ("digest", "manifest"):
1019                                 return 1
1020
1021                 # See above comment about fetching only when needed
1022                 if tree == 'porttree' and \
1023                         not digestcheck(checkme, mysettings, "strict" in features, mf=mf):
1024                         return 1
1025
1026                 if mydo == "fetch":
1027                         return 0
1028
1029                 # remove PORTAGE_ACTUAL_DISTDIR once cvs/svn is supported via SRC_URI
1030                 if tree == 'porttree' and \
1031                         ((mydo != "setup" and "noauto" not in features) \
1032                         or mydo in ("install", "unpack")):
1033                         _prepare_fake_distdir(mysettings, alist)
1034
1035                 #initial dep checks complete; time to process main commands
1036                 actionmap = _spawn_actionmap(mysettings)
1037
1038                 # merge the deps in so we have again a 'full' actionmap
1039                 # be glad when this can die.
1040                 for x in actionmap:
1041                         if len(actionmap_deps.get(x, [])):
1042                                 actionmap[x]["dep"] = ' '.join(actionmap_deps[x])
1043
1044                 if mydo in actionmap:
1045                         bintree = None
1046                         if mydo == "package":
1047                                 # Make sure the package directory exists before executing
1048                                 # this phase. This can raise PermissionDenied if
1049                                 # the current user doesn't have write access to $PKGDIR.
1050                                 if hasattr(portage, 'db'):
1051                                         bintree = portage.db[mysettings['EROOT']]['bintree']
1052                                         mysettings["PORTAGE_BINPKG_TMPFILE"] = \
1053                                                 bintree.getname(mysettings.mycpv) + \
1054                                                 ".%s" % (os.getpid(),)
1055                                         bintree._ensure_dir(os.path.dirname(
1056                                                 mysettings["PORTAGE_BINPKG_TMPFILE"]))
1057                                 else:
1058                                         parent_dir = os.path.join(mysettings["PKGDIR"],
1059                                                 mysettings["CATEGORY"])
1060                                         portage.util.ensure_dirs(parent_dir)
1061                                         if not os.access(parent_dir, os.W_OK):
1062                                                 raise PermissionDenied(
1063                                                         "access('%s', os.W_OK)" % parent_dir)
1064                         retval = spawnebuild(mydo,
1065                                 actionmap, mysettings, debug, logfile=logfile,
1066                                 fd_pipes=fd_pipes, returnpid=returnpid)
1067
1068                         if retval == os.EX_OK:
1069                                 if mydo == "package" and bintree is not None:
1070                                         bintree.inject(mysettings.mycpv,
1071                                                 filename=mysettings["PORTAGE_BINPKG_TMPFILE"])
1072                         else:
1073                                 if "PORTAGE_BINPKG_TMPFILE" in mysettings:
1074                                         try:
1075                                                 os.unlink(mysettings["PORTAGE_BINPKG_TMPFILE"])
1076                                         except OSError:
1077                                                 pass
1078
1079                 elif mydo=="qmerge":
1080                         # check to ensure install was run.  this *only* pops up when users
1081                         # forget it and are using ebuild
1082                         if not os.path.exists(
1083                                 os.path.join(mysettings["PORTAGE_BUILDDIR"], ".installed")):
1084                                 writemsg(_("!!! mydo=qmerge, but the install phase has not been run\n"),
1085                                         noiselevel=-1)
1086                                 return 1
1087                         # qmerge is a special phase that implies noclean.
1088                         if "noclean" not in mysettings.features:
1089                                 mysettings.features.add("noclean")
1090                         _handle_self_update(mysettings, vartree.dbapi)
1091                         #qmerge is specifically not supposed to do a runtime dep check
1092                         retval = merge(
1093                                 mysettings["CATEGORY"], mysettings["PF"], mysettings["D"],
1094                                 os.path.join(mysettings["PORTAGE_BUILDDIR"], "build-info"),
1095                                 myroot, mysettings, myebuild=mysettings["EBUILD"], mytree=tree,
1096                                 mydbapi=mydbapi, vartree=vartree, prev_mtimes=prev_mtimes)
1097                 elif mydo=="merge":
1098                         retval = spawnebuild("install", actionmap, mysettings, debug,
1099                                 alwaysdep=1, logfile=logfile, fd_pipes=fd_pipes,
1100                                 returnpid=returnpid)
1101                         if retval != os.EX_OK:
1102                                 # The merge phase handles this already.  Callers don't know how
1103                                 # far this function got, so we have to call elog_process() here
1104                                 # so that it's only called once.
1105                                 elog_process(mysettings.mycpv, mysettings)
1106                         if retval == os.EX_OK:
1107                                 _handle_self_update(mysettings, vartree.dbapi)
1108                                 retval = merge(mysettings["CATEGORY"], mysettings["PF"],
1109                                         mysettings["D"], os.path.join(mysettings["PORTAGE_BUILDDIR"],
1110                                         "build-info"), myroot, mysettings,
1111                                         myebuild=mysettings["EBUILD"], mytree=tree, mydbapi=mydbapi,
1112                                         vartree=vartree, prev_mtimes=prev_mtimes)
1113                 else:
1114                         writemsg_stdout(_("!!! Unknown mydo: %s\n") % mydo, noiselevel=-1)
1115                         return 1
1116
1117                 return retval
1118
1119         finally:
1120
1121                 if builddir_lock is not None:
1122                         builddir_lock.unlock()
1123                 if tmpdir:
1124                         mysettings["PORTAGE_TMPDIR"] = tmpdir_orig
1125                         shutil.rmtree(tmpdir)
1126
1127                 mysettings.pop("REPLACING_VERSIONS", None)
1128
1129                 # Make sure that DISTDIR is restored to it's normal value before we return!
1130                 if "PORTAGE_ACTUAL_DISTDIR" in mysettings:
1131                         mysettings["DISTDIR"] = mysettings["PORTAGE_ACTUAL_DISTDIR"]
1132                         del mysettings["PORTAGE_ACTUAL_DISTDIR"]
1133
1134                 if logfile and not returnpid:
1135                         try:
1136                                 if os.stat(logfile).st_size == 0:
1137                                         os.unlink(logfile)
1138                         except OSError:
1139                                 pass
1140
1141                 if mydo in ("digest", "manifest", "help"):
1142                         # If necessary, depend phase has been triggered by aux_get calls
1143                         # and the exemption is no longer needed.
1144                         portage._doebuild_manifest_exempt_depend -= 1
1145
1146 def _check_temp_dir(settings):
1147         if "PORTAGE_TMPDIR" not in settings or \
1148                 not os.path.isdir(settings["PORTAGE_TMPDIR"]):
1149                 writemsg(_("The directory specified in your "
1150                         "PORTAGE_TMPDIR variable, '%s',\n"
1151                         "does not exist.  Please create this directory or "
1152                         "correct your PORTAGE_TMPDIR setting.\n") % \
1153                         settings.get("PORTAGE_TMPDIR", ""), noiselevel=-1)
1154                 return 1
1155
1156         # as some people use a separate PORTAGE_TMPDIR mount
1157         # we prefer that as the checks below would otherwise be pointless
1158         # for those people.
1159         tmpdir = os.path.realpath(settings["PORTAGE_TMPDIR"])
1160         if os.path.exists(os.path.join(tmpdir, "portage")):
1161                 checkdir = os.path.realpath(os.path.join(tmpdir, "portage"))
1162                 if ("sandbox" in settings.features or
1163                         "usersandox" in settings.features) and \
1164                         not checkdir.startswith(tmpdir + os.sep):
1165                         msg = _("The 'portage' subdirectory of the directory "
1166                         "referenced by the PORTAGE_TMPDIR variable appears to be "
1167                         "a symlink. In order to avoid sandbox violations (see bug "
1168                         "#378379), you must adjust PORTAGE_TMPDIR instead of using "
1169                         "the symlink located at '%s'. A suitable PORTAGE_TMPDIR "
1170                         "setting would be '%s'.") % \
1171                         (os.path.join(tmpdir, "portage"), checkdir)
1172                         lines = []
1173                         lines.append("")
1174                         lines.append("")
1175                         lines.extend(wrap(msg, 72))
1176                         lines.append("")
1177                         for line in lines:
1178                                 if line:
1179                                         line = "!!! %s" % (line,)
1180                                 writemsg("%s\n" % (line,), noiselevel=-1)
1181                         return 1
1182         else:
1183                 checkdir = tmpdir
1184
1185         if not os.access(checkdir, os.W_OK):
1186                 writemsg(_("%s is not writable.\n"
1187                         "Likely cause is that you've mounted it as readonly.\n") % checkdir,
1188                         noiselevel=-1)
1189                 return 1
1190
1191         with tempfile.NamedTemporaryFile(prefix="exectest-", dir=checkdir) as fd:
1192                 os.chmod(fd.name, 0o755)
1193                 if not os.access(fd.name, os.X_OK):
1194                         writemsg(_("Can not execute files in %s\n"
1195                                 "Likely cause is that you've mounted it with one of the\n"
1196                                 "following mount options: 'noexec', 'user', 'users'\n\n"
1197                                 "Please make sure that portage can execute files in this directory.\n") % checkdir,
1198                                 noiselevel=-1)
1199                         return 1
1200
1201         return os.EX_OK
1202
1203 def _prepare_env_file(settings):
1204         """
1205         Extract environment.bz2 if it exists, but only if the destination
1206         environment file doesn't already exist. There are lots of possible
1207         states when doebuild() calls this function, and we want to avoid
1208         clobbering an existing environment file.
1209         """
1210
1211         env_extractor = BinpkgEnvExtractor(background=False,
1212                 scheduler=(portage._internal_caller and
1213                         global_event_loop() or EventLoop(main=False)),
1214                 settings=settings)
1215
1216         if env_extractor.dest_env_exists():
1217                 # There are lots of possible states when doebuild()
1218                 # calls this function, and we want to avoid
1219                 # clobbering an existing environment file.
1220                 return os.EX_OK
1221
1222         if not env_extractor.saved_env_exists():
1223                 # If the environment.bz2 doesn't exist, then ebuild.sh will
1224                 # source the ebuild as a fallback.
1225                 return os.EX_OK
1226
1227         env_extractor.start()
1228         env_extractor.wait()
1229         return env_extractor.returncode
1230
1231 def _prepare_fake_distdir(settings, alist):
1232         orig_distdir = settings["DISTDIR"]
1233         settings["PORTAGE_ACTUAL_DISTDIR"] = orig_distdir
1234         edpath = settings["DISTDIR"] = \
1235                 os.path.join(settings["PORTAGE_BUILDDIR"], "distdir")
1236         portage.util.ensure_dirs(edpath, gid=portage_gid, mode=0o755)
1237
1238         # Remove any unexpected files or directories.
1239         for x in os.listdir(edpath):
1240                 symlink_path = os.path.join(edpath, x)
1241                 st = os.lstat(symlink_path)
1242                 if x in alist and stat.S_ISLNK(st.st_mode):
1243                         continue
1244                 if stat.S_ISDIR(st.st_mode):
1245                         shutil.rmtree(symlink_path)
1246                 else:
1247                         os.unlink(symlink_path)
1248
1249         # Check for existing symlinks and recreate if necessary.
1250         for x in alist:
1251                 symlink_path = os.path.join(edpath, x)
1252                 target = os.path.join(orig_distdir, x)
1253                 try:
1254                         link_target = os.readlink(symlink_path)
1255                 except OSError:
1256                         os.symlink(target, symlink_path)
1257                 else:
1258                         if link_target != target:
1259                                 os.unlink(symlink_path)
1260                                 os.symlink(target, symlink_path)
1261
1262 def _spawn_actionmap(settings):
1263         features = settings.features
1264         restrict = settings["PORTAGE_RESTRICT"].split()
1265         nosandbox = (("userpriv" in features) and \
1266                 ("usersandbox" not in features) and \
1267                 "userpriv" not in restrict and \
1268                 "nouserpriv" not in restrict)
1269         if nosandbox and ("userpriv" not in features or \
1270                 "userpriv" in restrict or \
1271                 "nouserpriv" in restrict):
1272                 nosandbox = ("sandbox" not in features and \
1273                         "usersandbox" not in features)
1274
1275         if not portage.process.sandbox_capable:
1276                 nosandbox = True
1277
1278         sesandbox = settings.selinux_enabled() and \
1279                 "sesandbox" in features
1280
1281         droppriv = "userpriv" in features and \
1282                 "userpriv" not in restrict and \
1283                 secpass >= 2
1284
1285         fakeroot = "fakeroot" in features
1286
1287         portage_bin_path = settings["PORTAGE_BIN_PATH"]
1288         ebuild_sh_binary = os.path.join(portage_bin_path,
1289                 os.path.basename(EBUILD_SH_BINARY))
1290         misc_sh_binary = os.path.join(portage_bin_path,
1291                 os.path.basename(MISC_SH_BINARY))
1292         ebuild_sh = _shell_quote(ebuild_sh_binary) + " %s"
1293         misc_sh = _shell_quote(misc_sh_binary) + " __dyn_%s"
1294
1295         # args are for the to spawn function
1296         actionmap = {
1297 "pretend":  {"cmd":ebuild_sh, "args":{"droppriv":0,        "free":1,         "sesandbox":0,         "fakeroot":0}},
1298 "setup":    {"cmd":ebuild_sh, "args":{"droppriv":0,        "free":1,         "sesandbox":0,         "fakeroot":0}},
1299 "unpack":   {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":0,         "sesandbox":sesandbox, "fakeroot":0}},
1300 "prepare":  {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":0,         "sesandbox":sesandbox, "fakeroot":0}},
1301 "configure":{"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":nosandbox, "sesandbox":sesandbox, "fakeroot":0}},
1302 "compile":  {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":nosandbox, "sesandbox":sesandbox, "fakeroot":0}},
1303 "test":     {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":nosandbox, "sesandbox":sesandbox, "fakeroot":0}},
1304 "install":  {"cmd":ebuild_sh, "args":{"droppriv":0,        "free":0,         "sesandbox":sesandbox, "fakeroot":fakeroot}},
1305 "rpm":      {"cmd":misc_sh,   "args":{"droppriv":0,        "free":0,         "sesandbox":0,         "fakeroot":fakeroot}},
1306 "package":  {"cmd":misc_sh,   "args":{"droppriv":0,        "free":0,         "sesandbox":0,         "fakeroot":fakeroot}},
1307                 }
1308
1309         return actionmap
1310
1311 def _validate_deps(mysettings, myroot, mydo, mydbapi):
1312
1313         invalid_dep_exempt_phases = \
1314                 set(["clean", "cleanrm", "help", "prerm", "postrm"])
1315         all_keys = set(Package.metadata_keys)
1316         all_keys.add("SRC_URI")
1317         all_keys = tuple(all_keys)
1318         metadata = dict(zip(all_keys,
1319                 mydbapi.aux_get(mysettings.mycpv, all_keys,
1320                 myrepo=mysettings.get("PORTAGE_REPO_NAME"))))
1321
1322         class FakeTree(object):
1323                 def __init__(self, mydb):
1324                         self.dbapi = mydb
1325
1326         root_config = RootConfig(mysettings, {"porttree":FakeTree(mydbapi)}, None)
1327
1328         pkg = Package(built=False, cpv=mysettings.mycpv,
1329                 metadata=metadata, root_config=root_config,
1330                 type_name="ebuild")
1331
1332         msgs = []
1333         if pkg.invalid:
1334                 for k, v in pkg.invalid.items():
1335                         for msg in v:
1336                                 msgs.append("  %s\n" % (msg,))
1337
1338         if msgs:
1339                 portage.util.writemsg_level(_("Error(s) in metadata for '%s':\n") % \
1340                         (mysettings.mycpv,), level=logging.ERROR, noiselevel=-1)
1341                 for x in msgs:
1342                         portage.util.writemsg_level(x,
1343                                 level=logging.ERROR, noiselevel=-1)
1344                 if mydo not in invalid_dep_exempt_phases:
1345                         return 1
1346
1347         if not pkg.built and \
1348                 mydo not in ("digest", "help", "manifest") and \
1349                 pkg._metadata["REQUIRED_USE"] and \
1350                 eapi_has_required_use(pkg.eapi):
1351                 result = check_required_use(pkg._metadata["REQUIRED_USE"],
1352                         pkg.use.enabled, pkg.iuse.is_valid_flag, eapi=pkg.eapi)
1353                 if not result:
1354                         reduced_noise = result.tounicode()
1355                         writemsg("\n  %s\n" % _("The following REQUIRED_USE flag" + \
1356                                 " constraints are unsatisfied:"), noiselevel=-1)
1357                         writemsg("    %s\n" % reduced_noise,
1358                                 noiselevel=-1)
1359                         normalized_required_use = \
1360                                 " ".join(pkg._metadata["REQUIRED_USE"].split())
1361                         if reduced_noise != normalized_required_use:
1362                                 writemsg("\n  %s\n" % _("The above constraints " + \
1363                                         "are a subset of the following complete expression:"),
1364                                         noiselevel=-1)
1365                                 writemsg("    %s\n" % \
1366                                         human_readable_required_use(normalized_required_use),
1367                                         noiselevel=-1)
1368                         writemsg("\n", noiselevel=-1)
1369                         return 1
1370
1371         return os.EX_OK
1372
1373 # XXX This would be to replace getstatusoutput completely.
1374 # XXX Issue: cannot block execution. Deadlock condition.
1375 def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakeroot=0, **keywords):
1376         """
1377         Spawn a subprocess with extra portage-specific options.
1378         Optiosn include:
1379
1380         Sandbox: Sandbox means the spawned process will be limited in its ability t
1381         read and write files (normally this means it is restricted to ${D}/)
1382         SElinux Sandbox: Enables sandboxing on SElinux
1383         Reduced Privileges: Drops privilages such that the process runs as portage:portage
1384         instead of as root.
1385
1386         Notes: os.system cannot be used because it messes with signal handling.  Instead we
1387         use the portage.process spawn* family of functions.
1388
1389         This function waits for the process to terminate.
1390
1391         @param mystring: Command to run
1392         @type mystring: String
1393         @param mysettings: Either a Dict of Key,Value pairs or an instance of portage.config
1394         @type mysettings: Dictionary or config instance
1395         @param debug: Ignored
1396         @type debug: Boolean
1397         @param free: Enable sandboxing for this process
1398         @type free: Boolean
1399         @param droppriv: Drop to portage:portage when running this command
1400         @type droppriv: Boolean
1401         @param sesandbox: Enable SELinux Sandboxing (toggles a context switch)
1402         @type sesandbox: Boolean
1403         @param fakeroot: Run this command with faked root privileges
1404         @type fakeroot: Boolean
1405         @param keywords: Extra options encoded as a dict, to be passed to spawn
1406         @type keywords: Dictionary
1407         @rtype: Integer
1408         @return:
1409         1. The return code of the spawned process.
1410         """
1411
1412         check_config_instance(mysettings)
1413
1414         fd_pipes = keywords.get("fd_pipes")
1415         if fd_pipes is None:
1416                 fd_pipes = {
1417                         0:portage._get_stdin().fileno(),
1418                         1:sys.__stdout__.fileno(),
1419                         2:sys.__stderr__.fileno(),
1420                 }
1421         # In some cases the above print statements don't flush stdout, so
1422         # it needs to be flushed before allowing a child process to use it
1423         # so that output always shows in the correct order.
1424         stdout_filenos = (sys.__stdout__.fileno(), sys.__stderr__.fileno())
1425         for fd in fd_pipes.values():
1426                 if fd in stdout_filenos:
1427                         sys.__stdout__.flush()
1428                         sys.__stderr__.flush()
1429                         break
1430
1431         features = mysettings.features
1432         # TODO: Enable fakeroot to be used together with droppriv.  The
1433         # fake ownership/permissions will have to be converted to real
1434         # permissions in the merge phase.
1435         fakeroot = fakeroot and uid != 0 and portage.process.fakeroot_capable
1436         portage_build_uid = os.getuid()
1437         portage_build_gid = os.getgid()
1438         if uid == 0 and portage_uid and portage_gid and hasattr(os, "setgroups"):
1439                 if droppriv:
1440                         keywords.update({
1441                                 "uid": portage_uid,
1442                                 "gid": portage_gid,
1443                                 "groups": userpriv_groups,
1444                                 "umask": 0o02
1445                         })
1446                 if "userpriv" in features and "userpriv" not in mysettings["PORTAGE_RESTRICT"].split() and secpass >= 2:
1447                         portage_build_uid = portage_uid
1448                         portage_build_gid = portage_gid
1449         mysettings["PORTAGE_BUILD_USER"] = pwd.getpwuid(portage_build_uid).pw_name
1450         mysettings["PORTAGE_BUILD_GROUP"] = grp.getgrgid(portage_build_gid).gr_name
1451
1452         if not free:
1453                 free=((droppriv and "usersandbox" not in features) or \
1454                         (not droppriv and "sandbox" not in features and \
1455                         "usersandbox" not in features and not fakeroot))
1456
1457         if not free and not (fakeroot or portage.process.sandbox_capable):
1458                 free = True
1459
1460         if mysettings.mycpv is not None:
1461                 keywords["opt_name"] = "[%s]" % mysettings.mycpv
1462         else:
1463                 keywords["opt_name"] = "[%s/%s]" % \
1464                         (mysettings.get("CATEGORY",""), mysettings.get("PF",""))
1465
1466         if free or "SANDBOX_ACTIVE" in os.environ:
1467                 keywords["opt_name"] += " bash"
1468                 spawn_func = portage.process.spawn_bash
1469         elif fakeroot:
1470                 keywords["opt_name"] += " fakeroot"
1471                 keywords["fakeroot_state"] = os.path.join(mysettings["T"], "fakeroot.state")
1472                 spawn_func = portage.process.spawn_fakeroot
1473         else:
1474                 keywords["opt_name"] += " sandbox"
1475                 spawn_func = portage.process.spawn_sandbox
1476
1477         if sesandbox:
1478                 spawn_func = selinux.spawn_wrapper(spawn_func,
1479                         mysettings["PORTAGE_SANDBOX_T"])
1480
1481         if keywords.get("returnpid"):
1482                 return spawn_func(mystring, env=mysettings.environ(), **keywords)
1483
1484         proc = EbuildSpawnProcess(
1485                 background=False, args=mystring,
1486                 scheduler=SchedulerInterface(portage._internal_caller and
1487                         global_event_loop() or EventLoop(main=False)),
1488                 spawn_func=spawn_func,
1489                 settings=mysettings, **keywords)
1490
1491         proc.start()
1492         proc.wait()
1493
1494         return proc.returncode
1495
1496 # parse actionmap to spawn ebuild with the appropriate args
1497 def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
1498         logfile=None, fd_pipes=None, returnpid=False):
1499
1500         if returnpid:
1501                 warnings.warn("portage.spawnebuild() called " + \
1502                         "with returnpid parameter enabled. This usage will " + \
1503                         "not be supported in the future.",
1504                         DeprecationWarning, stacklevel=2)
1505
1506         if not returnpid and \
1507                 (alwaysdep or "noauto" not in mysettings.features):
1508                 # process dependency first
1509                 if "dep" in actionmap[mydo]:
1510                         retval = spawnebuild(actionmap[mydo]["dep"], actionmap,
1511                                 mysettings, debug, alwaysdep=alwaysdep, logfile=logfile,
1512                                 fd_pipes=fd_pipes, returnpid=returnpid)
1513                         if retval:
1514                                 return retval
1515
1516         eapi = mysettings["EAPI"]
1517
1518         if mydo in ("configure", "prepare") and not eapi_has_src_prepare_and_src_configure(eapi):
1519                 return os.EX_OK
1520
1521         if mydo == "pretend" and not eapi_has_pkg_pretend(eapi):
1522                 return os.EX_OK
1523
1524         if not (mydo == "install" and "noauto" in mysettings.features):
1525                 check_file = os.path.join(
1526                         mysettings["PORTAGE_BUILDDIR"], ".%sed" % mydo.rstrip('e'))
1527                 if os.path.exists(check_file):
1528                         writemsg_stdout(_(">>> It appears that "
1529                                 "'%(action)s' has already executed for '%(pkg)s'; skipping.\n") %
1530                                 {"action":mydo, "pkg":mysettings["PF"]})
1531                         writemsg_stdout(_(">>> Remove '%(file)s' to force %(action)s.\n") %
1532                                 {"file":check_file, "action":mydo})
1533                         return os.EX_OK
1534
1535         return _spawn_phase(mydo, mysettings,
1536                 actionmap=actionmap, logfile=logfile,
1537                 fd_pipes=fd_pipes, returnpid=returnpid)
1538
1539 _post_phase_cmds = {
1540
1541         "install" : [
1542                 "install_qa_check",
1543                 "install_symlink_html_docs",
1544                 "install_hooks"],
1545
1546         "preinst" : [
1547                 "preinst_sfperms",
1548                 "preinst_selinux_labels",
1549                 "preinst_suid_scan",
1550                 ]
1551 }
1552
1553 def _post_phase_userpriv_perms(mysettings):
1554         if "userpriv" in mysettings.features and secpass >= 2:
1555                 """ Privileged phases may have left files that need to be made
1556                 writable to a less privileged user."""
1557                 apply_recursive_permissions(mysettings["T"],
1558                         uid=portage_uid, gid=portage_gid, dirmode=0o70, dirmask=0,
1559                         filemode=0o60, filemask=0)
1560
1561 def _check_build_log(mysettings, out=None):
1562         """
1563         Search the content of $PORTAGE_LOG_FILE if it exists
1564         and generate the following QA Notices when appropriate:
1565
1566           * Automake "maintainer mode"
1567           * command not found
1568           * Unrecognized configure options
1569         """
1570         logfile = mysettings.get("PORTAGE_LOG_FILE")
1571         if logfile is None:
1572                 return
1573         try:
1574                 f = open(_unicode_encode(logfile, encoding=_encodings['fs'],
1575                         errors='strict'), mode='rb')
1576         except EnvironmentError:
1577                 return
1578
1579         f_real = None
1580         if logfile.endswith('.gz'):
1581                 f_real = f
1582                 f =  gzip.GzipFile(filename='', mode='rb', fileobj=f)
1583
1584         am_maintainer_mode = []
1585         bash_command_not_found = []
1586         bash_command_not_found_re = re.compile(
1587                 r'(.*): line (\d*): (.*): command not found$')
1588         command_not_found_exclude_re = re.compile(r'/configure: line ')
1589         helper_missing_file = []
1590         helper_missing_file_re = re.compile(
1591                 r'^!!! (do|new).*: .* does not exist$')
1592
1593         configure_opts_warn = []
1594         configure_opts_warn_re = re.compile(
1595                 r'^configure: WARNING: [Uu]nrecognized options: (.*)')
1596
1597         qa_configure_opts = ""
1598         try:
1599                 with io.open(_unicode_encode(os.path.join(
1600                         mysettings["PORTAGE_BUILDDIR"],
1601                         "build-info", "QA_CONFIGURE_OPTIONS"),
1602                         encoding=_encodings['fs'], errors='strict'),
1603                         mode='r', encoding=_encodings['repo.content'],
1604                         errors='replace') as qa_configure_opts_f:
1605                         qa_configure_opts = qa_configure_opts_f.read()
1606         except IOError as e:
1607                 if e.errno not in (errno.ENOENT, errno.ESTALE):
1608                         raise
1609
1610         qa_configure_opts = qa_configure_opts.split()
1611         if qa_configure_opts:
1612                 if len(qa_configure_opts) > 1:
1613                         qa_configure_opts = "|".join("(%s)" % x for x in qa_configure_opts)
1614                         qa_configure_opts = "^(%s)$" % qa_configure_opts
1615                 else:
1616                         qa_configure_opts = "^%s$" % qa_configure_opts[0]
1617                 qa_configure_opts = re.compile(qa_configure_opts)
1618
1619         qa_am_maintainer_mode = []
1620         try:
1621                 with io.open(_unicode_encode(os.path.join(
1622                         mysettings["PORTAGE_BUILDDIR"],
1623                         "build-info", "QA_AM_MAINTAINER_MODE"),
1624                         encoding=_encodings['fs'], errors='strict'),
1625                         mode='r', encoding=_encodings['repo.content'],
1626                         errors='replace') as qa_am_maintainer_mode_f:
1627                         qa_am_maintainer_mode = [x for x in
1628                                 qa_am_maintainer_mode_f.read().splitlines() if x]
1629         except IOError as e:
1630                 if e.errno not in (errno.ENOENT, errno.ESTALE):
1631                         raise
1632
1633         if qa_am_maintainer_mode:
1634                 if len(qa_am_maintainer_mode) > 1:
1635                         qa_am_maintainer_mode = \
1636                                 "|".join("(%s)" % x for x in qa_am_maintainer_mode)
1637                         qa_am_maintainer_mode = "^(%s)$" % qa_am_maintainer_mode
1638                 else:
1639                         qa_am_maintainer_mode = "^%s$" % qa_am_maintainer_mode[0]
1640                 qa_am_maintainer_mode = re.compile(qa_am_maintainer_mode)
1641
1642         # Exclude output from dev-libs/yaz-3.0.47 which looks like this:
1643         #
1644         #Configuration:
1645         #  Automake:                   ${SHELL} /var/tmp/portage/dev-libs/yaz-3.0.47/work/yaz-3.0.47/config/missing --run automake-1.10
1646         am_maintainer_mode_re = re.compile(r'/missing --run ')
1647         am_maintainer_mode_exclude_re = \
1648                 re.compile(r'(/missing --run (autoheader|autotest|help2man|makeinfo)|^\s*Automake:\s)')
1649
1650         make_jobserver_re = \
1651                 re.compile(r'g?make\[\d+\]: warning: jobserver unavailable:')
1652         make_jobserver = []
1653
1654         def _eerror(lines):
1655                 for line in lines:
1656                         eerror(line, phase="install", key=mysettings.mycpv, out=out)
1657
1658         try:
1659                 for line in f:
1660                         line = _unicode_decode(line)
1661                         if am_maintainer_mode_re.search(line) is not None and \
1662                                 am_maintainer_mode_exclude_re.search(line) is None and \
1663                                 (not qa_am_maintainer_mode or
1664                                         qa_am_maintainer_mode.search(line) is None):
1665                                 am_maintainer_mode.append(line.rstrip("\n"))
1666
1667                         if bash_command_not_found_re.match(line) is not None and \
1668                                 command_not_found_exclude_re.search(line) is None:
1669                                 bash_command_not_found.append(line.rstrip("\n"))
1670
1671                         if helper_missing_file_re.match(line) is not None:
1672                                 helper_missing_file.append(line.rstrip("\n"))
1673
1674                         m = configure_opts_warn_re.match(line)
1675                         if m is not None:
1676                                 for x in m.group(1).split(", "):
1677                                         if not qa_configure_opts or qa_configure_opts.match(x) is None:
1678                                                 configure_opts_warn.append(x)
1679
1680                         if make_jobserver_re.match(line) is not None:
1681                                 make_jobserver.append(line.rstrip("\n"))
1682
1683         except zlib.error as e:
1684                 _eerror(["portage encountered a zlib error: '%s'" % (e,),
1685                         "while reading the log file: '%s'" % logfile])
1686         finally:
1687                 f.close()
1688
1689         def _eqawarn(lines):
1690                 for line in lines:
1691                         eqawarn(line, phase="install", key=mysettings.mycpv, out=out)
1692         wrap_width = 70
1693
1694         if am_maintainer_mode:
1695                 msg = [_("QA Notice: Automake \"maintainer mode\" detected:")]
1696                 msg.append("")
1697                 msg.extend("\t" + line for line in am_maintainer_mode)
1698                 msg.append("")
1699                 msg.extend(wrap(_(
1700                         "If you patch Makefile.am, "
1701                         "configure.in,  or configure.ac then you "
1702                         "should use autotools.eclass and "
1703                         "eautomake or eautoreconf. Exceptions "
1704                         "are limited to system packages "
1705                         "for which it is impossible to run "
1706                         "autotools during stage building. "
1707                         "See http://www.gentoo.org/p"
1708                         "roj/en/qa/autofailure.xml for more information."),
1709                         wrap_width))
1710                 _eqawarn(msg)
1711
1712         if bash_command_not_found:
1713                 msg = [_("QA Notice: command not found:")]
1714                 msg.append("")
1715                 msg.extend("\t" + line for line in bash_command_not_found)
1716                 _eqawarn(msg)
1717
1718         if helper_missing_file:
1719                 msg = [_("QA Notice: file does not exist:")]
1720                 msg.append("")
1721                 msg.extend("\t" + line[4:] for line in helper_missing_file)
1722                 _eqawarn(msg)
1723
1724         if configure_opts_warn:
1725                 msg = [_("QA Notice: Unrecognized configure options:")]
1726                 msg.append("")
1727                 msg.extend("\t%s" % x for x in configure_opts_warn)
1728                 _eqawarn(msg)
1729
1730         if make_jobserver:
1731                 msg = [_("QA Notice: make jobserver unavailable:")]
1732                 msg.append("")
1733                 msg.extend("\t" + line for line in make_jobserver)
1734                 _eqawarn(msg)
1735
1736         f.close()
1737         if f_real is not None:
1738                 f_real.close()
1739
1740 def _post_src_install_write_metadata(settings):
1741         """
1742         It's possible that the ebuild has changed the
1743         CHOST variable, so revert it to the initial
1744         setting. Also, revert IUSE in case it's corrupted
1745         due to local environment settings like in bug #386829.
1746         """
1747
1748         eapi_attrs = _get_eapi_attrs(settings.configdict['pkg']['EAPI'])
1749
1750         build_info_dir = os.path.join(settings['PORTAGE_BUILDDIR'], 'build-info')
1751
1752         metadata_keys = ['IUSE']
1753         if eapi_attrs.iuse_effective:
1754                 metadata_keys.append('IUSE_EFFECTIVE')
1755
1756         for k in metadata_keys:
1757                 v = settings.configdict['pkg'].get(k)
1758                 if v is not None:
1759                         write_atomic(os.path.join(build_info_dir, k), v + '\n')
1760
1761         # The following variables are irrelevant for virtual packages.
1762         if settings.get('CATEGORY') != 'virtual':
1763
1764                 for k in ('CHOST',):
1765                         v = settings.get(k)
1766                         if v is not None:
1767                                 write_atomic(os.path.join(build_info_dir, k), v + '\n')
1768
1769         with io.open(_unicode_encode(os.path.join(build_info_dir,
1770                 'BUILD_TIME'), encoding=_encodings['fs'], errors='strict'),
1771                 mode='w', encoding=_encodings['repo.content'],
1772                 errors='strict') as f:
1773                 f.write(_unicode_decode("%.0f\n" % (time.time(),)))
1774
1775         use = frozenset(settings['PORTAGE_USE'].split())
1776         for k in _vdb_use_conditional_keys:
1777                 v = settings.configdict['pkg'].get(k)
1778                 filename = os.path.join(build_info_dir, k)
1779                 if v is None:
1780                         try:
1781                                 os.unlink(filename)
1782                         except OSError:
1783                                 pass
1784                         continue
1785
1786                 if k.endswith('DEPEND'):
1787                         if eapi_attrs.slot_operator:
1788                                 continue
1789                         token_class = Atom
1790                 else:
1791                         token_class = None
1792
1793                 v = use_reduce(v, uselist=use, token_class=token_class)
1794                 v = paren_enclose(v)
1795                 if not v:
1796                         try:
1797                                 os.unlink(filename)
1798                         except OSError:
1799                                 pass
1800                         continue
1801                 with io.open(_unicode_encode(os.path.join(build_info_dir,
1802                         k), encoding=_encodings['fs'], errors='strict'),
1803                         mode='w', encoding=_encodings['repo.content'],
1804                         errors='strict') as f:
1805                         f.write(_unicode_decode(v + '\n'))
1806
1807         if eapi_attrs.slot_operator:
1808                 deps = evaluate_slot_operator_equal_deps(settings, use, QueryCommand.get_db())
1809                 for k, v in deps.items():
1810                         filename = os.path.join(build_info_dir, k)
1811                         if not v:
1812                                 try:
1813                                         os.unlink(filename)
1814                                 except OSError:
1815                                         pass
1816                                 continue
1817                         with io.open(_unicode_encode(os.path.join(build_info_dir,
1818                                 k), encoding=_encodings['fs'], errors='strict'),
1819                                 mode='w', encoding=_encodings['repo.content'],
1820                                 errors='strict') as f:
1821                                 f.write(_unicode_decode(v + '\n'))
1822
1823 def _preinst_bsdflags(mysettings):
1824         if bsd_chflags:
1825                 # Save all the file flags for restoration later.
1826                 os.system("mtree -c -p %s -k flags > %s" % \
1827                         (_shell_quote(mysettings["D"]),
1828                         _shell_quote(os.path.join(mysettings["T"], "bsdflags.mtree"))))
1829
1830                 # Remove all the file flags to avoid EPERM errors.
1831                 os.system("chflags -R noschg,nouchg,nosappnd,nouappnd %s" % \
1832                         (_shell_quote(mysettings["D"]),))
1833                 os.system("chflags -R nosunlnk,nouunlnk %s 2>/dev/null" % \
1834                         (_shell_quote(mysettings["D"]),))
1835
1836
1837 def _postinst_bsdflags(mysettings):
1838         if bsd_chflags:
1839                 # Restore all of the flags saved above.
1840                 os.system("mtree -e -p %s -U -k flags < %s > /dev/null" % \
1841                         (_shell_quote(mysettings["ROOT"]),
1842                         _shell_quote(os.path.join(mysettings["T"], "bsdflags.mtree"))))
1843
1844 def _post_src_install_uid_fix(mysettings, out):
1845         """
1846         Files in $D with user and group bits that match the "portage"
1847         user or group are automatically mapped to PORTAGE_INST_UID and
1848         PORTAGE_INST_GID if necessary. The chown system call may clear
1849         S_ISUID and S_ISGID bits, so those bits are restored if
1850         necessary.
1851         """
1852
1853         os = _os_merge
1854
1855         inst_uid = int(mysettings["PORTAGE_INST_UID"])
1856         inst_gid = int(mysettings["PORTAGE_INST_GID"])
1857
1858         _preinst_bsdflags(mysettings)
1859
1860         destdir = mysettings["D"]
1861         ed_len = len(mysettings["ED"])
1862         unicode_errors = []
1863         desktop_file_validate = \
1864                 portage.process.find_binary("desktop-file-validate") is not None
1865         xdg_dirs = mysettings.get('XDG_DATA_DIRS', '/usr/share').split(':')
1866         xdg_dirs = tuple(os.path.join(i, "applications") + os.sep
1867                 for i in xdg_dirs if i)
1868
1869         qa_desktop_file = ""
1870         try:
1871                 with io.open(_unicode_encode(os.path.join(
1872                         mysettings["PORTAGE_BUILDDIR"],
1873                         "build-info", "QA_DESKTOP_FILE"),
1874                         encoding=_encodings['fs'], errors='strict'),
1875                         mode='r', encoding=_encodings['repo.content'],
1876                         errors='replace') as f:
1877                         qa_desktop_file = f.read()
1878         except IOError as e:
1879                 if e.errno not in (errno.ENOENT, errno.ESTALE):
1880                         raise
1881
1882         qa_desktop_file = qa_desktop_file.split()
1883         if qa_desktop_file:
1884                 if len(qa_desktop_file) > 1:
1885                         qa_desktop_file = "|".join("(%s)" % x for x in qa_desktop_file)
1886                         qa_desktop_file = "^(%s)$" % qa_desktop_file
1887                 else:
1888                         qa_desktop_file = "^%s$" % qa_desktop_file[0]
1889                 qa_desktop_file = re.compile(qa_desktop_file)
1890
1891         while True:
1892
1893                 unicode_error = False
1894                 size = 0
1895                 counted_inodes = set()
1896                 fixlafiles_announced = False
1897                 fixlafiles = "fixlafiles" in mysettings.features
1898                 desktopfile_errors = []
1899
1900                 for parent, dirs, files in os.walk(destdir):
1901                         try:
1902                                 parent = _unicode_decode(parent,
1903                                         encoding=_encodings['merge'], errors='strict')
1904                         except UnicodeDecodeError:
1905                                 new_parent = _unicode_decode(parent,
1906                                         encoding=_encodings['merge'], errors='replace')
1907                                 new_parent = _unicode_encode(new_parent,
1908                                         encoding='ascii', errors='backslashreplace')
1909                                 new_parent = _unicode_decode(new_parent,
1910                                         encoding=_encodings['merge'], errors='replace')
1911                                 os.rename(parent, new_parent)
1912                                 unicode_error = True
1913                                 unicode_errors.append(new_parent[ed_len:])
1914                                 break
1915
1916                         for fname in chain(dirs, files):
1917                                 try:
1918                                         fname = _unicode_decode(fname,
1919                                                 encoding=_encodings['merge'], errors='strict')
1920                                 except UnicodeDecodeError:
1921                                         fpath = _os.path.join(
1922                                                 parent.encode(_encodings['merge']), fname)
1923                                         new_fname = _unicode_decode(fname,
1924                                                 encoding=_encodings['merge'], errors='replace')
1925                                         new_fname = _unicode_encode(new_fname,
1926                                                 encoding='ascii', errors='backslashreplace')
1927                                         new_fname = _unicode_decode(new_fname,
1928                                                 encoding=_encodings['merge'], errors='replace')
1929                                         new_fpath = os.path.join(parent, new_fname)
1930                                         os.rename(fpath, new_fpath)
1931                                         unicode_error = True
1932                                         unicode_errors.append(new_fpath[ed_len:])
1933                                         fname = new_fname
1934                                         fpath = new_fpath
1935                                 else:
1936                                         fpath = os.path.join(parent, fname)
1937
1938                                 fpath_relative = fpath[ed_len - 1:]
1939                                 if desktop_file_validate and fname.endswith(".desktop") and \
1940                                         os.path.isfile(fpath) and \
1941                                         fpath_relative.startswith(xdg_dirs) and \
1942                                         not (qa_desktop_file and qa_desktop_file.match(fpath_relative.strip(os.sep)) is not None):
1943
1944                                         desktop_validate = validate_desktop_entry(fpath)
1945                                         if desktop_validate:
1946                                                 desktopfile_errors.extend(desktop_validate)
1947
1948                                 if fixlafiles and \
1949                                         fname.endswith(".la") and os.path.isfile(fpath):
1950                                         f = open(_unicode_encode(fpath,
1951                                                 encoding=_encodings['merge'], errors='strict'),
1952                                                 mode='rb')
1953                                         has_lafile_header = b'.la - a libtool library file' \
1954                                                 in f.readline()
1955                                         f.seek(0)
1956                                         contents = f.read()
1957                                         f.close()
1958                                         try:
1959                                                 needs_update, new_contents = rewrite_lafile(contents)
1960                                         except portage.exception.InvalidData as e:
1961                                                 needs_update = False
1962                                                 if not fixlafiles_announced:
1963                                                         fixlafiles_announced = True
1964                                                         writemsg("Fixing .la files\n", fd=out)
1965
1966                                                 # Suppress warnings if the file does not have the
1967                                                 # expected header (bug #340725). Even if the header is
1968                                                 # missing, we still call rewrite_lafile() since some
1969                                                 # valid libtool archives may not have the header.
1970                                                 msg = "   %s is not a valid libtool archive, skipping\n" % fpath[len(destdir):]
1971                                                 qa_msg = "QA Notice: invalid .la file found: %s, %s" % (fpath[len(destdir):], e)
1972                                                 if has_lafile_header:
1973                                                         writemsg(msg, fd=out)
1974                                                         eqawarn(qa_msg, key=mysettings.mycpv, out=out)
1975
1976                                         if needs_update:
1977                                                 if not fixlafiles_announced:
1978                                                         fixlafiles_announced = True
1979                                                         writemsg("Fixing .la files\n", fd=out)
1980                                                 writemsg("   %s\n" % fpath[len(destdir):], fd=out)
1981                                                 # write_atomic succeeds even in some cases in which
1982                                                 # a normal write might fail due to file permission
1983                                                 # settings on some operating systems such as HP-UX
1984                                                 write_atomic(_unicode_encode(fpath,
1985                                                         encoding=_encodings['merge'], errors='strict'),
1986                                                         new_contents, mode='wb')
1987
1988                                 mystat = os.lstat(fpath)
1989                                 if stat.S_ISREG(mystat.st_mode) and \
1990                                         mystat.st_ino not in counted_inodes:
1991                                         counted_inodes.add(mystat.st_ino)
1992                                         size += mystat.st_size
1993                                 if mystat.st_uid != portage_uid and \
1994                                         mystat.st_gid != portage_gid:
1995                                         continue
1996                                 myuid = -1
1997                                 mygid = -1
1998                                 if mystat.st_uid == portage_uid:
1999                                         myuid = inst_uid
2000                                 if mystat.st_gid == portage_gid:
2001                                         mygid = inst_gid
2002                                 apply_secpass_permissions(
2003                                         _unicode_encode(fpath, encoding=_encodings['merge']),
2004                                         uid=myuid, gid=mygid,
2005                                         mode=mystat.st_mode, stat_cached=mystat,
2006                                         follow_links=False)
2007
2008                         if unicode_error:
2009                                 break
2010
2011                 if not unicode_error:
2012                         break
2013
2014         if desktopfile_errors:
2015                 for l in _merge_desktopfile_error(desktopfile_errors):
2016                         l = l.replace(mysettings["ED"], '/')
2017                         eqawarn(l, phase='install', key=mysettings.mycpv, out=out)
2018
2019         if unicode_errors:
2020                 for l in _merge_unicode_error(unicode_errors):
2021                         eqawarn(l, phase='install', key=mysettings.mycpv, out=out)
2022
2023         build_info_dir = os.path.join(mysettings['PORTAGE_BUILDDIR'],
2024                 'build-info')
2025
2026         f = io.open(_unicode_encode(os.path.join(build_info_dir,
2027                 'SIZE'), encoding=_encodings['fs'], errors='strict'),
2028                 mode='w', encoding=_encodings['repo.content'],
2029                 errors='strict')
2030         f.write(_unicode_decode(str(size) + '\n'))
2031         f.close()
2032
2033         _reapply_bsdflags_to_image(mysettings)
2034
2035 def _reapply_bsdflags_to_image(mysettings):
2036         """
2037         Reapply flags saved and removed by _preinst_bsdflags.
2038         """
2039         if bsd_chflags:
2040                 os.system("mtree -e -p %s -U -k flags < %s > /dev/null" % \
2041                         (_shell_quote(mysettings["D"]),
2042                         _shell_quote(os.path.join(mysettings["T"], "bsdflags.mtree"))))
2043
2044 def _post_src_install_soname_symlinks(mysettings, out):
2045         """
2046         Check that libraries in $D have corresponding soname symlinks.
2047         If symlinks are missing then create them and trigger a QA Notice.
2048         This requires $PORTAGE_BUILDDIR/build-info/NEEDED.ELF.2 for
2049         operation.
2050         """
2051
2052         image_dir = mysettings["D"]
2053         needed_filename = os.path.join(mysettings["PORTAGE_BUILDDIR"],
2054                 "build-info", "NEEDED.ELF.2")
2055
2056         f = None
2057         try:
2058                 f = io.open(_unicode_encode(needed_filename,
2059                         encoding=_encodings['fs'], errors='strict'),
2060                         mode='r', encoding=_encodings['repo.content'],
2061                         errors='replace')
2062                 lines = f.readlines()
2063         except IOError as e:
2064                 if e.errno not in (errno.ENOENT, errno.ESTALE):
2065                         raise
2066                 return
2067         finally:
2068                 if f is not None:
2069                         f.close()
2070
2071         qa_no_symlink = ""
2072         f = None
2073         try:
2074                 f = io.open(_unicode_encode(os.path.join(
2075                         mysettings["PORTAGE_BUILDDIR"],
2076                         "build-info", "QA_SONAME_NO_SYMLINK"),
2077                         encoding=_encodings['fs'], errors='strict'),
2078                         mode='r', encoding=_encodings['repo.content'],
2079                         errors='replace')
2080                 qa_no_symlink = f.read()
2081         except IOError as e:
2082                 if e.errno not in (errno.ENOENT, errno.ESTALE):
2083                         raise
2084         finally:
2085                 if f is not None:
2086                         f.close()
2087
2088         qa_no_symlink = qa_no_symlink.split()
2089         if qa_no_symlink:
2090                 if len(qa_no_symlink) > 1:
2091                         qa_no_symlink = "|".join("(%s)" % x for x in qa_no_symlink)
2092                         qa_no_symlink = "^(%s)$" % qa_no_symlink
2093                 else:
2094                         qa_no_symlink = "^%s$" % qa_no_symlink[0]
2095                 qa_no_symlink = re.compile(qa_no_symlink)
2096
2097         libpaths = set(portage.util.getlibpaths(
2098                 mysettings["ROOT"], env=mysettings))
2099         libpath_inodes = set()
2100         for libpath in libpaths:
2101                 libdir = os.path.join(mysettings["ROOT"], libpath.lstrip(os.sep))
2102                 try:
2103                         s = os.stat(libdir)
2104                 except OSError:
2105                         continue
2106                 else:
2107                         libpath_inodes.add((s.st_dev, s.st_ino))
2108
2109         is_libdir_cache = {}
2110
2111         def is_libdir(obj_parent):
2112                 try:
2113                         return is_libdir_cache[obj_parent]
2114                 except KeyError:
2115                         pass
2116
2117                 rval = False
2118                 if obj_parent in libpaths:
2119                         rval = True
2120                 else:
2121                         parent_path = os.path.join(mysettings["ROOT"],
2122                                 obj_parent.lstrip(os.sep))
2123                         try:
2124                                 s = os.stat(parent_path)
2125                         except OSError:
2126                                 pass
2127                         else:
2128                                 if (s.st_dev, s.st_ino) in libpath_inodes:
2129                                         rval = True
2130
2131                 is_libdir_cache[obj_parent] = rval
2132                 return rval
2133
2134         missing_symlinks = []
2135
2136         # Parse NEEDED.ELF.2 like LinkageMapELF.rebuild() does.
2137         for l in lines:
2138                 l = l.rstrip("\n")
2139                 if not l:
2140                         continue
2141                 fields = l.split(";")
2142                 if len(fields) < 5:
2143                         portage.util.writemsg_level(_("\nWrong number of fields " \
2144                                 "in %s: %s\n\n") % (needed_filename, l),
2145                                 level=logging.ERROR, noiselevel=-1)
2146                         continue
2147
2148                 obj, soname = fields[1:3]
2149                 if not soname:
2150                         continue
2151                 if not is_libdir(os.path.dirname(obj)):
2152                         continue
2153                 if qa_no_symlink and qa_no_symlink.match(obj.strip(os.sep)) is not None:
2154                         continue
2155
2156                 obj_file_path = os.path.join(image_dir, obj.lstrip(os.sep))
2157                 sym_file_path = os.path.join(os.path.dirname(obj_file_path), soname)
2158                 try:
2159                         os.lstat(sym_file_path)
2160                 except OSError as e:
2161                         if e.errno not in (errno.ENOENT, errno.ESTALE):
2162                                 raise
2163                 else:
2164                         continue
2165
2166                 missing_symlinks.append((obj, soname))
2167
2168         if not missing_symlinks:
2169                 return
2170
2171         qa_msg = ["QA Notice: Missing soname symlink(s):"]
2172         qa_msg.append("")
2173         qa_msg.extend("\t%s -> %s" % (os.path.join(
2174                 os.path.dirname(obj).lstrip(os.sep), soname),
2175                 os.path.basename(obj))
2176                 for obj, soname in missing_symlinks)
2177         qa_msg.append("")
2178         for line in qa_msg:
2179                 eqawarn(line, key=mysettings.mycpv, out=out)
2180
2181 def _merge_desktopfile_error(errors):
2182         lines = []
2183
2184         msg = _("QA Notice: This package installs one or more .desktop files "
2185                 "that do not pass validation.")
2186         lines.extend(wrap(msg, 72))
2187
2188         lines.append("")
2189         errors.sort()
2190         lines.extend("\t" + x for x in errors)
2191         lines.append("")
2192
2193         return lines
2194
2195 def _merge_unicode_error(errors):
2196         lines = []
2197
2198         msg = _("QA Notice: This package installs one or more file names "
2199                 "containing characters that are not encoded with the UTF-8 encoding.")
2200         lines.extend(wrap(msg, 72))
2201
2202         lines.append("")
2203         errors.sort()
2204         lines.extend("\t" + x for x in errors)
2205         lines.append("")
2206
2207         return lines
2208
2209 def _prepare_self_update(settings):
2210         """
2211         Call this when portage is updating itself, in order to create
2212         temporary copies of PORTAGE_BIN_PATH and PORTAGE_PYM_PATH, since
2213         the new versions may be incompatible. An atexit hook will
2214         automatically clean up the temporary copies.
2215         """
2216
2217         # sanity check: ensure that that this routine only runs once
2218         if portage._bin_path != portage.const.PORTAGE_BIN_PATH:
2219                 return
2220
2221         # Load lazily referenced portage submodules into memory,
2222         # so imports won't fail during portage upgrade/downgrade.
2223         _preload_elog_modules(settings)
2224         portage.proxy.lazyimport._preload_portage_submodules()
2225
2226         # Make the temp directory inside $PORTAGE_TMPDIR/portage, since
2227         # it's common for /tmp and /var/tmp to be mounted with the
2228         # "noexec" option (see bug #346899).
2229         build_prefix = os.path.join(settings["PORTAGE_TMPDIR"], "portage")
2230         portage.util.ensure_dirs(build_prefix)
2231         base_path_tmp = tempfile.mkdtemp(
2232                 "", "._portage_reinstall_.", build_prefix)
2233         portage.process.atexit_register(shutil.rmtree, base_path_tmp)
2234
2235         orig_bin_path = portage._bin_path
2236         portage._bin_path = os.path.join(base_path_tmp, "bin")
2237         shutil.copytree(orig_bin_path, portage._bin_path, symlinks=True)
2238
2239         orig_pym_path = portage._pym_path
2240         portage._pym_path = os.path.join(base_path_tmp, "pym")
2241         shutil.copytree(orig_pym_path, portage._pym_path, symlinks=True)
2242
2243         for dir_path in (base_path_tmp, portage._bin_path, portage._pym_path):
2244                 os.chmod(dir_path, 0o755)
2245
2246 def _handle_self_update(settings, vardb):
2247         cpv = settings.mycpv
2248         if settings["ROOT"] == "/" and \
2249                 portage.dep.match_from_list(
2250                 portage.const.PORTAGE_PACKAGE_ATOM, [cpv]):
2251                 _prepare_self_update(settings)
2252                 return True
2253         return False