[pacman-dev] [PATCH] libalpm: never attempt to remove a mountpoint

Dave Reisner d at falconindy.com
Tue Feb 12 20:42:57 EST 2013


On Wed, Feb 13, 2013 at 11:31:54AM +1000, Allan McRae wrote:
> From: Dave Reisner <dreisner at archlinux.org>
> 
> Arch Linux typically runs into this with /sys when upgrading the
> filesystem package in build chroots, but LXC users might also run into
> this, since their /sys is shared from the host and must, for security
> reasons, be mounted RO.
> 
> I've neglected to add any tests for this because they would require root
> in order to run. Current tests all pass with this patch and I've
> confirmed the desired behavior in a VM. Incidentally, the first hunk of
> this patch (skipping can_remove_file checks for directories) resolves the
> case of API mountpoints being removed since they eventually fall into
> unlink_file and fail with "contains files". However, this patch should
> still be the Right Thing To Do™, as we can't possibly remove a directory
> that is also a mountpoint.
> 
> Signed-off-by: Dave Reisner <dreisner at archlinux.org>
> 
> [Allan] Do not skip checking if directories can be removed. Instead test
> if directories are mountpoints in can_remove_file.
> 
> Signed-off-by: Allan McRae <allan at archlinux.org>
> ---
> 
> This is an updated version of Dave's original patch.  Instead of skipping
> all directory checks which could result in us trying to remove empty directories
> on read-only file systems, test all directories to see if they are a mountpoint
> during can_remove_file.   This is hugely inefficient...  it results in two stat
> calls per directory, but it fixes the current issue.  A better fix would require
> completely rewriting the pre-removal checks to be done globally and not on a per
> package basis.

Looks good to me. Thanks for cleaning this up.

>  lib/libalpm/remove.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
> index 50fc93c..64888c5 100644
> --- a/lib/libalpm/remove.c
> +++ b/lib/libalpm/remove.c
> @@ -267,6 +267,37 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data)
>  	return 0;
>  }
>  
> +static int dir_is_mountpoint(alpm_handle_t *handle, const char *directory,
> +		const struct stat *stbuf)
> +{
> +	char parent_dir[PATH_MAX];
> +	struct stat parent_stbuf;
> +	dev_t dir_st_dev;
> +
> +	if(stbuf == NULL) {
> +		struct stat dir_stbuf;
> +		if(stat(directory, &dir_stbuf) < 0) {
> +			_alpm_log(handle, ALPM_LOG_DEBUG,
> +					"failed to stat directory %s: %s",
> +					directory, strerror(errno));
> +			return 0;
> +		}
> +		dir_st_dev = dir_stbuf.st_dev;
> +	} else {
> +		dir_st_dev = stbuf->st_dev;
> +	}
> +
> +	snprintf(parent_dir, PATH_MAX, "%s..", directory);
> +	if(stat(parent_dir, &parent_stbuf) < 0) {
> +		_alpm_log(handle, ALPM_LOG_DEBUG,
> +				"failed to stat parent of %s: %s: %s",
> +				directory, parent_dir, strerror(errno));
> +		return 0;
> +	}
> +
> +	return dir_st_dev != parent_stbuf.st_dev;
> +}
> +
>  /**
>   * @brief Check if alpm can delete a file.
>   *
> @@ -286,6 +317,12 @@ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file,
>  		return 1;
>  	}
>  
> +	if(file->name[strlen(file->name) - 1] == '/' &&
> +			dir_is_mountpoint(handle, file->name, NULL)) {
> +		/* we do not remove mountpoints */
> +		return 1;
> +	}
> +
>  	snprintf(filepath, PATH_MAX, "%s%s", handle->root, file->name);
>  	/* If we fail write permissions due to a read-only filesystem, abort.
>  	 * Assume all other possible failures are covered somewhere else */
> @@ -427,6 +464,9 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg,
>  					fileobj->name)) {
>  			_alpm_log(handle, ALPM_LOG_DEBUG,
>  					"keeping directory %s (in new package)\n", file);
> +		} else if(dir_is_mountpoint(handle, file, &buf)) {
> +			_alpm_log(handle, ALPM_LOG_DEBUG,
> +					"keeping directory %s (mountpoint)\n", file);
>  		} else {
>  			/* one last check- does any other package own this file? */
>  			alpm_list_t *local, *local_pkgs;
> -- 
> 1.8.1.3
> 
> 


More information about the pacman-dev mailing list