def parse_soname_deps(s): """ Parse a REQUIRES or PROVIDES dependency string, and raise InvalidData if necessary. @param s: REQUIRES or PROVIDES string @type s: str @rtype: iter @return: An iterator of SonameAtom instances """ categories = set() category = None previous_soname = None for soname in s.split(): if soname.endswith(":"): if category is not None and previous_soname is None: raise InvalidData(_error_empty_category % category) category = soname[:-1] previous_soname = None if category in categories: raise InvalidData(_error_duplicate_category % category) categories.add(category) elif category is None: raise InvalidData(_error_missing_category % soname) else: previous_soname = soname yield SonameAtom(category, soname) if category is not None and previous_soname is None: raise InvalidData(_error_empty_category % category)
def parse(cls, filename, line): """ Parse a NEEDED.ELF.2 entry. Raises InvalidData if necessary. @param filename: file name for use in exception messages @type filename: str @param line: a single line of text from a NEEDED.ELF.2 file, without a trailing newline @type line: str @rtype: NeededEntry @return: A new NeededEntry instance containing data from line """ fields = line.split(";") if len(fields) < cls._MIN_FIELDS: raise InvalidData( _("Wrong number of fields " "in %s: %s\n\n") % (filename, line)) obj = cls() # Extra fields may exist (for future extensions). if (len(fields) > cls._MULTILIB_CAT_INDEX and fields[cls._MULTILIB_CAT_INDEX]): obj.multilib_category = fields[cls._MULTILIB_CAT_INDEX] else: obj.multilib_category = None del fields[cls._MIN_FIELDS:] obj.arch, obj.filename, obj.soname, rpaths, needed = fields obj.runpaths = tuple(filter(None, rpaths.split(":"))) obj.needed = tuple(filter(None, needed.split(","))) return obj
def __init__(self, cpv, metadata=None, settings=None, eapi=None, repo=None, slot=None): if not isinstance(cpv, _unicode): # Avoid TypeError from _unicode.__init__ with PyPy. cpv = _unicode_decode(cpv) _unicode.__init__(cpv) if metadata is not None: self.__dict__['_metadata'] = metadata slot = metadata.get('SLOT', slot) repo = metadata.get('repository', repo) eapi = metadata.get('EAPI', eapi) if settings is not None: self.__dict__['_settings'] = settings if eapi is not None: self.__dict__['eapi'] = eapi self.__dict__['cpv_split'] = catpkgsplit(cpv, eapi=eapi) if self.cpv_split is None: raise InvalidData(cpv) self.__dict__['cp'] = self.cpv_split[0] + '/' + self.cpv_split[1] if self.cpv_split[-1] == "r0" and cpv[-3:] != "-r0": self.__dict__['version'] = "-".join(self.cpv_split[2:-1]) else: self.__dict__['version'] = "-".join(self.cpv_split[2:]) # for match_from_list introspection self.__dict__['cpv'] = self if slot is not None: eapi_attrs = _get_eapi_attrs(eapi) slot_match = _get_slot_re(eapi_attrs).match(slot) if slot_match is None: # Avoid an InvalidAtom exception when creating SLOT atoms self.__dict__['slot'] = '0' self.__dict__['sub_slot'] = '0' self.__dict__['slot_invalid'] = slot else: if eapi_attrs.slot_operator: slot_split = slot.split("/") self.__dict__['slot'] = slot_split[0] if len(slot_split) > 1: self.__dict__['sub_slot'] = slot_split[1] else: self.__dict__['sub_slot'] = slot_split[0] else: self.__dict__['slot'] = slot self.__dict__['sub_slot'] = slot if repo is not None: repo = _gen_valid_repo(repo) if not repo: repo = _unknown_repo self.__dict__['repo'] = repo
def _parse_lafile_contents(contents): """ Parses 'dependency_libs' and 'inherited_linker_flags' lines. """ dep_libs = None inh_link_flags = None for line in contents.split(b"\n"): m = dep_libs_re.match(line) if m: if dep_libs is not None: raise InvalidData("duplicated dependency_libs entry") dep_libs = m.group("value") continue m = inh_link_flags_re.match(line) if m: if inh_link_flags is not None: raise InvalidData("duplicated inherited_linker_flags entry") inh_link_flags = m.group("value") continue return dep_libs, inh_link_flags
def parse(cls, filename, line): """ Parse a NEEDED.ELF.2 entry. Raises InvalidData if necessary. @param filename: file name for use in exception messages @type filename: str @param line: a single line of text from a NEEDED.ELF.2 file, without a trailing newline @type line: str @rtype: NeededEntry @return: A new NeededEntry instance containing data from line """ fields = line.split(";") if len(fields) < cls._MIN_FIELDS: raise InvalidData( _("Wrong number of fields " "in %s: %s\n\n") % (filename, line)) obj = cls() # Extra fields may exist (for future extensions). if len(fields) > cls._MULTILIB_CAT_INDEX and fields[ cls._MULTILIB_CAT_INDEX]: obj.multilib_category = fields[cls._MULTILIB_CAT_INDEX] else: obj.multilib_category = None del fields[cls._MIN_FIELDS:] obj.arch, obj.filename, obj.soname, rpaths, needed = fields # We don't use scanelf -q, since that would omit libraries like # musl's /usr/lib/libc.so which do not have any DT_NEEDED or # DT_SONAME settings. Since we don't use scanelf -q, we have to # handle the special rpath value " - " below. rpaths = "" if rpaths == " - " else rpaths obj.runpaths = tuple(filter(None, rpaths.split(":"))) obj.needed = tuple(filter(None, needed.split(","))) return obj
def _lockfile_iteration(mypath, wantnewlockfile=False, unlinkfile=False, waiting_msg=None, flags=0): """ Acquire a lock on mypath, without retry. Return None if the lockfile was removed by previous lock holder (caller must retry). @param mypath: lock file path @type mypath: str @param wantnewlockfile: use a separate new lock file @type wantnewlockfile: bool @param unlinkfile: remove lock file prior to unlock @type unlinkfile: bool @param waiting_msg: message to show before blocking @type waiting_msg: str @param flags: lock flags (only supports os.O_NONBLOCK) @type flags: int @rtype: bool @return: unlockfile tuple on success, None if retry is needed """ if not mypath: raise InvalidData(_("Empty path given")) # Since Python 3.4, chown requires int type (no proxies). portage_gid = int(portage.data.portage_gid) # Support for file object or integer file descriptor parameters is # deprecated due to ambiguity in whether or not it's safe to close # the file descriptor, making it prone to "Bad file descriptor" errors # or file descriptor leaks. if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] lockfilename_path = mypath if hasattr(mypath, 'fileno'): warnings.warn( "portage.locks.lockfile() support for " "file object parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename_path = getattr(mypath, 'name', None) mypath = mypath.fileno() if isinstance(mypath, int): warnings.warn( "portage.locks.lockfile() support for integer file " "descriptor parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") lockfilename_path = lockfilename unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: while True: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE) and os.path.isdir( os.path.dirname(lockfilename)): # Retry required for NFS (see bug 636798). continue else: _raise_exc(e) else: break if not preexisting: try: if portage.data.secpass >= 1 and os.stat( lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): os.close(myfd) return None else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = portage._eintr_func_wrapper(_get_lock_fn()) try: if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: raise IOError(errno.ENOSYS, "Function not implemented") locking_method(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if not hasattr(e, "errno"): raise if e.errno in (errno.EACCES, errno.EAGAIN, errno.ENOLCK): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: os.close(myfd) raise TryAgain(mypath) global _quiet if _quiet: out = None else: out = portage.output.EOutput() if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s") % lockfilename if out is not None: out.ebegin(waiting_msg) # try for the exclusive lock now. enolock_msg_shown = False while True: try: locking_method(myfd, fcntl.LOCK_EX) except EnvironmentError as e: if e.errno == errno.ENOLCK: # This is known to occur on Solaris NFS (see # bug #462694). Assume that the error is due # to temporary exhaustion of record locks, # and loop until one becomes available. if not enolock_msg_shown: enolock_msg_shown = True if isinstance(mypath, int): context_desc = _("Error while waiting " "to lock fd %i") % myfd else: context_desc = _("Error while waiting " "to lock '%s'") % lockfilename writemsg("\n!!! %s: %s\n" % (context_desc, e), noiselevel=-1) time.sleep(_HARDLINK_POLL_LATENCY) continue if out is not None: out.eend(1, str(e)) raise else: break if out is not None: out.eend(os.EX_OK) elif e.errno in (errno.ENOSYS, ): # We're not allowed to lock on this FS. if not isinstance(lockfilename, int): # If a file object was passed in, it's not safe # to close the file descriptor because it may # still be in use. os.close(myfd) lockfilename_path = _unicode_decode(lockfilename_path, encoding=_encodings['fs'], errors='strict') if not isinstance(lockfilename_path, basestring): raise link_success = hardlink_lockfile(lockfilename_path, waiting_msg=waiting_msg, flags=flags) if not link_success: raise lockfilename = lockfilename_path locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and myfd != HARDLINK_FD and unlinkfile: try: removed = _lockfile_was_removed(myfd, lockfilename) except Exception: # Do not leak the file descriptor here. os.close(myfd) raise else: if removed: # Removed by previous lock holder... Caller will retry... os.close(myfd) return None if myfd != HARDLINK_FD: # FD_CLOEXEC is enabled by default in Python >=3.4. if sys.hexversion < 0x3040000: try: fcntl.FD_CLOEXEC except AttributeError: pass else: fcntl.fcntl( myfd, fcntl.F_SETFD, fcntl.fcntl(myfd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC) _open_fds.add(myfd) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def __init__( self, cpv, metadata=None, settings=None, eapi=None, repo=None, slot=None, build_time=None, build_id=None, file_size=None, mtime=None, db=None, ): if not isinstance(cpv, str): # Avoid TypeError from str.__init__ with PyPy. cpv = _unicode_decode(cpv) str.__init__(cpv) if metadata is not None: self.__dict__["_metadata"] = metadata slot = metadata.get("SLOT", slot) repo = metadata.get("repository", repo) eapi = metadata.get("EAPI", eapi) build_time = metadata.get("BUILD_TIME", build_time) file_size = metadata.get("SIZE", file_size) build_id = metadata.get("BUILD_ID", build_id) mtime = metadata.get("_mtime_", mtime) if settings is not None: self.__dict__["_settings"] = settings if db is not None: self.__dict__["_db"] = db if eapi is not None: self.__dict__["eapi"] = eapi self.__dict__["build_time"] = self._long(build_time, 0) self.__dict__["file_size"] = self._long(file_size, None) self.__dict__["build_id"] = self._long(build_id, None) self.__dict__["mtime"] = self._long(mtime, None) self.__dict__["cpv_split"] = catpkgsplit(cpv, eapi=eapi) if self.cpv_split is None: raise InvalidData(cpv) self.__dict__["cp"] = self.cpv_split[0] + "/" + self.cpv_split[1] if self.cpv_split[-1] == "r0" and cpv[-3:] != "-r0": self.__dict__["version"] = "-".join(self.cpv_split[2:-1]) else: self.__dict__["version"] = "-".join(self.cpv_split[2:]) # for match_from_list introspection self.__dict__["cpv"] = self if slot is not None: eapi_attrs = _get_eapi_attrs(eapi) slot_match = _get_slot_re(eapi_attrs).match(slot) if slot_match is None: # Avoid an InvalidAtom exception when creating SLOT atoms self.__dict__["slot"] = "0" self.__dict__["sub_slot"] = "0" self.__dict__["slot_invalid"] = slot else: if eapi_attrs.slot_operator: slot_split = slot.split("/") self.__dict__["slot"] = slot_split[0] if len(slot_split) > 1: self.__dict__["sub_slot"] = slot_split[1] else: self.__dict__["sub_slot"] = slot_split[0] else: self.__dict__["slot"] = slot self.__dict__["sub_slot"] = slot if repo is not None: repo = _gen_valid_repo(repo) if not repo: repo = _unknown_repo self.__dict__["repo"] = repo
def rewrite_lafile(contents): """ Given the contents of an .la file, parse and fix it. This operates with strings of raw bytes (assumed to contain some ascii characters), in order to avoid any potential character encoding issues. Raises 'InvalidData' if the .la file is invalid. @param contents: the contents of a libtool archive file @type contents: bytes @rtype: tuple @return: (True, fixed_contents) if something needed to be fixed, (False, None) otherwise. """ #Parse the 'dependency_libs' and 'inherited_linker_flags' lines. dep_libs, inh_link_flags = \ _parse_lafile_contents(contents) if dep_libs is None: raise InvalidData("missing or invalid dependency_libs") new_dep_libs = [] new_inh_link_flags = [] librpath = [] libladir = [] if inh_link_flags is not None: new_inh_link_flags = inh_link_flags.split() #Check entries in 'dependency_libs'. for dep_libs_entry in dep_libs.split(): if dep_libs_entry.startswith(b"-l"): #-lfoo, keep it if dep_libs_entry not in new_dep_libs: new_dep_libs.append(dep_libs_entry) elif dep_libs_entry.endswith(b".la"): #Two cases: #1) /usr/lib64/libfoo.la, turn it into -lfoo and append -L/usr/lib64 to libladir #2) libfoo.la, keep it dir, file = _os.path.split(dep_libs_entry) if not dir or not file.startswith(b"lib"): if dep_libs_entry not in new_dep_libs: new_dep_libs.append(dep_libs_entry) else: #/usr/lib64/libfoo.la -> -lfoo lib = b"-l" + file[3:-3] if lib not in new_dep_libs: new_dep_libs.append(lib) #/usr/lib64/libfoo.la -> -L/usr/lib64 ladir = b"-L" + dir if ladir not in libladir: libladir.append(ladir) elif dep_libs_entry.startswith(b"-L"): #Do some replacement magic and store them in 'libladir'. #This allows us to place all -L entries at the beginning #of 'dependency_libs'. ladir = dep_libs_entry ladir = X11_local_sub.sub(b"lib", ladir) ladir = pkgconfig_sub1.sub(b"usr", ladir) ladir = pkgconfig_sub2.sub(br"\g<usrlib>", ladir) if ladir not in libladir: libladir.append(ladir) elif dep_libs_entry.startswith(b"-R"): if dep_libs_entry not in librpath: librpath.append(dep_libs_entry) elif flag_re.match(dep_libs_entry): #All this stuff goes into inh_link_flags, if the la file has such an entry. #If it doesn't, they stay in 'dependency_libs'. if inh_link_flags is not None: if dep_libs_entry not in new_inh_link_flags: new_inh_link_flags.append(dep_libs_entry) else: if dep_libs_entry not in new_dep_libs: new_dep_libs.append(dep_libs_entry) else: raise InvalidData("Error: Unexpected entry '%s' in 'dependency_libs'" \ % _unicode_decode(dep_libs_entry)) #What should 'dependency_libs' and 'inherited_linker_flags' look like? expected_dep_libs = b"" for x in (librpath, libladir, new_dep_libs): if x: expected_dep_libs += b" " + b" ".join(x) expected_inh_link_flags = b"" if new_inh_link_flags: expected_inh_link_flags += b" " + b" ".join(new_inh_link_flags) #Don't touch the file if we don't need to, otherwise put the expected values into #'contents' and write it into the la file. changed = False if dep_libs != expected_dep_libs: contents = contents.replace(b"dependency_libs='" + dep_libs + b"'", \ b"dependency_libs='" + expected_dep_libs + b"'") changed = True if inh_link_flags is not None and expected_inh_link_flags != inh_link_flags: contents = contents.replace(b"inherited_linker_flags='" + inh_link_flags + b"'", \ b"inherited_linker_flags='" + expected_inh_link_flags + b"'") changed = True if changed: return True, contents else: return False, None
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ if not mypath: raise InvalidData(_("Empty path given")) # Support for file object or integer file descriptor parameters is # deprecated due to ambiguity in whether or not it's safe to close # the file descriptor, making it prone to "Bad file descriptor" errors # or file descriptor leaks. if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] lockfilename_path = mypath if hasattr(mypath, 'fileno'): warnings.warn( "portage.locks.lockfile() support for " "file object parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename_path = getattr(mypath, 'name', None) mypath = mypath.fileno() if isinstance(mypath, int): warnings.warn( "portage.locks.lockfile() support for integer file " "descriptor parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") lockfilename_path = lockfilename unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile(mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = _default_lock_fn try: if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: raise IOError(errno.ENOSYS, "Function not implemented") locking_method(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if not hasattr(e, "errno"): raise if e.errno in (errno.EACCES, errno.EAGAIN): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: os.close(myfd) raise TryAgain(mypath) global _quiet if _quiet: out = None else: out = portage.output.EOutput() if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s\n") % lockfilename if out is not None: out.ebegin(waiting_msg) # try for the exclusive lock now. try: locking_method(myfd, fcntl.LOCK_EX) except EnvironmentError as e: if out is not None: out.eend(1, str(e)) raise if out is not None: out.eend(os.EX_OK) elif e.errno in (errno.ENOSYS, errno.ENOLCK): # We're not allowed to lock on this FS. if not isinstance(lockfilename, int): # If a file object was passed in, it's not safe # to close the file descriptor because it may # still be in use. os.close(myfd) lockfilename_path = _unicode_decode(lockfilename_path, encoding=_encodings['fs'], errors='strict') if not isinstance(lockfilename_path, basestring): raise link_success = hardlink_lockfile(lockfilename_path, waiting_msg=waiting_msg, flags=flags) if not link_success: raise lockfilename = lockfilename_path locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and \ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) if myfd != HARDLINK_FD: _open_fds.add(myfd) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ import fcntl if not mypath: raise InvalidData(_("Empty path given")) if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] if hasattr(mypath, 'fileno'): mypath = mypath.fileno() if isinstance(mypath, int): lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") del base, tail unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile(mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = fcntl.lockf try: fcntl.lockf(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if "errno" not in dir(e): raise if e.errno in (errno.EACCES, errno.EAGAIN): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: raise TryAgain(mypath) global _quiet out = EOutput() out.quiet = _quiet if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s\n") % lockfilename out.ebegin(waiting_msg) # try for the exclusive lock now. try: fcntl.lockf(myfd, fcntl.LOCK_EX) except EnvironmentError as e: out.eend(1, str(e)) raise out.eend(os.EX_OK) elif e.errno == errno.ENOLCK: # We're not allowed to lock on this FS. os.close(myfd) link_success = False if lockfilename == str(lockfilename): if wantnewlockfile: try: if os.stat(lockfilename)[stat.ST_NLINK] == 1: os.unlink(lockfilename) except OSError: pass link_success = hardlink_lockfile(lockfilename) if not link_success: raise locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and \ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)