Merged from trunk 7792:7838
authorFabian Groffen <grobian@gentoo.org>
Sat, 29 Sep 2007 20:25:12 +0000 (20:25 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 29 Sep 2007 20:25:12 +0000 (20:25 -0000)
   | 7793     | When --with-bdeps=y is enabled for built packages, pull in  |
   | zmedico  | build time deps as requested, but marked them as            |
   |          | "satisfied" since they are not strictly required. This      |
   |          | allows more freedom in the merge order calculation for      |
   |          | solving circular dependencies. Don't convert to PDEPEND     |
   |          | since that could make --with-bdeps=y less effective if it   |
   |          | is used to adjust merge order to prevent built_with_use()   |
   |          | calls from failing.                                         |

   | 7794     | Flush stdout before calling pkg_info() to ensure that       |
   | zmedico  | output always shows in the correct order.                   |

   | 7795     | Flush stderr and stdout if their file descriptors are in    |
   | zmedico  | fd_pipes at the beginning of spawn().                       |

   | 7796     | In spawn(), initialize default fd_pipes before doing the    |
   | zmedico  | stdout/stderr flush.                                        |

   | 7797     | When --deep is not enabled, many dependencies are dicarded  |
   | zmedico  | and left out of the digraph. This patch prevents            |
   |          | dependencies from being discarded in some cases where the   |
   |          | are needed in order to optimize merge order. It also        |
   |          | modifies the DepPriority.rebuild attribute so that it only  |
   |          | applies to build time dependencies. This leads to better    |
   |          | merge order in some cases when --deep is not enabled. For   |
   |          | example, `emerge xf86-input-keyboard xorg-server` will now  |
   |          | properly merge xorg-server before xf86-input-keyboard       |
   |          | (problem from bug #192254, comment #5).                     |

   | 7798     | tweak get_config() so that it only executes one external    |
   | SpankMan | binary (sed) instead of chaining multiple ones              |

   | 7799     | fix possible information leak vulnerability when doing a    |
   | SpankMan | merge of configuration files and be better about handling   |
   |          | of whitespace in $TMP in a few places                       |

   | 7800     | s/note/not/ reported by p-y.                                |
   | zmedico  |                                                             |

   | 7801     | Bug #190179 - Use `prelink --verify filename` to write the  |
   | zmedico  | temp file via stdout since --undo fails when run as a       |
   |          | normal non-superuser because it tries to chown the output   |
   |          | file. Also, use mkstemp() to eliminate the need for locking |
   |          | the temp file. Thanks to Israel G. Lugo                     |
   |          | <israel.lugo@lugosys.com> for the initial patch.            |

   | 7802     | Initialize ${TMP} before registering the die trap so that   |
   | zmedico  | we're sure which directory die will clean up.               |

   | 7803     | Bug #74615 - Quote all file paths inside dispatch-conf      |
   | zmedico  | shell commands.                                             |

   | 7804     | Bugs #168772 and #193695 - During unmerge, only ignore      |
   | zmedico  | specific exceptions raised from unlink() and rmdir() calls. |

   | 7805     | Bug #193695 - Add support for FreeBSD chflags during        |
   | zmedico  | unmerge. This code is adapted from the code that already    |
   |          | exists in movefile() for the merge phase.                   |

   | 7806     | In movefile() FreeBSD chflags handling, use chflags instead |
   | zmedico  | of lchflags when temporarily adjusting the flags on the     |
   |          | parent directory since we want to follow any symlinks to    |
   |          | the real parent directory.                                  |

   | 7807     | Bug #193695 - Add FreeBSD chflags support for rmdir() calls |
   | zmedico  | during unmerge.                                             |

   | 7808     | Bug #192341 - Eliminate the dependency on py-freebsd by     |
   | zmedico  | implementing it's chflags() and lchflags() functions as     |
   |          | wrappers around the chflags command (which should always be |
   |          | available in any case). The functions are only called when  |
   |          | merging/unmerging files that actually have flags set so the |
   |          | performance difference should be negligible.                |

   | 7834     | Bug #192341 - When the chflags command does not exit        |
   | zmedico  | successfully, try to generate an informative error. First,  |
   |          | use stat or lstat to try and generate an ENOENT error. It   |
   |          | the path exists, verify that the chflags binary exists and  |
   |          | raise CommandNotFound if necessary. Finally, simply         |
   |          | generate an EPERM OSError with the output of the command    |
   |          | since we're not sure exactly why it failed or what the real |
   |          | errno was.                                                  |

   | 7835     | Set non-blocking mode on the pty master file descriptor     |
   | zmedico  | while the slave file descriptor is still held open since    |
   |          | otherwise the fcntl call can fail on FreeBSD (the child     |
   |          | process might have already exited and closed the slave file |
   |          | descriptor so we have to keep it open in order to avoid     |
   |          | FreeBSD potentially generating an EAGAIN exception). This   |
   |          | appoach is cleaner than triggering the exception and being  |
   |          | forced to handle it somehow.                                |

   | 7838     | Bug #192706 - Do not print a summary at the end of          |
   | zmedico  | --depclean if there is nothing to clean and --quiet is      |
   |          | enabled.                                                    |

svn path=/main/branches/prefix/; revision=7882

bin/dispatch-conf
bin/etc-update
cnf/dispatch-conf.conf
man/repoman.1
pym/emerge/__init__.py
pym/portage/__init__.py
pym/portage/checksum.py
pym/portage/dbapi/vartree.py
pym/portage/dispatch_conf.py

index 972cf117cacf61f4c38a890eba9a670481383bd8..439af5d45b11f145db8406fffad27d6559d854f3 100755 (executable)
@@ -29,9 +29,9 @@ from portage import dispatch_conf, const
 from portage.process import find_binary
 
 FIND_EXTANT_CONFIGS  = "find '%s' %s -iname '._cfg????_%s' ! -iname '.*~' ! -iname '.*.bak'"
-DIFF_CONTENTS        = 'diff -Nu %s %s'
-DIFF_CVS_INTERP      = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "# .Header:.*"'
-DIFF_WSCOMMENTS      = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "^[-+]#" | grep -v "^[-+][:space:]*$"'
+DIFF_CONTENTS        = "diff -Nu '%s' '%s'"
+DIFF_CVS_INTERP      = "diff -Nu '%s' '%s' | grep '^[+-][^+-]' | grep -v '# .Header:.*'"
+DIFF_WSCOMMENTS      = "diff -Nu '%s' '%s' | grep '^[+-][^+-]' | grep -v '^[-+]#' | grep -v '^[-+][:space:]*$'"
 
 # We need a secure scratch dir and python does silly verbose errors on the use of tempnam
 oldmask = os.umask(0077)
index e99cd08737fc9b9ecbc0618bf37784319139e018..a59227c3660b5417faa43911a39f6eb495a9665c 100755 (executable)
@@ -17,15 +17,21 @@ if type -P gsed >/dev/null ; then
 fi
 
 function get_config() {
-       item=$1
-
-       # First strip off comment lines, then grab the configuration
-       # item. If there's more than one of the same configuration item,
-       # then allow the last setting to take precedence.
-       local result
-       result=$(cut -d'#' -f1-1 ${PORTAGE_CONFIGROOT}etc/etc-update.conf | \
-               sed -ne "s/^ *$item *= *\([\"']\{0,1\}\)\(.*\)\1/\2/p" |sed -e '$p;d')
-       eval echo $result
+       # the sed here does:
+       #  - strip off comments
+       #  - match lines that set item in question
+       #    - delete the "item =" part
+       #    - store the actual value into the hold space
+       #  - on the last line, restore the hold space and print it
+       # If there's more than one of the same configuration item, then
+       # the store to the hold space clobbers previous value so the last
+       # setting takes precedence.
+       local item=$1
+       eval echo $(sed -n \
+               -e 's:[[:space:]]*#.*$::' \
+               -e "/^[[:space:]]*$item[[:space:]]*=/{s:[^=]*=[[:space:]]*\([\"']\{0,1\}\)\(.*\)\1:\2:;h}" \
+               -e '${g;p}' \
+               "${PORTAGE_CONFIGROOT}"etc/etc-update.conf)
 }
 
 function scan() {
@@ -361,18 +367,26 @@ Please select from the menu above (-1 to ignore this update): "
 }
 
 function do_merge() {
+       # make sure we keep the merged file in the secure tempdir
+       # so we dont leak any information contained in said file
+       # (think of case where the file has 0600 perms; during the
+       # merging process, the temp file gets umask perms!)
 
        local file="${1}"
        local ofile="${2}"
-       local mfile="${2}.merged"
+       local mfile="${TMP}/${2}.merged"
        local -i my_input=0
        echo "${file} ${ofile} ${mfile}"
 
-       if [ -e ${mfile} ] ; then
+       if [[ -e ${mfile} ]] ; then
                echo "A previous version of the merged file exists, cleaning..."
-               rm ${rm_opts} ${mfile}
+               rm ${rm_opts} "${mfile}"
        fi
 
+       # since mfile will be like $TMP/path/to/original-file.merged, we
+       # need to make sure the full /path/to/ exists ahead of time
+       mkdir -p "${mfile%/*}"
+
        until (( ${my_input} == -1 )); do
                echo "Merging ${file} and ${ofile}"
                $(echo "${merge_command}" |
@@ -396,8 +410,8 @@ Please select from the menu above (-1 to exit, losing this merge): "
                                       chown "$(stat -f %Su:%Sg "${ofile}")" "${mfile}"
                                       chmod $(stat -f %Mp%Lp "${ofile}") "${mfile}"
                                   fi
-                                  mv ${mv_opts} ${mfile} ${ofile}
-                                  rm ${rm_opts} ${file}
+                                  mv ${mv_opts} "${mfile}" "${ofile}"
+                                  rm ${rm_opts} "${file}"
                                   return 255
                                   ;;
                                2) ( echo "Showing differences between ${ofile} and ${mfile}"
@@ -411,7 +425,7 @@ Please select from the menu above (-1 to exit, losing this merge): "
                                4) ${EDITOR:-nano -w} "${mfile}"
                                   continue
                                         ;;
-                               5) rm ${rm_opts} ${mfile}
+                               5) rm ${rm_opts} "${mfile}"
                                   return 0
                                   ;;
                                *) continue
