summaryrefslogtreecommitdiff
path: root/lib/libalpm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm')
-rw-r--r--lib/libalpm/add.c30
-rw-r--r--lib/libalpm/alpm.h1
-rw-r--r--lib/libalpm/conflict.c138
-rw-r--r--lib/libalpm/conflict.h2
-rw-r--r--lib/libalpm/handle.c10
-rw-r--r--lib/libalpm/handle.h1
-rw-r--r--lib/libalpm/list.c18
-rw-r--r--lib/libalpm/list.h1
-rw-r--r--lib/libalpm/md5.h2
-rw-r--r--lib/libalpm/remove.c52
-rw-r--r--lib/libalpm/trans.c2
-rw-r--r--lib/libalpm/trans.h1
-rw-r--r--lib/libalpm/util.c19
13 files changed, 184 insertions, 93 deletions
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index af7d6b0b..327b5407 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -191,6 +191,7 @@ error:
int add_prepare(pmtrans_t *trans, pmdb_t *db, PMList **data)
{
PMList *lp;
+ PMList *skiplist;
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
@@ -269,12 +270,17 @@ int add_prepare(pmtrans_t *trans, pmdb_t *db, PMList **data)
EVENT(trans, PM_TRANS_EVT_FILECONFLICTS_START, NULL, NULL);
_alpm_log(PM_LOG_FLOW1, "looking for file conflicts");
- lp = db_find_conflicts(db, trans->packages, handle->root);
+ lp = db_find_conflicts(db, trans->packages, handle->root, &skiplist);
if(lp != NULL) {
*data = lp;
RET_ERR(PM_ERR_FILE_CONFLICTS, -1);
}
+ /* copy the file skiplist into the transaction */
+ for(lp = skiplist; lp; lp = lp->next) {
+ trans->skiplist = pm_list_add(trans->skiplist, lp->data);
+ }
+
EVENT(trans, PM_TRANS_EVT_FILECONFLICTS_DONE, NULL, NULL);
}
@@ -354,6 +360,10 @@ int add_commit(pmtrans_t *trans, pmdb_t *db)
FREETRANS(tr);
RET_ERR(PM_ERR_TRANS_ABORT, -1);
}
+ /* copy the skiplist over */
+ for(lp = trans->skiplist; lp; lp = lp->next) {
+ pm_list_add(tr->skiplist, lp->data);
+ }
if(remove_commit(tr, db) == -1) {
FREETRANS(tr);
RET_ERR(PM_ERR_TRANS_ABORT, -1);
@@ -361,9 +371,8 @@ int add_commit(pmtrans_t *trans, pmdb_t *db)
FREETRANS(tr);
}
} else {
- /* no previous package version is installed, so this is actually just an
- * install
- */
+ /* no previous package version is installed, so this is actually
+ * just an install. */
pmo_upgrade = 0;
}
}
@@ -409,6 +418,17 @@ int add_commit(pmtrans_t *trans, pmdb_t *db)
snprintf(expath, PATH_MAX, "%s%s", handle->root, pathname);
}
+ /* if a file is in NoExtract then we never extract it.
+ *
+ * eg, /home/httpd/html/index.html may be removed so index.php
+ * could be used.
+ */
+ if(pm_list_is_strin(pathname, handle->noextract)) {
+ alpm_logaction("notice: %s is in NoExtract -- skipping extraction", pathname);
+ tar_skip_regfile(tar);
+ continue;
+ }
+
if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) {
/* file already exists */
if(pm_list_is_strin(pathname, handle->noupgrade)) {
@@ -589,7 +609,7 @@ int add_commit(pmtrans_t *trans, pmdb_t *db)
/* Add the package to the database */
t = time(NULL);
- /* Update the requiredby field by scaning the whole database
+ /* Update the requiredby field by scanning the whole database
* looking for packages depending on the package to add */
for(lp = db_get_pkgcache(db); lp; lp = lp->next) {
pmpkg_t *tmpp = lp->data;
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 989bca25..75493365 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -84,6 +84,7 @@ enum {
PM_OPT_LOCALDB,
PM_OPT_SYNCDB,
PM_OPT_NOUPGRADE,
+ PM_OPT_NOEXTRACT,
PM_OPT_IGNOREPKG,
PM_OPT_HOLDPKG
};
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index 3408c676..1c9cd309 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -31,7 +31,7 @@
#include "util.h"
#include "conflict.h"
-PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root)
+PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root, PMList **skip_list)
{
PMList *i, *j, *k;
char *filestr = NULL;
@@ -44,41 +44,7 @@ PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root)
return(NULL);
}
- /* CHECK 1: check every db package against every target package */
- /* XXX: I've disabled the database-against-targets check for now, as the
- * many many strcmp() calls slow it down heavily and most of the
- * checking is redundant to the targets-against-filesystem check.
- * This will be re-enabled if I can improve performance significantly.
- *
- pmpkg_t *info = NULL;
- char *dbstr = NULL;
- db_rewind(db);
- while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL) {
- for(i = info->files; i; i = i->next) {
- if(i->data == NULL) continue;
- dbstr = (char*)i->data;
- for(j = targets; j; j = j->next) {
- pmpkg_t *targ = (pmpkg_t*)j->data;
- if(strcmp(info->name, targ->name)) {
- for(k = targ->files; k; k = k->next) {
- filestr = (char*)k->data;
- if(!strcmp(dbstr, filestr)) {
- if(rindex(k->data, '/') == filestr+strlen(filestr)-1) {
- continue;
- }
- MALLOC(str, 512);
- snprintf(str, 512, "%s: exists in \"%s\" (target) and \"%s\" (installed)", dbstr,
- targ->name, info->name);
- conflicts = pm_list_add(conflicts, str);
- }
- }
- }
- }
- }
- FREEPKG(info);
- }*/
-
- /* CHECK 2: check every target against every target */
+ /* CHECK 1: check every target against every target */
for(i = targets; i; i = i->next) {
pmpkg_t *p1 = (pmpkg_t*)i->data;
for(j = i; j; j = j->next) {
@@ -104,52 +70,90 @@ PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root)
}
}
- /* CHECK 3: check every target against the filesystem */
+ /* CHECK 2: check every target against the filesystem */
for(i = targets; i; i = i->next) {
pmpkg_t *p = (pmpkg_t*)i->data;
pmpkg_t *dbpkg = NULL;
for(j = p->files; j; j = j->next) {
+ int isdir = 0;
filestr = (char*)j->data;
snprintf(path, PATH_MAX, "%s%s", root, filestr);
- if(!stat(path, &buf) && !S_ISDIR(buf.st_mode)) {
+ /* is this target a file or directory? */
+ if(path[strlen(path)-1] == '/') {
+ isdir = 1;
+ path[strlen(path)-1] = '\0';
+ }
+ if(!lstat(path, &buf)) {
int ok = 0;
- if(dbpkg == NULL) {
- dbpkg = db_scan(db, p->name, INFRQ_DESC | INFRQ_FILES);
+ if(!S_ISLNK(buf.st_mode) && ((isdir && !S_ISDIR(buf.st_mode)) || (!isdir && S_ISDIR(buf.st_mode)))) {
+ /* if the package target is a directory, and the filesystem target
+ * is not (or vice versa) then it's a conflict
+ */
+ ok = 0;
+ goto donecheck;
}
- if(dbpkg && pm_list_is_strin(j->data, dbpkg->files)) {
+ /* re-fetch with stat() instead of lstat() */
+ stat(path, &buf);
+ if(S_ISDIR(buf.st_mode)) {
+ /* if it's a directory, then we have no conflict */
ok = 1;
- }
- /* Make sure that the supposedly-conflicting file is not actually just
- * a symlink that points to a path that used to exist in the package.
- */
- /* Check if any part of the conflicting file's path is a symlink */
- if(dbpkg && !ok) {
- char str[PATH_MAX];
- for(k = dbpkg->files; k; k = k->next) {
- snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data);
- stat(str, &buf2);
- if(buf.st_ino == buf2.st_ino) {
- ok = 1;
- }
+ } else {
+ if(dbpkg == NULL) {
+ dbpkg = db_scan(db, p->name, INFRQ_DESC | INFRQ_FILES);
}
- }
- /* Check if the conflicting file has been moved to another package/target */
- if(!ok) {
- /* Look at all the targets */
- for(k = targets; k && !ok; k = k->next) {
- pmpkg_t *p1 = (pmpkg_t *)k->data;
- /* As long as they're not the current package */
- if(strcmp(p1->name, p->name)) {
- pmpkg_t *dbpkg2 = NULL;
- dbpkg2 = db_scan(db, p1->name, INFRQ_DESC | INFRQ_FILES);
- /* If it used to exist in there, but doesn't anymore */
- if(dbpkg2 && !pm_list_is_strin(filestr, p1->files) && pm_list_is_strin(filestr, dbpkg2->files)) {
+ if(dbpkg && pm_list_is_strin(j->data, dbpkg->files)) {
+ ok = 1;
+ }
+ /* Make sure that the supposedly-conflicting file is not actually just
+ * a symlink that points to a path that used to exist in the package.
+ */
+ /* Check if any part of the conflicting file's path is a symlink */
+ if(dbpkg && !ok) {
+ char str[PATH_MAX];
+ for(k = dbpkg->files; k; k = k->next) {
+ snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data);
+ stat(str, &buf2);
+ if(buf.st_ino == buf2.st_ino) {
ok = 1;
}
- FREEPKG(dbpkg2);
+ }
+ }
+ /* Check if the conflicting file has been moved to another package/target */
+ if(!ok) {
+ /* Look at all the targets */
+ for(k = targets; k && !ok; k = k->next) {
+ pmpkg_t *p1 = (pmpkg_t *)k->data;
+ /* As long as they're not the current package */
+ if(strcmp(p1->name, p->name)) {
+ pmpkg_t *dbpkg2 = NULL;
+ dbpkg2 = db_scan(db, p1->name, INFRQ_DESC | INFRQ_FILES);
+ /* If it used to exist in there, but doesn't anymore */
+ if(dbpkg2 && !pm_list_is_strin(filestr, p1->files) && pm_list_is_strin(filestr, dbpkg2->files)) {
+ ok = 1;
+ /* Add to the "skip list" of files that we shouldn't remove during an upgrade.
+ *
+ * This is a workaround for the following scenario:
+ *
+ * - the old package A provides file X
+ * - the new package A does not
+ * - the new package B provides file X
+ * - package A depends on B, so B is upgraded first
+ *
+ * Package B is upgraded, so file X is installed. Then package A
+ * is upgraded, and it *removes* file X, since it no longer exists
+ * in package A.
+ *
+ * Our workaround is to scan through all "old" packages and all "new"
+ * ones, looking for files that jump to different packages.
+ */
+ *skip_list = pm_list_add(*skip_list, filestr);
+ }
+ FREEPKG(dbpkg2);
+ }
}
}
}
+donecheck:
if(!ok) {
MALLOC(str, 512);
snprintf(str, 512, "%s: %s: exists in filesystem", p->name, path);
diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h
index 133d714d..83bf55ca 100644
--- a/lib/libalpm/conflict.h
+++ b/lib/libalpm/conflict.h
@@ -23,7 +23,7 @@
#include "db.h"
-PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root);
+PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root, PMList **skip_list);
#endif /* _ALPM_CONFLICT_H */
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 6e855793..8567b87d 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -139,6 +139,15 @@ int handle_set_option(pmhandle_t *handle, unsigned char val, unsigned long data)
_alpm_log(PM_LOG_FLOW2, "PM_OPT_NOUPGRADE flushed");
}
break;
+ case PM_OPT_NOEXTRACT:
+ if((char *)data && strlen((char *)data) != 0) {
+ handle->noextract = pm_list_add(handle->noextract, strdup((char *)data));
+ _alpm_log(PM_LOG_FLOW2, "'%s' added to PM_OPT_NOEXTRACT", (char *)data);
+ } else {
+ FREELIST(handle->noextract);
+ _alpm_log(PM_LOG_FLOW2, "PM_OPT_NOEXTRACT flushed");
+ }
+ break;
case PM_OPT_IGNOREPKG:
if((char *)data && strlen((char *)data) != 0) {
handle->ignorepkg = pm_list_add(handle->ignorepkg, strdup((char *)data));
@@ -189,6 +198,7 @@ int handle_get_option(pmhandle_t *handle, unsigned char val, long *data)
case PM_OPT_SYNCDB: *data = (long)handle->dbs_sync; break;
case PM_OPT_LOGFILE: *data = (long)handle->logfile; break;
case PM_OPT_NOUPGRADE: *data = (long)handle->noupgrade; break;
+ case PM_OPT_NOEXTRACT: *data = (long)handle->noextract; break;
case PM_OPT_IGNOREPKG: *data = (long)handle->ignorepkg; break;
case PM_OPT_USESYSLOG: *data = handle->usesyslog; break;
case PM_OPT_LOGCB: *data = (long)pm_logcb; break;
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 5f3e8e8e..a37ee0fd 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -44,6 +44,7 @@ typedef struct __pmhandle_t {
char *dbpath;
char *logfile;
PMList *noupgrade; /* List of strings */
+ PMList *noextract; /* List of strings */
PMList *ignorepkg; /* List of strings */
unsigned char usesyslog;
} pmhandle_t;
diff --git a/lib/libalpm/list.c b/lib/libalpm/list.c
index 9d3f4005..8bf0d702 100644
--- a/lib/libalpm/list.c
+++ b/lib/libalpm/list.c
@@ -256,6 +256,24 @@ PMList* pm_list_last(PMList *list)
return(list->last);
}
+/* Filter out any duplicate strings in a list.
+ *
+ * Not the most efficient way, but simple to implement -- we assemble
+ * a new list, using is_in() to check for dupes at each iteration.
+ *
+ */
+PMList *_alpm_list_remove_dupes(PMList *list)
+{
+ PMList *i, *newlist = NULL;
+
+ for(i = list; i; i = i->next) {
+ if(!pm_list_is_strin(i->data, newlist)) {
+ newlist = pm_list_add(newlist, strdup(i->data));
+ }
+ }
+ return newlist;
+}
+
/* Reverse the order of a list
*
* The caller is responsible for freeing the old list
diff --git a/lib/libalpm/list.h b/lib/libalpm/list.h
index 35bacd00..e625dbff 100644
--- a/lib/libalpm/list.h
+++ b/lib/libalpm/list.h
@@ -55,6 +55,7 @@ int pm_list_count(PMList *list);
int pm_list_is_in(void *needle, PMList *haystack);
PMList *pm_list_is_strin(char *needle, PMList *haystack);
PMList *pm_list_last(PMList *list);
+PMList *_alpm_list_remove_dupes(PMList *list);
PMList *_alpm_list_reverse(PMList *list);
PMList *_alpm_list_strdup(PMList *list);
diff --git a/lib/libalpm/md5.h b/lib/libalpm/md5.h
index e6e4ea64..20aae92b 100644
--- a/lib/libalpm/md5.h
+++ b/lib/libalpm/md5.h
@@ -31,7 +31,7 @@ typedef unsigned char *POINTER;
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
-typedef unsigned long int UINT4;
+typedef unsigned int UINT4;
/* MD5 context. */
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index fd00eae1..0e335906 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -191,28 +191,42 @@ int remove_commit(pmtrans_t *trans, pmdb_t *db)
_alpm_log(PM_LOG_FLOW2, "removing directory %s", file);
}
} else {
- /* if the file is flagged, back it up to .pacsave */
- if(nb) {
- if(trans->type == PM_TRANS_TYPE_UPGRADE) {
- /* we're upgrading so just leave the file as is. pacman_add() will handle it */
- } else {
- if(!(trans->flags & 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", file, newpath);
- alpm_logaction("%s saved as %s", line, newpath);
+ /* check the "skip list" before removing the file.
+ * see the big comment block in db_find_conflicts() for an
+ * explanation. */
+ int skipit = 0;
+ PMList *j;
+ for(j = trans->skiplist; j; j = j->next) {
+ if(!strcmp(file, (char*)j->data)) {
+ skipit = 1;
+ }
+ }
+ if(skipit) {
+ _alpm_log(PM_LOG_FLOW2, "skipping removal of %s as it has moved to another package\n", file);
+ } else {
+ /* if the file is flagged, back it up to .pacsave */
+ if(nb) {
+ if(trans->type == PM_TRANS_TYPE_UPGRADE) {
+ /* we're upgrading so just leave the file as is. pacman_add() will handle it */
} else {
- _alpm_log(PM_LOG_FLOW2, "unlinking %s", file);
- if(unlink(line)) {
- _alpm_log(PM_LOG_ERROR, "cannot remove file %s", file);
+ if(!(trans->flags & 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", file, newpath);
+ alpm_logaction("%s saved as %s", line, newpath);
+ } else {
+ _alpm_log(PM_LOG_FLOW2, "unlinking %s", file);
+ if(unlink(line)) {
+ _alpm_log(PM_LOG_ERROR, "cannot remove file %s", file);
+ }
}
}
- }
- } else {
- _alpm_log(PM_LOG_FLOW2, "unlinking %s", file);
- if(unlink(line)) {
- _alpm_log(PM_LOG_ERROR, "cannot remove file %s", file);
+ } else {
+ _alpm_log(PM_LOG_FLOW2, "unlinking %s", file);
+ if(unlink(line)) {
+ _alpm_log(PM_LOG_ERROR, "cannot remove file %s", file);
+ }
}
}
}
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index c7c4448f..43f134e0 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -46,6 +46,7 @@ pmtrans_t *trans_new()
trans->targets = NULL;
trans->packages = NULL;
+ trans->skiplist = NULL;
trans->type = 0;
trans->flags = 0;
trans->cb_event = NULL;
@@ -68,6 +69,7 @@ void trans_free(pmtrans_t *trans)
i->data = NULL;
}
FREELIST(trans->packages);
+ FREELIST(trans->skiplist);
} else {
FREELISTPKGS(trans->packages);
}
diff --git a/lib/libalpm/trans.h b/lib/libalpm/trans.h
index 96b9083b..8518e5aa 100644
--- a/lib/libalpm/trans.h
+++ b/lib/libalpm/trans.h
@@ -36,6 +36,7 @@ typedef struct __pmtrans_t {
unsigned char state;
PMList *targets; /* PMList of (char *) */
PMList *packages; /* PMList of (pmpkg_t *) or (pmsyncpkg_t *) */
+ PMList *skiplist; /* PMList of (char *) */
alpm_trans_cb_event cb_event;
} pmtrans_t;
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index 4836812e..6b2b60a6 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -40,6 +40,8 @@
#include "util.h"
#include "alpm.h"
+static char *chrootbin = NULL;
+
/* borrowed and modified from Per Liden's pkgutils (http://crux.nu) */
long _alpm_gzopen_frontend(char *pathname, int oflags, int mode)
{
@@ -366,6 +368,23 @@ int _alpm_runscriptlet(char *root, char *installfn, char *script, char *ver, cha
return(0);
}
+ if(chrootbin == NULL) {
+ char *dirs[] = {"/usr/sbin","/usr/bin","/sbin","/bin"};
+ int i;
+ for(i = 0; i < 4 && !chrootbin; i++) {
+ char cpath[PATH_MAX];
+ snprintf(cpath, PATH_MAX, "%s/chroot", dirs[i]);
+ if(!stat(cpath, &buf)) {
+ chrootbin = strdup(cpath);
+ _alpm_log(PM_LOG_DEBUG, "found chroot binary: %s", chrootbin);
+ }
+ }
+ if(chrootbin == NULL) {
+ _alpm_log(PM_LOG_ERROR, "cannot find chroot binary - unable to run scriptlet");
+ return(1);
+ }
+ }
+
if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) {
snprintf(tmpdir, PATH_MAX, "%stmp/", root);
if(stat(tmpdir, &buf)) {