From e07547ee4ed4fd812a7f50b998589fa27c12de4c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 19 Aug 2011 13:10:17 -0500 Subject: Rework finding a writable cache directory This is a refactor and refresh of the code used to find where we should download packages. * Incorporate suggestions from FS#25435 to use TMPDIR from the environment if set, otherwise fall back to /tmp as before. * Make the writability tests a bit more in depth. We now do a three part check consisting of: - S_ISDIR(): is this even a directory - access(W_OK): is this directory writable by the current user. Unfortunately for root, this almost always returns that it is, but in the case of a RO mount or NFS share inaccessible to root, this check will exclude the directory. - mode & (any write bit): is there a writable bit set on this directory. This makes it possible to enforce a read-only cache directory by setting permissions to 0555, for example. Signed-off-by: Dan McGee --- lib/libalpm/util.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 27709c64..7e3bc372 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -638,7 +638,7 @@ char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename) struct stat buf; /* Loop through the cache dirs until we find a matching file */ - for(i = alpm_option_get_cachedirs(handle); i; i = i->next) { + for(i = handle->cachedirs; i; i = i->next) { snprintf(path, PATH_MAX, "%s%s", (char *)alpm_list_getdata(i), filename); if(stat(path, &buf) == 0 && S_ISREG(buf.st_mode)) { @@ -659,11 +659,11 @@ char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename) const char *_alpm_filecache_setup(alpm_handle_t *handle) { struct stat buf; - alpm_list_t *i, *tmp; - char *cachedir; + alpm_list_t *i; + char *cachedir, *tmpdir; - /* Loop through the cache dirs until we find a writeable dir */ - for(i = alpm_option_get_cachedirs(handle); i; i = i->next) { + /* Loop through the cache dirs until we find a usable directory */ + for(i = handle->cachedirs; i; i = i->next) { cachedir = alpm_list_getdata(i); if(stat(cachedir, &buf) != 0) { /* cache directory does not exist.... try creating it */ @@ -673,21 +673,35 @@ const char *_alpm_filecache_setup(alpm_handle_t *handle) _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", cachedir); return cachedir; } - } else if(S_ISDIR(buf.st_mode) && (buf.st_mode & S_IWUSR)) { + } else if(!S_ISDIR(buf.st_mode)) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "skipping cachedir, not a directory: %s\n", cachedir); + } else if(access(cachedir, W_OK) != 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "skipping cachedir, not writable: %s\n", cachedir); + } else if(!(buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "skipping cachedir, no write bits set: %s\n", cachedir); + } else { _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", cachedir); return cachedir; - } else { - _alpm_log(handle, ALPM_LOG_DEBUG, "skipping cachedir: %s\n", cachedir); } } - /* we didn't find a valid cache directory. use /tmp. */ - tmp = alpm_list_add(NULL, "/tmp/"); - alpm_option_set_cachedirs(handle, tmp); - alpm_list_free(tmp); - _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", "/tmp/"); - _alpm_log(handle, ALPM_LOG_WARNING, _("couldn't create package cache, using /tmp instead\n")); - return "/tmp/"; + /* we didn't find a valid cache directory. use TMPDIR or /tmp. */ + if((tmpdir = getenv("TMPDIR")) && stat(tmpdir, &buf) && S_ISDIR(buf.st_mode)) { + /* TMPDIR was good, we can use it */ + } else { + tmpdir = "/tmp"; + } + i = alpm_list_add(NULL, tmpdir); + alpm_option_set_cachedirs(handle, i); + alpm_list_free(i); + cachedir = handle->cachedirs->data; + _alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", cachedir); + _alpm_log(handle, ALPM_LOG_WARNING, + _("couldn't find or create package cache, using %s instead\n"), cachedir); + return cachedir; } /** lstat wrapper that treats /path/dirsymlink/ the same as /path/dirsymlink. -- cgit v1.2.3-70-g09d2