@@ -419,7 +433,7 @@ Please select from the menu above (-1 to exit, losing this merge): "
                        esac
                done
        done
-       rm ${rm_opts} ${mfile}
+       rm ${rm_opts} "${mfile}"
        return 255
 }
 
@@ -433,7 +447,7 @@ function die() {
                [ ${count} -gt 0 ] && echo "NOTE: ${count} updates remaining"
        fi
 
-       rm -rf ${TMP}
+       rm -rf "${TMP}"
        exit ${2}
 }
 
@@ -442,6 +456,7 @@ function die() {
 #
 scriptname=$(basename $0)
 
+TMP="${PORTAGE_TMPDIR}/etc-update-$$"
 trap die term
 
 type portageq > /dev/null || exit $?
@@ -459,9 +474,11 @@ PORTAGE_CONFIGROOT=${PORTAGE_CONFIGROOT}${EPREFIX}/
 #echo $CONFIG_PROTECT_MASK
 #export PORTAGE_TMPDIR=$(/usr/lib/portage/bin/portageq envvar PORTAGE_TMPDIR)
 
-TMP="${PORTAGE_TMPDIR}/$$"
-rm -rf ${TMP} 2> /dev/null
-mkdir ${TMP} || die "failed mkdir command!" 1
+rm -rf "${TMP}" 2> /dev/null
+mkdir "${TMP}" || die "failed to create temp dir" 1
+# make sure we have a secure directory to work in
+chmod 0700 "${TMP}" || die "failed to set perms on temp dir" 1
+chown ${UID:-0}:${GID:-0} "${TMP}" || die "failed to set ownership on temp dir" 1
 
 # I need the CONFIG_PROTECT value
 #CONFIG_PROTECT=$(@PORTAGE_BASE@/bin/portageq envvar CONFIG_PROTECT)
index 5a1a39a722a0fd6be7b4d7e6d7239af25e39015c..6a94a52ec93b031dac86f3663cd4c797b152a110 100644 (file)
@@ -12,13 +12,13 @@ use-rcs=no
 # Diff for display
 # %s old file
 # %s new file
-diff="diff -Nu %s %s | less --no-init --QUIT-AT-EOF"
+diff="diff -Nu '%s' '%s' | less --no-init --QUIT-AT-EOF"
 
 # Diff for interactive merges.
 # %s output file
 # %s old file
 # %s new file
-merge="sdiff --suppress-common-lines --output=%s %s %s"
+merge="sdiff --suppress-common-lines --output='%s' '%s' '%s'"
 
 # Automerge files comprising only CVS interpolations (e.g. Header or Id)
 # (yes or no)
index 98efbed09c2cad6030bc706de1860afad81e96b7..7b97a0abcb7fcc35a53f0abd1363af552ebdb76c 100644 (file)
@@ -226,7 +226,7 @@ Error generating cache entry for ebuild; typically caused by ebuild syntax error
 File is not UTF8 compliant
 .TP
 .B file.executable
-Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do note need the executable bit
+Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do not need the executable bit
 .TP
 .B file.name
 File/dir name must be composed of only the following chars: a-zA-Z0-9._-+:
index 9b282f0a28831a25356f23497ba98c6791a1bf46..eff84886fac9c82afe12cd53e4348f2a30eb5d04 100644 (file)
@@ -716,9 +716,9 @@ class DepPriority(object):
                                return -1
                        if self.runtime_post:
                                return -2
-               if self.rebuild:
-                       return -3
                if self.buildtime:
+                       if self.rebuild:
+                               return -3
                        return -4
                if self.runtime:
                        return -5
@@ -1356,11 +1356,20 @@ class depgraph(object):
                        if "--buildpkgonly" in self.myopts:
                                edepend["RDEPEND"] = ""
                                edepend["PDEPEND"] = ""
-               if not (arg and "--onlydeps" in self.myopts and \
-                       mytype == "ebuild") and \
-                       self.myopts.get("--with-bdeps", "n") == "n" and \
-                       (mytype == "binary" or mybigkey[3] == "nomerge"):
-                       edepend["DEPEND"] = ""
+               bdeps_satisfied = False
+               if mytype in ("installed", "binary"):
+                       if self.myopts.get("--with-bdeps", "n") == "y":
+                               # Pull in build time deps as requested, but marked them as
+                               # "satisfied" since they are not strictly required. This allows
+                               # more freedom in the merge order calculation for solving
+                               # circular dependencies. Don't convert to PDEPEND since that
+                               # could make --with-bdeps=y less effective if it is used to
+                               # adjust merge order to prevent built_with_use() calls from
+                               # failing.
+                               bdeps_satisfied = True
+                       else:
+                               # built packages do not have build time dependencies.
+                               edepend["DEPEND"] = ""
 
                """ We have retrieve the dependency information, now we need to recursively
                    process them.  DEPEND gets processed for root = "/", {R,P}DEPEND in myroot. """
@@ -1369,7 +1378,8 @@ class depgraph(object):
 
                try:
                        if not self.select_dep("/", edepend["DEPEND"], myparent=mp,
-                               myuse=myuse, priority=DepPriority(buildtime=True),
+                               myuse=myuse, priority=DepPriority(buildtime=True,
+                               satisfied=bdeps_satisfied),
                                parent_arg=arg):
                                return 0
                        """RDEPEND is soft by definition.  However, in order to ensure
@@ -1726,17 +1736,6 @@ class depgraph(object):
                                                ("blocks", p_root, x[1:]), set()).add(myparent)
                                continue
                        else:
-                               #We are not processing a blocker but a normal dependency
-                               if myparent:
-                                       """In some cases, dep_check will return deps that shouldn't
-                                       be proccessed any further, so they are identified and
-                                       discarded here."""
-                                       if "empty" not in self.myparams and \
-                                               "deep" not in self.myparams and \
-                                               not ("--update" in self.myopts and parent_arg) and \
-                                               vardb.match(x):
-                                               continue
-
                                # List of acceptable packages, ordered by type preference.
                                matched_packages = []
                                myeb_matches = portdb.xmatch("match-visible", x)
@@ -1956,6 +1955,29 @@ class depgraph(object):
                                # ordered by type preference ("ebuild" type is the last resort)
                                selected_pkg =  matched_packages[0]
 
+                               # In some cases, dep_check will return deps that shouldn't
+                               # be proccessed any further, so they are identified and
+                               # discarded here. Try to discard as few as possible since
+                               # discarded dependencies reduce the amount of information
+                               # available for optimization of merge order.
+                               if myparent and not arg and vardb.match(x) and \
+                                       not existing_node and \
+                                       "empty" not in self.myparams and \
+                                       "deep" not in self.myparams and \
+                                       not ("--update" in self.myopts and parent_arg):
+                                       (mytype, myroot, mykey), metadata = selected_pkg
+                                       myarg = None
+                                       if myroot == self.target_root:
+                                               try:
+                                                       myarg = self._set_atoms.findAtomForPackage(
+                                                               mykey, metadata)
+                                               except portage.exception.InvalidDependString:
+                                                       # This is already handled inside
+                                                       # self.create() when necessary.
+                                                       pass
+                                       if not myarg:
+                                               continue
+
                        if myparent:
                                #we are a dependency, so we want to be unconditionally added
                                mypriority = priority.copy()
@@ -5769,6 +5791,9 @@ def action_depclean(settings, trees, ldpath_mtimes,
        if action == "prune":
                return
 
+       if not cleanlist and "--quiet" in myopts:
+               return
+
        print "Packages installed:   "+str(len(myvarlist))
        print "Packages in world:    "+str(len(worldlist))
        print "Packages in system:   "+str(len(syslist))
index de86361c6760e56760b828ffa57122a27f73796a..852f7f5f248c2ed0e73e3a3b257b9f72b6095367 100644 (file)
@@ -42,10 +42,32 @@ except ImportError, e:
 
 bsd_chflags = None
 if os.uname()[0] in ["FreeBSD"]:
-       try:
-               import freebsd as bsd_chflags
-       except ImportError:
+       def bsd_chflags():
                pass
+       def _chflags(path, flags, opts=""):
+               cmd = "chflags %s %o '%s'" % (opts, flags, path)
+               status, output = commands.getstatusoutput(cmd)
+               if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
+                       return
+               # Try to generate an ENOENT error if appropriate.
+               if "h" in opts:
+                       os.lstat(path)
+               else:
+                       os.stat(path)
+               # Make sure the binary exists.
+               if not portage.process.find_binary("chflags"):
+                       raise portage.exception.CommandNotFound("chflags")
+               # Now we're not sure exactly why it failed or what
+               # the real errno was, so just report EPERM.
+               e = OSError(errno.EPERM, output)
+               e.errno = errno.EPERM
+               e.filename = path
+               e.message = output
+               raise e
+       def _lchflags(path, flags):
+               return _chflags(path, flags, opts="-h")
+       bsd_chflags.chflags = _chflags
+       bsd_chflags.lchflags = _lchflags
 
 try:
        from portage.cache.cache_errors import CacheError
@@ -2394,6 +2416,18 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
                env=mysettings.environ()
                keywords["opt_name"]="[%s]" % mysettings["PF"]
 
+       fd_pipes = keywords.get("fd_pipes")
+       if fd_pipes is None:
+               fd_pipes = {0:0, 1:1, 2:2}
+       # In some cases the above print statements don't flush stdout, so
+       # it needs to be flushed before allowing a child process to use it
+       # so that output always shows in the correct order.
+       for fd in fd_pipes.itervalues():
+               if fd == sys.stdout.fileno():
+                       sys.stdout.flush()
+               if fd == sys.stderr.fileno():
+                       sys.stderr.flush()
+
        # The default policy for the sesandbox domain only allows entry (via exec)
        # from shells and from binaries that belong to portage (the number of entry
        # points is minimized).  The "tee" binary is not among the allowed entry
@@ -2407,10 +2441,7 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
        got_pty = False
        if logfile:
                del keywords["logfile"]
-               fd_pipes = keywords.get("fd_pipes")
-               if fd_pipes is None:
-                       fd_pipes = {0:0, 1:1, 2:2}
-               elif 1 not in fd_pipes or 2 not in fd_pipes:
+               if 1 not in fd_pipes or 2 not in fd_pipes:
                        raise ValueError(fd_pipes)
                from pty import openpty
                try:
@@ -2420,6 +2451,16 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
                        writemsg("openpty failed: '%s'\n" % str(e), noiselevel=1)
                        del e
                        master_fd, slave_fd = os.pipe()
+
+               # We must set non-blocking mode before we close the slave_fd
+               # since otherwise the fcntl call can fail on FreeBSD (the child
+               # process might have already exited and closed slave_fd so we
+               # have to keep it open in order to avoid FreeBSD potentially
+               # generating an EAGAIN exception).
+               import fcntl
+               fcntl.fcntl(master_fd, fcntl.F_SETFL,
+                       fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
                fd_pipes.setdefault(0, sys.stdin.fileno())
                fd_pipes_orig = fd_pipes.copy()
                if got_pty and os.isatty(fd_pipes_orig[1]):
@@ -2466,7 +2507,7 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
        try:
                mypids.extend(spawn_func(mystring, env=env, **keywords))
        finally:
-               if slave_fd:
+               if logfile:
                        os.close(slave_fd)
                if sesandbox:
                        selinux.setexec(None)
@@ -2481,26 +2522,14 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
                iwtd = [master_file]
                owtd = []
                ewtd = []
-               import array, fcntl, select
-               fd_flags = {}
-               for f in iwtd:
-                       fd_flags[f] = fcntl.fcntl(f.fileno(), fcntl.F_GETFL)
+               import array, select
                buffsize = 65536
                eof = False
-               # Use non-blocking mode to prevent read
-               # calls from blocking indefinitely.
-               try:
-                       fcntl.fcntl(master_file.fileno(), fcntl.F_SETFL,
-                               fd_flags[master_file] | os.O_NONBLOCK)
-               except EnvironmentError, e:
-                       if e.errno != errno.EAGAIN:
-                               raise
-                       del e
-                       # The EAGAIN error signals eof on FreeBSD.
-                       eof = True
                while not eof:
                        events = select.select(iwtd, owtd, ewtd)
                        for f in events[0]:
+                               # Use non-blocking mode to prevent read
+                               # calls from blocking indefinitely.
                                buf = array.array('B')
                                try:
                                        buf.fromfile(f, buffsize)
@@ -4191,9 +4220,11 @@ def movefile(src,dest,newmtime=None,sstat=None,mysettings=None):
        if bsd_chflags:
                if destexists and dstat.st_flags != 0:
                        bsd_chflags.lchflags(dest, 0)
+               # Use normal stat/chflags for the parent since we want to
+               # follow any symlinks to the real parent directory.
                pflags = os.stat(os.path.dirname(dest)).st_flags
                if pflags != 0:
-                       bsd_chflags.lchflags(os.path.dirname(dest), 0)
+                       bsd_chflags.chflags(os.path.dirname(dest), 0)
 
        if destexists:
                if stat.S_ISLNK(dstat[stat.ST_MODE]):
@@ -4300,7 +4331,7 @@ def movefile(src,dest,newmtime=None,sstat=None,mysettings=None):
        if bsd_chflags:
                # Restore the flags we saved before moving
                if pflags:
-                       bsd_chflags.lchflags(os.path.dirname(dest), pflags)
+                       bsd_chflags.chflags(os.path.dirname(dest), pflags)
 
        return newmtime
 
index fa00247ab1c70fb569eb58ead6b668df661b433f..c663b68d9987664601b7f302afe9b27a86569859 100644 (file)
@@ -7,6 +7,7 @@ from portage.const import PRIVATE_PATH,PRELINK_BINARY,HASHING_BLOCKSIZE
 import os
 import errno
 import stat
+import tempfile
 import portage.exception
 import portage.process
 import portage.locks
@@ -198,16 +199,19 @@ def perform_checksum(filename, hashname="MD5", calc_prelink=0):
        """
        global prelink_capable
        myfilename      = filename[:]
-       prelink_tmpfile = os.path.join("/", PRIVATE_PATH, "prelink-checksum.tmp." + str(os.getpid()))
+       prelink_tmpfile = None
        mylock          = None
        try:
                if calc_prelink and prelink_capable:
-                       mylock = portage.locks.lockfile(prelink_tmpfile, wantnewlockfile=1)
                        # Create non-prelinked temporary file to checksum.
                        # Files rejected by prelink are summed in place.
                        try:
-                               retval = portage.process.spawn([PRELINK_BINARY, "--undo", "-o",
-                                       prelink_tmpfile, filename], fd_pipes={})
+                               tmpfile_fd, prelink_tmpfile = tempfile.mkstemp()
+                               try:
+                                       retval = portage.process.spawn([PRELINK_BINARY,
+                                               "--verify", filename], fd_pipes={1:tmpfile_fd})
+                               finally:
+                                       os.close(tmpfile_fd)
                                if retval == os.EX_OK:
                                        myfilename = prelink_tmpfile
                        except portage.exception.CommandNotFound:
@@ -222,7 +226,7 @@ def perform_checksum(filename, hashname="MD5", calc_prelink=0):
                        if e.errno == errno.ENOENT:
                                raise portage.exception.FileNotFound(myfilename)
                        raise
-               if calc_prelink and prelink_capable:
+               if prelink_tmpfile:
                        try:
                                os.unlink(prelink_tmpfile)
                        except OSError, e:
index 855b2b5b8212568bdaa4230e9b1cef560257ff1e..064db4d2fb8382f6fe6a8db2171175119a48d7d4 100644 (file)
@@ -1184,7 +1184,30 @@ class dblink(object):
 
                        #process symlinks second-to-last, directories last.
                        mydirs = []
+                       ignored_unlink_errnos = (errno.ENOENT, errno.EISDIR)
                        modprotect = os.path.join(self.vartree.root, "lib/modules/")
+
+                       def unlink(file_name, lstatobj):
+                               if bsd_chflags:
+                                       if lstatobj.st_flags != 0:
+                                               bsd_chflags.lchflags(file_name, 0)
+                                       parent_name = os.path.dirname(file_name)
+                                       # Use normal stat/chflags for the parent since we want to
+                                       # follow any symlinks to the real parent directory.
+                                       pflags = os.stat(parent_name).st_flags
+                                       if pflags != 0:
+                                               bsd_chflags.chflags(parent_name, 0)
+                               try:
+                                       if not stat.S_ISLNK(lstatobj.st_mode):
+                                               # Remove permissions to ensure that any hardlinks to
+                                               # suid/sgid files are rendered harmless.
+                                               os.chmod(file_name, 0)
+                                       os.unlink(file_name)
+                               finally:
+                                       if bsd_chflags and pflags != 0:
+                                               # Restore the parent flags we saved before unlinking
+                                               bsd_chflags.chflags(parent_name, pflags)
+
                        def show_unmerge(zing, desc, file_type, file_name):
                                        writemsg_stdout("%s %s %s %s\n" % \
                                                (zing, desc.ljust(8), file_type, file_name))
@@ -1234,13 +1257,11 @@ class dblink(object):
                                        not (islink and statobj and stat.S_ISDIR(statobj.st_mode)) and \
                                        not self.isprotected(obj):
                                        try:
-                                               # Remove permissions to ensure that any hardlinks to
-                                               # suid/sgid files are rendered harmless.
-                                               if statobj and not islink:
-                                                       os.chmod(obj, 0)
-                                               os.unlink(obj)
+                                               unlink(obj, lstatobj)
                                        except EnvironmentError, e:
-                                               pass
+                                               if e.errno not in ignored_unlink_errnos:
+                                                       raise
+                                               del e
                                        show_unmerge("<<<", "", file_type, obj)
                                        continue
 
@@ -1266,9 +1287,12 @@ class dblink(object):
                                        # contents as a directory even if it happens to correspond
                                        # to a symlink when it's merged to the live filesystem.
                                        try:
-                                               os.unlink(obj)
+                                               unlink(obj, lstatobj)
                                                show_unmerge("<<<", "", file_type, obj)
                                        except (OSError, IOError),e:
+                                               if e.errno not in ignored_unlink_errnos:
+                                                       raise
+                                               del e
                                                show_unmerge("!!!", "", file_type, obj)
                                elif pkgfiles[objkey][0] == "obj":
                                        if statobj is None or not stat.S_ISREG(statobj.st_mode):
@@ -1288,13 +1312,11 @@ class dblink(object):
                                                show_unmerge("---", "!md5", file_type, obj)
                                                continue
                                        try:
-                                               # Remove permissions to ensure that any hardlinks to
-                                               # suid/sgid files are rendered harmless.
-                                               if not islink:
-                                                       os.chmod(obj, 0)
-                                               os.unlink(obj)
+                                               unlink(obj, lstatobj)
                                        except (OSError, IOError), e:
-                                               pass
+                                               if e.errno not in ignored_unlink_errnos:
+                                                       raise
+                                               del e
                                        show_unmerge("<<<", "", file_type, obj)
                                elif pkgfiles[objkey][0] == "fif":
                                        if not stat.S_ISFIFO(lstatobj[stat.ST_MODE]):
@@ -1309,10 +1331,31 @@ class dblink(object):
 
                        for obj in mydirs:
                                try:
-                                       os.rmdir(obj)
+                                       if bsd_chflags:
+                                               lstatobj = os.lstat(obj)
+                                               if lstatobj.st_flags != 0:
+                                                       bsd_chflags.lchflags(obj, 0)
+                                               parent_name = os.path.dirname(obj)
+                                               # Use normal stat/chflags for the parent since we want to
+                                               # follow any symlinks to the real parent directory.
+                                               pflags = os.stat(parent_name).st_flags
+                                               if pflags != 0:
+                                                       bsd_chflags.chflags(parent_name, 0)
+                                       try:
+                                               os.rmdir(obj)
+                                       finally:
+                                               if bsd_chflags and pflags != 0:
+                                                       # Restore the parent flags we saved before unlinking
+                                                       bsd_chflags.chflags(parent_name, pflags)
                                        show_unmerge("<<<", "", "dir", obj)
-                               except EnvironmentError:
-                                       show_unmerge("---", "!empty", "dir", obj)
+                               except EnvironmentError, e:
+                                       if e.errno not in (errno.ENOENT,
+                                               errno.EEXIST, errno.ENOTEMPTY,
+                                               errno.ENOTDIR):
+                                               raise
+                                       if e.errno != errno.ENOENT:
+                                               show_unmerge("---", "!empty", "dir", obj)
+                                       del e
 
                #remove self from vartree database so that our own virtual gets zapped if we're the last node
                self.vartree.zap(self.mycpv)
index b88d2cf73f5491f05838fb71fcd08b2cf5b7dcbe..df256dc7776bcbf5dc5ffc5e2b4bf95c1ffbeb77 100644 (file)
@@ -16,9 +16,9 @@ RCS_BRANCH = '1.1.1'
 RCS_LOCK = 'rcs -ko -M -l'
 RCS_PUT = 'ci -t-"Archived config file." -m"dispatch-conf update."'
 RCS_GET = 'co'
-RCS_MERGE = 'rcsmerge -p -r' + RCS_BRANCH + ' %s >%s'
+RCS_MERGE = "rcsmerge -p -r" + RCS_BRANCH + " '%s' > '%s'"
 
-DIFF3_MERGE = 'diff3 -mE %s %s %s >%s'
+DIFF3_MERGE = "diff3 -mE '%s' '%s' '%s' > '%s'"
 
 def read_config(mandatory_opts):
     try:
@@ -33,7 +33,7 @@ def read_config(mandatory_opts):
     for key in mandatory_opts:
         if not opts.has_key(key):
             if key == "merge":
-                opts["merge"] = "sdiff --suppress-common-lines --output=%s %s %s"
+                opts["merge"] = "sdiff --suppress-common-lines --output='%s' '%s' '%s'"
             else:
                 print >> sys.stderr, 'dispatch-conf: Missing option "%s" in /etc/dispatch-conf.conf; fatal' % (key,)
 
@@ -106,7 +106,7 @@ def file_archive(archive, curconf, newconf, mrgconf):
 
     # Archive the current config file if it isn't already saved
     if os.path.exists(archive) \
-     and len(commands.getoutput('diff -aq %s %s' % (curconf,archive))) != 0:
+     and len(commands.getoutput("diff -aq '%s' '%s'" % (curconf,archive))) != 0:
         suf = 1
         while suf < 9 and os.path.exists(archive + '.' + str(suf)):
             suf += 1