[pacman-dev] [PATCH] lib/conflict: avoid conflict with unchanged effective path

Dave Reisner d at falconindy.com
Mon Jul 16 10:06:45 EDT 2012


On Sat, Jul 14, 2012 at 11:21:50PM -0400, Dave Reisner wrote:
> This applies to a case such as when /lib is a symlink to /usr/lib. If a
> package is installed which contains /lib/libfoo.so, pacman will complain
> if this package is then "fixed" to contain /usr/lib/libfoo.so. Since
> these have the same effective path and it exists within the same
> package, ignore the conflict.
> 
> Fixes FS#30681.
> 
> Signed-off-by: Dave Reisner <dreisner at archlinux.org>
> ---

So as I discovered last night, this doesn't deal with broken symlinks.
For example, if you symlink /bin or /sbin to usr/bin, and then install a
package like kmod, you end up with:

  /usr/bin/modprobe -> ../usr/bin/kmod

Which is an orphaned link. The realpath(3) call will fail, and the
conflict won't be resolved. Fixing this seems like we need to emulate
the behavior of GNU readlink's -m flag, where we simply canonicalize as
much as we can (stepping through piece by piece in the path) and then
resolving the remainder with heuristics (squeezing successive slashes
and handling ../). This is ugly...

> Written against maint.
> 
>  lib/libalpm/conflict.c               | 34 ++++++++++++++++++++++++++++++++++
>  test/pacman/tests/fileconflict013.py | 20 ++++++++++++++++++++
>  2 files changed, 54 insertions(+)
>  create mode 100644 test/pacman/tests/fileconflict013.py
> 
> diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
> index d6e5d8c..64dd5b0 100644
> --- a/lib/libalpm/conflict.c
> +++ b/lib/libalpm/conflict.c
> @@ -314,6 +314,28 @@ void _alpm_fileconflict_free(alpm_fileconflict_t *conflict)
>  	FREE(conflict);
>  }
>  
> +static const alpm_file_t *_alpm_filelist_contains_resolved(alpm_filelist_t *filelist,
> +		const char *name, const char *root, size_t rootlen)
> +{
> +	size_t i;
> +	const alpm_file_t *file;
> +
> +	if(!filelist) {
> +		return NULL;
> +	}
> +
> +	for(file = filelist->files, i = 0; i < filelist->count; file++, i++) {
> +		char fullpath[PATH_MAX], abspath[PATH_MAX];
> +		snprintf(fullpath, sizeof(fullpath), "%s%s", root, file->name);
> +		if(realpath(fullpath, abspath)) {
> +			if(strcmp(&abspath[rootlen], name) == 0) {
> +				return file;
> +			}
> +		}
> +	}
> +	return NULL;
> +}
> +
>  const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist,
>  		const char *name)
>  {
> @@ -579,6 +601,18 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,
>  				free(rpath);
>  			}
>  
> +			/* check if any of the package's own files resolve to the conflict to
> +			 * prevent problems with, e.g. /lib/liba.so moving to /usr/lib/liba.so
> +			 * when /lib is a symlink to usr/lib */
> +			if(!resolved_conflict && dbpkg && !S_ISDIR(lsbuf.st_mode)) {
> +				if(_alpm_filelist_contains_resolved(alpm_pkg_get_files(dbpkg),
> +							relative_path, handle->root, rootlen)) {
> +					_alpm_log(handle, ALPM_LOG_DEBUG,
> +							"package contained a realpath resolved to a package file\n");
> +					resolved_conflict = 1;
> +				}
> +			}
> +
>  			/* is the file unowned and in the backup list of the new package? */
>  			if(!resolved_conflict && _alpm_needbackup(filestr, p1)) {
>  				alpm_list_t *local_pkgs = _alpm_db_get_pkgcache(handle->db_local);
> diff --git a/test/pacman/tests/fileconflict013.py b/test/pacman/tests/fileconflict013.py
> new file mode 100644
> index 0000000..a83923c
> --- /dev/null
> +++ b/test/pacman/tests/fileconflict013.py
> @@ -0,0 +1,20 @@
> +self.description = "file->file path change with same effective path (/lib as symlink)"
> +
> +lp1 = pmpkg("filesystem", "1.0-1")
> +lp1.files = ["usr/",
> +             "usr/lib/",
> +             "lib -> usr/lib/"]
> +self.addpkg2db("local", lp1)
> +
> +lp2 = pmpkg("pkg1", "1.0-1")
> +lp2.files = ["lib/libfoo.so"]
> +self.addpkg2db("local", lp2)
> +
> +sp1 = pmpkg("pkg1", "1.0-2")
> +sp1.files = ["usr/lib/libfoo.so"]
> +self.addpkg2db("sync", sp1)
> +
> +self.args = "-Su"
> +
> +self.addrule("PACMAN_RETCODE=0")
> +self.addrule("PKG_VERSION=pkg1|1.0-2")
> -- 
> 1.7.11.2
> 


More information about the pacman-dev mailing list