summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Griffin <aaron@archlinux.org>2007-02-08 09:09:34 +0100
committerAaron Griffin <aaron@archlinux.org>2007-02-08 09:09:34 +0100
commita94e22d9245f78242527b983a285dadf118f1afc (patch)
tree4c8c65f764da17cf6a5efa9355f400317fcec44d
parenta97bb3e279f962724e53ea0398a2b03bb23bac75 (diff)
downloadpacman-a94e22d9245f78242527b983a285dadf118f1afc.tar.gz
pacman-a94e22d9245f78242527b983a285dadf118f1afc.tar.xz
Attempt to NOT remove packages on filesystem errors (like a read-only
filesystem). See FS#5887
-rw-r--r--lib/libalpm/alpm.h1
-rw-r--r--lib/libalpm/error.c2
-rw-r--r--lib/libalpm/remove.c95
3 files changed, 71 insertions, 27 deletions
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 3522604f..a5b5e1a4 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -450,6 +450,7 @@ enum _pmerrno_t {
PM_ERR_PKG_LOAD,
PM_ERR_PKG_INSTALLED,
PM_ERR_PKG_CANT_FRESH,
+ PM_ERR_PKG_CANT_REMOVE,
PM_ERR_PKG_INVALID_NAME,
PM_ERR_PKG_CORRUPTED,
PM_ERR_PKG_REPO_NOT_FOUND,
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index 334012d1..a6d20acf 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -97,6 +97,8 @@ char SYMEXPORT *alpm_strerror(int err)
return _("package already installed");
case PM_ERR_PKG_CANT_FRESH:
return _("package not installed or lesser version");
+ case PM_ERR_PKG_CANT_REMOVE:
+ return _("cannot remove all files for package");
case PM_ERR_PKG_INVALID_NAME:
return _("package name is not valid");
case PM_ERR_PKG_CORRUPTED:
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index afe5532b..9933d4cc 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -162,8 +162,40 @@ static int str_cmp(const void *s1, const void *s2)
return(strcmp(s1, s2));
}
+
+static int can_remove_file(const char *path)
+{
+ alpm_list_t *i;
+ char file[PATH_MAX+1];
+
+ snprintf(file, PATH_MAX, "%s%s", handle->root, path);
+
+ for(i = handle->trans->skiplist; i; i = i->next) {
+ if(strcmp(file, i->data) == 0) {
+ /* skipping this file, return success because "removing" this
+ * file does nothing */
+ return(1);
+ }
+ }
+ /* If we fail write permissions due to a read-only filesystem, abort.
+ * Assume all other possible failures are covered somewhere else */
+ if(access(file, W_OK) == -1) {
+ if(access(file, F_OK) == 0) {
+ /* only return failure if the file ACTUALLY exists and we don't have
+ * permissions */
+ _alpm_log(PM_LOG_WARNING, _("cannot remove file '%s': %s"), file, strerror(errno));
+ return(0);
+ }
+ }
+
+ return(1);
+}
+
/* Helper function for iterating through a package's file and deleting them
* Used by _alpm_remove_commit
+ *
+ * TODO the parameters are a bit out of control here. This function doesn't
+ * need to report PROGRESS, do it in the parent function.
*/
static void unlink_file(pmpkg_t *info, alpm_list_t *lp, alpm_list_t *targ,
pmtrans_t *trans, int filenum, int *position)
@@ -171,34 +203,35 @@ static void unlink_file(pmpkg_t *info, alpm_list_t *lp, alpm_list_t *targ,
struct stat buf;
int nb = 0;
double percent = 0.0;
- char *file = lp->data;
- char line[PATH_MAX+1];
+ char file[PATH_MAX+1];
char *checksum = _alpm_needbackup(lp->data, info->backup);
ALPM_LOG_FUNC;
- if ( *position != 0 ) {
+ if(*position != 0) {
percent = (double)*position / filenum;
- } if ( checksum ) {
+ }
+ if(checksum) {
nb = 1;
FREE(checksum);
- } if ( !nb && trans->type == PM_TRANS_TYPE_UPGRADE ) {
+ }
+ if(!nb && trans->type == PM_TRANS_TYPE_UPGRADE) {
/* check noupgrade */
- if ( alpm_list_find_str(handle->noupgrade, file) ) {
+ if(alpm_list_find_str(handle->noupgrade, lp->data)) {
nb = 1;
}
}
- snprintf(line, PATH_MAX, "%s%s", handle->root, file);
- if ( lstat(line, &buf) ) {
- _alpm_log(PM_LOG_DEBUG, _("file %s does not exist"), line);
+ snprintf(file, PATH_MAX, "%s%s", handle->root, (char *)lp->data);
+ if(lstat(file, &buf)) {
+ _alpm_log(PM_LOG_DEBUG, _("file %s does not exist"), file);
return;
}
- if ( S_ISDIR(buf.st_mode) ) {
- if ( rmdir(line) ) {
+ if(S_ISDIR(buf.st_mode)) {
+ if(rmdir(file)) {
/* this is okay, other pakcages are probably using it (like /usr) */
- _alpm_log(PM_LOG_DEBUG, _("keeping directory %s"), line);
+ _alpm_log(PM_LOG_DEBUG, _("keeping directory %s"), file);
} else {
- _alpm_log(PM_LOG_DEBUG, _("removing directory %s"), line);
+ _alpm_log(PM_LOG_DEBUG, _("removing directory %s"), file);
}
} else {
/* check the "skip list" before removing the file.
@@ -206,35 +239,36 @@ static void unlink_file(pmpkg_t *info, alpm_list_t *lp, alpm_list_t *targ,
* explanation. */
int skipit = 0;
alpm_list_t *j;
- for ( j = trans->skiplist; j; j = j->next ) {
- if ( !strcmp(file, (char*)j->data) ) {
+ for(j = trans->skiplist; j; j = j->next) {
+ if(!strcmp(lp->data, (char*)j->data)) {
skipit = 1;
}
}
- if ( skipit ) {
- _alpm_log(PM_LOG_DEBUG, _("skipping removal of %s as it has moved to another package"),
- line);
+ if(skipit) {
+ _alpm_log(PM_LOG_WARNING, _("skipping removal of %s as it has moved to another package"),
+ file);
} else {
/* if the file is flagged, back it up to .pacsave */
- if ( nb ) {
- if ( !(trans->type == PM_TRANS_TYPE_UPGRADE) ) {
+ if(nb) {
+ if(!(trans->type == PM_TRANS_TYPE_UPGRADE)) {
/* if it was an upgrade, the file would be left alone because
* pacman_add() would handle it */
- if ( !(trans->type & PM_TRANS_FLAG_NOSAVE) ) {
+ if(!(trans->type & PM_TRANS_FLAG_NOSAVE)) {
char newpath[PATH_MAX];
- snprintf(newpath, PATH_MAX, "%s.pacsave", line);
- rename(line, newpath);
- _alpm_log(PM_LOG_WARNING, _("%s saved as %s"), line, newpath);
+ snprintf(newpath, PATH_MAX, "%s.pacsave", file);
+ rename(file, newpath);
+ _alpm_log(PM_LOG_WARNING, _("%s saved as %s"), file, newpath);
}
}
} else {
- _alpm_log(PM_LOG_DEBUG, _("unlinking %s"), line);
+ _alpm_log(PM_LOG_DEBUG, _("unlinking %s"), file);
int list_count = alpm_list_count(trans->packages); /* this way we don't have to call alpm_list_count twice during PROGRESS */
+
PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name, (double)(percent * 100), list_count, (list_count - alpm_list_count(targ) + 1));
++(*position);
- if (unlink(line) == -1) {
- _alpm_log(PM_LOG_ERROR, _("cannot remove file %s: %s"), file, strerror(errno));
+ if(unlink(file) == -1) {
+ _alpm_log(PM_LOG_ERROR, _("cannot remove file %s: %s"), lp->data, strerror(errno));
}
}
}
@@ -272,6 +306,13 @@ int _alpm_remove_commit(pmtrans_t *trans, pmdb_t *db)
}
if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {
+ for(lp = info->files; lp; lp = lp->next) {
+ if(!can_remove_file(lp->data)) {
+ _alpm_log(PM_LOG_DEBUG, _("not removing package '%s', can't remove all files"), info->name);
+ RET_ERR(PM_ERR_PKG_CANT_REMOVE, -1);
+ }
+ }
+
int filenum = alpm_list_count(info->files);
_alpm_log(PM_LOG_DEBUG, _("removing files"));