From d05f0047a02a2b3b3f1a07c0feb980837a3496a3 Mon Sep 17 00:00:00 2001 From: Judd Vinet Date: Fri, 10 Jun 2005 21:31:25 +0000 Subject: Imported from pacman-2.9.6.tar.gz --- ChangeLog | 11 ++ Makefile.in | 3 +- doc/pacman.8.in | 2 +- etc/makepkg.conf | 6 +- scripts/gensync | 4 +- scripts/makepkg | 9 +- scripts/makeworld | 8 +- scripts/pacman-optimize | 114 ++++++++++++++++++++ scripts/updatesync | 4 +- src/db.c | 125 ++++++++++++++-------- src/db.h | 7 +- src/list.c | 17 ++- src/pacconf.h | 2 +- src/pacman.c | 158 ++++++++++++++++++---------- src/pacman.h | 2 +- src/pacsync.c | 7 ++ src/strhash.c | 273 +++++++++++++++++++++++++----------------------- src/strhash.h | 1 + 18 files changed, 494 insertions(+), 259 deletions(-) create mode 100755 scripts/pacman-optimize diff --git a/ChangeLog b/ChangeLog index c6b9e42d..6f92d4ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ VERSION DESCRIPTION ----------------------------------------------------------------------------- +2.9.6 - added a pacman-optimize script to try and defragment the DB + - modified NoUpgrade behaviour to avoid extracting files + that are missing from the filesystem -- this helps in + situations where the admin does not want the file there, eg, + remove index.html so index.php takes precedence + - fixed a bug where files would sometimes go missing if they + moved from one package to another + - add db_remove() which is responsible for clearing out stale + hash table entries when packages are removed + - added cache support to makepkg + - patch from Aurelien Foret fixes a few memory leaks 2.9.5 - bugfix: missing files after re-ordering packages wrt deps with --upgrade - added "Repository" line to -Si output diff --git a/Makefile.in b/Makefile.in index cd6b18bb..34c463f7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,7 +34,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ -PACVER = 2.9.5 +PACVER = 2.9.6 TOPDIR = @srcdir@ SRCDIR = $(TOPDIR)/src/ @@ -106,6 +106,7 @@ install: pacman vercmp convertdb man $(INSTALL) -D -m0755 $(SCRDIR)makeworld $(DESTDIR)$(BINDIR)/makeworld $(INSTALL) -D -m0755 $(SCRDIR)gensync $(DESTDIR)$(BINDIR)/gensync $(INSTALL) -D -m0755 $(SCRDIR)updatesync $(DESTDIR)$(BINDIR)/updatesync + $(INSTALL) -D -m0755 $(SCRDIR)pacman-optimize $(DESTDIR)$(BINDIR)/pacman-optimize $(INSTALL) -D -m0644 $(MANSRC)pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8 $(INSTALL) -D -m0644 $(MANSRC)makepkg.8 $(DESTDIR)$(MANDIR)/man8/makepkg.8 $(INSTALL) -D -m0644 etc/pacman.conf $(DESTDIR)/etc/pacman.conf diff --git a/doc/pacman.8.in b/doc/pacman.8.in index 27787c15..09c47d50 100644 --- a/doc/pacman.8.in +++ b/doc/pacman.8.in @@ -81,7 +81,7 @@ Output more status and error messages. Specify an alternate configuration file. .TP .B "\-\-noconfirm" -Bypass any and all "Are you sure?" messages. It's not a good to do this +Bypass any and all "Are you sure?" messages. It's not a good idea to do this unless you want to run pacman from a script. .SH SYNC OPTIONS .TP diff --git a/etc/makepkg.conf b/etc/makepkg.conf index 0d0809a0..d43b0e67 100644 --- a/etc/makepkg.conf +++ b/etc/makepkg.conf @@ -12,8 +12,8 @@ export CHOST="i686-pc-linux-gnu" # Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon exclusive (binaries # will use the P6 instruction set and only run on P6+ systems) -export CFLAGS="-march=i686 -O2 -pipe" -export CXXFLAGS="-march=i686 -O2 -pipe" +export CFLAGS="-march=i686 -O2 -pipe -Wl,-O1" +export CXXFLAGS="-march=i686 -O2 -pipe -Wl,-O1" # Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon optimized (but binaries # will run on any x86 system) #export CFLAGS="-mcpu=i686 -O2 -pipe" @@ -26,7 +26,7 @@ export CXXFLAGS="-march=i686 -O2 -pipe" export USE_FAKEROOT="y" # Enable colorized output messages -export USE_COLOR="n" +export USE_COLOR="y" # Specify a fixed directory where all packages will be placed #export PKGDEST=/home/packages diff --git a/scripts/gensync b/scripts/gensync index 49a2939a..0ebc1386 100755 --- a/scripts/gensync +++ b/scripts/gensync @@ -2,7 +2,7 @@ # # gensync # -# Copyright (c) 2002-2004 by Judd Vinet +# Copyright (c) 2002-2005 by Judd Vinet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ # USA. # -myver='2.9.2' +myver='2.9.6' usage() { echo "gensync $myver" diff --git a/scripts/makepkg b/scripts/makepkg index a4c4d23a..31e78f97 100755 --- a/scripts/makepkg +++ b/scripts/makepkg @@ -2,7 +2,7 @@ # # makepkg # -# Copyright (c) 2002-2004 by Judd Vinet +# Copyright (c) 2002-2005 by Judd Vinet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ # USA. # -myver='2.9.2' +myver='2.9.6' startdir=`pwd` PKGDEST=$startdir USE_COLOR="n" @@ -357,7 +357,7 @@ if [ "`id -u`" != "0" ]; then fi fi -msg "Making package: $pkgname (`date`)" +msg "Making package: $pkgname $pkgver-$pkgrel (`date`)" unset deplist makedeplist if [ `type -p pacman` -a "$NODEPS" = "0" ]; then @@ -552,6 +552,9 @@ if [ "$NOBUILD" = "1" ]; then exit 0 fi +# use ccache if it's available +[ -d /usr/lib/ccache/bin ] && export PATH=/usr/lib/ccache/bin:$PATH + # build msg "Starting build()..." build 2>&1 diff --git a/scripts/makeworld b/scripts/makeworld index c42013c7..30418afd 100755 --- a/scripts/makeworld +++ b/scripts/makeworld @@ -2,7 +2,7 @@ # # makeworld # -# Copyright (c) 2002-2004 by Judd Vinet +# Copyright (c) 2002-2005 by Judd Vinet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,8 +20,8 @@ # USA. # +version="2.9.6" toplevel=`pwd` -version="2.9.2" usage() { echo "makeworld version $version" @@ -106,12 +106,12 @@ fi # convert a (possibly) relative path to absolute cd $dest dest=`pwd` -cd - +cd - &>/dev/null sd=`date +"[%b %d %H:%M]"` for category in $*; do - for port in `find $toplevel/$category -type d -maxdepth 1 -mindepth 1 | sort`; do + for port in `find $toplevel/$category -maxdepth 1 -mindepth 1 -type d | sort`; do cd $port if [ -f PKGBUILD ]; then . PKGBUILD diff --git a/scripts/pacman-optimize b/scripts/pacman-optimize new file mode 100755 index 00000000..b9573cbb --- /dev/null +++ b/scripts/pacman-optimize @@ -0,0 +1,114 @@ +#!/bin/bash +# +# pacman-optimize +# +# Copyright (c) 2002-2005 by Judd Vinet +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. +# + +myver='2.9.6' + +usage() { + echo "pacman-optimize $myver" + echo "usage: $0 [pacman_db_root]" + echo + echo "pacman-optimize is a little hack that should improve the performance" + echo "of pacman when reading/writing to its filesystem-based database." + echo + echo "Because pacman uses many small files to keep track of packages," + echo "there is a tendency for these files to become fragmented over time." + echo "This script attempts to relocate these small files into one" + echo "contiguous location on your hard drive. The result is that the hard" + echo "drive should be able to read them faster, since the hard drive head" + echo "does not have to move around the disk as much." + echo +} + +die() { + echo "pacman-optimize: $*" >&2 + exit 1 +} + +die_r() { + rm -f /tmp/pacman.lck + die $* +} + + +dbroot="/var/lib/pacman" + +if [ "$1" != "" ]; then + if [ "$1" = "-h" -o "$1" = "--help" ]; then + usage + exit 0 + fi + dbroot=$1 +fi + +if [ "`id -u`" != 0 ]; then + die "You must be root to optimize the database" +fi + +# make sure pacman isn't running +if [ -f /tmp/pacman.lck ]; then + die "Pacman lockfile was found. Cannot run while pacman is running." +fi + +if [ ! -d $dbroot ]; then + die "$dbroot does not exist or is not a directory" +fi + +# don't let pacman run while we do this +touch /tmp/pacman.lck + +# step 1: sum the old db +echo "==> md5sum'ing the old database..." +tar c $dbroot 2>/dev/null | md5sum >/tmp/pacsums.old + +# step 1: copy the entire db directory to a new one +echo "==> copying $dbroot..." +cp -a $dbroot $dbroot.new || die_r "error copying $dbroot" + +# step 2: switch the directory names and sum the new one +echo "==> md5sum'ing the new database..." +mv $dbroot $dbroot.bak || die_r "error renaming $dbroot" +mv $dbroot.new $dbroot || die_r "error renaming $dbroot.new" +tar c $dbroot 2>/dev/null | md5sum >/tmp/pacsums.new + +# step 3: compare sums +echo "==> checking integrity..." +diff /tmp/pacsums.old /tmp/pacsums.new >/dev/null 2>&1 +if [ $? -ne 0 ]; then + # failed, move the old one back into place + rm -rf $dbroot + mv $dbroot.bak $dbroot + die_r "integrity check FAILED, reverting to old databse" +fi + +# step 4: remove the backup +echo "==> removing old database..." +rm -rf $dbroot.bak || die_r "error removing backup $dbroot.bak" + +# remove the lock and sum files +rm -f /tmp/pacman.lck /tmp/pacsums.old /tmp/pacsums.new + +echo +echo "Finished. Your pacman database has been optimized." +echo + +exit 0 + diff --git a/scripts/updatesync b/scripts/updatesync index 943af8a5..e36d25e7 100755 --- a/scripts/updatesync +++ b/scripts/updatesync @@ -3,7 +3,7 @@ # updatesync # # Copyright (c) 2004 by Jason Chu -# Derived from gensync (c) 2002-2004 Judd Vinet +# Derived from gensync (c) 2002-2005 Judd Vinet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ # USA. # -myver='2.9.2' +myver='2.9.6' usage() { echo "updatesync $myver" diff --git a/src/db.c b/src/db.c index 8dd12c98..005498c4 100644 --- a/src/db.c +++ b/src/db.c @@ -137,21 +137,32 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq) char *ptr = NULL; int found = 0; - /* hash table for caching directory names */ - static strhash_t* htable = NULL; - - if (!htable) - htable = new_strhash(951); + /* initialize the hash table */ + if(!db_htable) { + db_htable = new_strhash(951); + } snprintf(path, PATH_MAX, "%s/", db->path); path_len = strlen(path); + /* TODO: + * + * Currently we're using a hash table to cache the directory + * name of each package we db_scan() for. This saves us from + * having to scan the db directory for the full + * pkgname-pkgver-pkgrel dir name, but we still have to issue + * a db_read() call to get the actual package data. + * + * A more efficient method may be to cache the package data + * itself. + */ + if(target != NULL) { /* search for a specific package (by name only) */ /* See if we have the path cached. */ strcat(path, target); - if (strhash_isin(htable, path)) { + if(strhash_isin(db_htable, path)) { struct dirent* pkgdir; pkginfo_t* pkg; @@ -159,7 +170,7 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq) * Actually it only uses the d_name field. */ MALLOC(pkgdir, sizeof(struct dirent)); - strcpy(pkgdir->d_name, strhash_get(htable, path)); + strcpy(pkgdir->d_name, strhash_get(db_htable, path)); pkg = db_read(db, pkgdir, inforeq); FREE(pkgdir); @@ -242,8 +253,8 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq) * data: xrally-1.1.1-1 */ - if (!strhash_isin(htable, path)) { - strhash_add(htable, strdup(path), strdup(ent->d_name)); + if(!strhash_isin(db_htable, path)) { + strhash_add(db_htable, strdup(path), strdup(ent->d_name)); } } } @@ -595,6 +606,40 @@ int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq) return(0); } +/* + * Remove a package record from the database + */ +void db_remove(pacdb_t *db, pkginfo_t *target) +{ + char topdir[PATH_MAX]; + char path[PATH_MAX]; + + snprintf(topdir, PATH_MAX, "%s/%s-%s", db->path, + target->name, target->version); + + /* DESC */ + snprintf(path, PATH_MAX, "%s/desc", topdir); + unlink(path); + /* FILES */ + snprintf(path, PATH_MAX, "%s/files", topdir); + unlink(path); + /* DEPENDS */ + snprintf(path, PATH_MAX, "%s/depends", topdir); + unlink(path); + /* INSTALL */ + snprintf(path, PATH_MAX, "%s/install", topdir); + unlink(path); + /* directory */ + rmdir(topdir); + + /* remove the entry from the hash table */ + if(db_htable) { + /*clear_strhash(db_htable);*/ + snprintf(topdir, PATH_MAX, "%s/%s", db->path, target->name); + strhash_remove(db_htable, topdir); + } +} + void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles) { PMList *i, *j; @@ -655,7 +700,7 @@ void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles } -PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) +PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root, PMList **skip_list) { PMList *i, *j, *k; char *filestr = NULL; @@ -663,6 +708,7 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) char *str = NULL; struct stat buf, buf2; PMList *conflicts = NULL; + strhash_t** htables; int target_num = 0; int d = 0; @@ -680,42 +726,12 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) for(d = 0, i = targets; i; i = i->next, d++) { htables[d] = new_strhash(151); - strhash_add_list(htables[d], ((pkginfo_t*)i->data)->files); } htables[target_num] = new_strhash(151); - /* 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. - * - pkginfo_t *info = NULL; - char *dbstr = NULL; - rewinddir(db->dir); - - while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL) { - for(i = info->files; i; i = i->next) { - dbstr = (char*)i->data; - - if(dbstr == NULL || rindex(dbstr, '/') == dbstr+strlen(dbstr)-1) - continue; - - for(d = 0, j = targets; j; j = j->next, d++) { - pkginfo_t *targ = (pkginfo_t*)j->data; - if(strcmp(info->name, targ->name) && strhash_isin(htables[d], dbstr)) { - MALLOC(str, 512); - snprintf(str, 512, "%s: exists in \"%s\" (target) and \"%s\" (installed)", dbstr, - targ->name, info->name); - conflicts = list_add(conflicts, str); - } - } - } - }*/ - - /* CHECK 2: check every target against every target */ + /* CHECK 1: check every target against every target */ for(d = 0, i = targets; i; i = i->next, d++) { pkginfo_t *p1 = (pkginfo_t*)i->data; for(e = d, j = i; j; j = j->next, e++) { @@ -741,7 +757,7 @@ PMList* db_find_conflicts(pacdb_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) { pkginfo_t *p = (pkginfo_t*)i->data; pkginfo_t *dbpkg = NULL; @@ -769,6 +785,7 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data); stat(str, &buf2); if(buf.st_ino == buf2.st_ino && buf.st_dev == buf2.st_dev) { + printf("inodes match: %s and %s\n", path, str); ok = 1; } } @@ -785,7 +802,26 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) dbpkg2 = db_scan(db, p1->name, INFRQ_DESC | INFRQ_FILES); /* If it used to exist in there, but doesn't anymore */ if(dbpkg2 && !is_in(filestr, p1->files) && is_in(filestr, dbpkg2->files)) { + /*printf("file %s moved from %s to %s\n", filestr, p1->name, p->name);*/ + 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 = list_add(*skip_list, filestr); } FREEPKG(dbpkg2); } @@ -801,6 +837,11 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) FREEPKG(dbpkg); } + /* free up the hash tables */ + for(d = 0; d <= target_num; d++) { + free_strhash(htables[d]); + } + return(conflicts); } diff --git a/src/db.h b/src/db.h index 402280f8..f7d2a1a7 100644 --- a/src/db.h +++ b/src/db.h @@ -22,6 +22,7 @@ #define _PAC_DB_H #include +#include "strhash.h" /* info requests for db_read */ #define INFRQ_DESC 0x01 @@ -35,6 +36,9 @@ typedef struct __pacdb_t { DIR* dir; } pacdb_t; +/* hash table for caching db_scan() results */ +static strhash_t* db_htable; + pacdb_t* db_open(char *root, char *dbpath, char *treename); void db_close(pacdb_t *db); int db_getlastupdate(const char *dbpath, char *ts); @@ -43,8 +47,9 @@ PMList* db_loadpkgs(pacdb_t *db); pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq); pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq); int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq); +void db_remove(pacdb_t *db, pkginfo_t *target); void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles); -PMList* db_find_conflicts(pacdb_t *db, PMList* targets, char *root); +PMList* db_find_conflicts(pacdb_t *db, PMList* targets, char *root, PMList **skip_list); PMList *whatprovides(pacdb_t *db, char* package); PMList *find_groups(pacdb_t *db); PMList *pkg_ingroup(pacdb_t *db, char *group); diff --git a/src/list.c b/src/list.c index 689a17d3..49c07f51 100644 --- a/src/list.c +++ b/src/list.c @@ -67,17 +67,14 @@ PMList* list_new() void list_free(PMList *list) { - if(list == NULL) { - return; - } - if(list->data != NULL) { - free(list->data); - list->data = NULL; - } - if(list->next != NULL) { - list_free(list->next); + PMList *ptr, *it = list; + + while(it) { + ptr = it->next; + free(it->data); + free(it); + it = ptr; } - free(list); return; } diff --git a/src/pacconf.h b/src/pacconf.h index ceab2044..2274b9ec 100644 --- a/src/pacconf.h +++ b/src/pacconf.h @@ -22,7 +22,7 @@ #define _PAC_PACCONF_H #ifndef PACVER -#define PACVER "2.9.5" +#define PACVER "2.9.6" #endif #ifndef PACDBDIR diff --git a/src/pacman.c b/src/pacman.c index f12643e5..3daa1fe4 100644 --- a/src/pacman.c +++ b/src/pacman.c @@ -240,7 +240,7 @@ int main(int argc, char *argv[]) /* start the requested operation */ switch(pmo_op) { case PM_ADD: ret = pacman_add(db_local, pm_targets, NULL); break; - case PM_REMOVE: ret = pacman_remove(db_local, pm_targets); break; + case PM_REMOVE: ret = pacman_remove(db_local, pm_targets, NULL); break; case PM_UPGRADE: ret = pacman_upgrade(db_local, pm_targets, NULL); break; case PM_QUERY: ret = pacman_query(db_local, pm_targets); break; case PM_SYNC: ret = pacman_sync(db_local, pm_targets); break; @@ -1323,7 +1323,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) int oldval = pmo_nodeps; /* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */ pmo_nodeps = 1; - retcode = pacman_remove(db, rmtargs); + retcode = pacman_remove(db, rmtargs, NULL); pmo_nodeps = oldval; FREELIST(rmtargs); if(retcode == 1) { @@ -1356,7 +1356,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) int oldval = pmo_nodeps; /* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */ pmo_nodeps = 1; - allgood = !pacman_remove(db, rmtargs); + allgood = !pacman_remove(db, rmtargs, NULL); pmo_nodeps = oldval; if(!allgood) { fprintf(stderr, "package removal failed. aborting...\n"); @@ -1367,11 +1367,17 @@ int pacman_sync(pacdb_t *db, PMList *targets) allgood = !pacman_upgrade(db, files, dependonly); } /* propagate replaced packages' requiredby fields to their new owners */ + /* XXX: segfault */ if(allgood) { for(i = final; i; i = i->next) { syncpkg_t *sync = (syncpkg_t*)i->data; if(sync->replaces) { - pkginfo_t *new = db_scan(db, sync->pkg->name, INFRQ_DEPENDS); + pkginfo_t *new; + new = db_scan(db, sync->pkg->name, INFRQ_DEPENDS); + if(!new) { + fprintf(stderr, "Something has gone terribly wrong. I'll probably segfault now.\n"); + fflush(stderr); + } for(j = sync->replaces; j; j = j->next) { pkginfo_t *old = (pkginfo_t*)j->data; /* merge lists */ @@ -1448,6 +1454,8 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) struct stat buf; PMList *targ, *lp, *j, *k; PMList *alltargs = NULL; + PMList *skiplist = NULL; + unsigned short real_pmo_upgrade; tartype_t gztype = { (openfunc_t) gzopen_frontend, @@ -1646,7 +1654,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) alltargs = k; /* make sure pacman_remove does it's own dependency check */ pmo_upgrade = 0; - retcode = pacman_remove(db, rmtargs); + retcode = pacman_remove(db, rmtargs, NULL); list_free(rmtargs); if(retcode == 1) { fprintf(stderr, "\n%s aborted.\n", oldupg ? "upgrade" : "install"); @@ -1683,7 +1691,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) if(!pmo_force) { printf("checking for file conflicts... "); fflush(stdout); - lp = db_find_conflicts(db, alltargs, pmo_root); + lp = db_find_conflicts(db, alltargs, pmo_root, &skiplist); if(lp) { printf("\nerror: the following file conflicts were found:\n"); for(j = lp; j; j = j->next) { @@ -1738,7 +1746,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) /* copy over the install reason */ info->reason = oldpkg->reason; vprint("removing old package first...\n"); - retcode = pacman_remove(db, tmp); + retcode = pacman_remove(db, tmp, skiplist); FREELIST(tmp); if(retcode == 1) { fprintf(stderr, "\nupgrade aborted.\n"); @@ -1793,7 +1801,20 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) snprintf(expath, PATH_MAX, "%s%s", pmo_root, pathname); } - if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) { + /* if a file is in NoUpgrade and missing from the filesystem, + * then we never extract it. + * + * eg, /home/httpd/html/index.html may be removed so index.php + * could be used + */ + if(stat(expath, &buf) && is_in(pathname, pmo_noupgrade)) { + vprint("%s is in NoUpgrade - skipping\n", pathname); + logaction(stderr, "warning: %s is in NoUpgrade -- skipping extraction", pathname); + tar_skip_regfile(tar); + continue; + } + + if(!notouch && !stat(expath, &buf) && !S_ISDIR(buf.st_mode)) { /* file already exists */ if(is_in(pathname, pmo_noupgrade)) { notouch = 1; @@ -1916,7 +1937,6 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) vprint("%s is in NoUpgrade - skipping\n", pathname); strncat(expath, ".pacnew", PATH_MAX); logaction(stderr, "warning: extracting %s%s as %s", pmo_root, pathname, expath); - /*tar_skip_regfile(tar);*/ } if(pmo_force) { /* if pmo_force was used, then unlink() each file (whether it's there @@ -1980,6 +2000,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) continue; } } + FREEPKG(tmpp); } vprint("Updating database..."); @@ -2019,6 +2040,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) if(provides) { /* use the first one */ depinfo = db_scan(db, provides->data, INFRQ_DEPENDS); + FREELIST(provides); if(depinfo == NULL) { /* wtf */ continue; @@ -2066,7 +2088,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly) return(ret); } -int pacman_remove(pacdb_t *db, PMList *targets) +int pacman_remove(pacdb_t *db, PMList *targets, PMList *skiplist) { char line[PATH_MAX+1]; char pm_install[PATH_MAX+1]; @@ -2137,8 +2159,17 @@ int pacman_remove(pacdb_t *db, PMList *targets) for(j = lp; j; j = j->next) { depmissing_t* miss = (depmissing_t*)j->data; info = db_scan(db, miss->depend.name, INFRQ_ALL); + if(info == NULL) { + fprintf(stderr, "error: %s is not installed, even though it is required\n", miss->depend.name); + fprintf(stderr, " by an installed package (%s)\n\n", miss->target); + fprintf(stderr, "cannot complete a cascade removal with a broken dependency chain\n"); + FREELISTPKGS(alltargs); + return(1); + } if(!is_pkgin(info, alltargs)) { alltargs = list_add(alltargs, info); + } else { + FREEPKG(info); } } list_free(lp); @@ -2198,16 +2229,19 @@ int pacman_remove(pacdb_t *db, PMList *targets) /* iterate through the list backwards, unlinking files */ for(lp = list_last(info->files); lp; lp = lp->prev) { int nb = 0; - if(needbackup((char*)lp->data, info->backup)) { + char *file; + + file = (char*)lp->data; + if(needbackup(file, info->backup)) { nb = 1; } if(!nb && pmo_upgrade) { /* check pmo_noupgrade */ - if(is_in((char*)lp->data, pmo_noupgrade)) { + if(is_in(file, pmo_noupgrade)) { nb = 1; } } - snprintf(line, PATH_MAX, "%s%s", pmo_root, (char*)lp->data); + snprintf(line, PATH_MAX, "%s%s", pmo_root, file); if(lstat(line, &buf)) { vprint("file %s does not exist\n", line); continue; @@ -2218,27 +2252,41 @@ int pacman_remove(pacdb_t *db, PMList *targets) /* this is okay, other packages are probably using it. */ } } else { - /* if the file is flagged, back it up to .pacsave */ - if(nb) { - if(pmo_upgrade) { - /* we're upgrading so just leave the file as is. pacman_add() will handle it */ - } else { - if(!pmo_nosave) { - newpath = (char*)realloc(newpath, strlen(line)+strlen(".pacsave")+1); - sprintf(newpath, "%s.pacsave", line); - rename(line, newpath); - logaction(stderr, "warning: %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; + for(j = skiplist; j; j = j->next) { + if(!strcmp(file, (char*)j->data)) { + skipit = 1; + } + } + if(skipit) { + vprint("skipping removal of %s (it has moved to another package)\n", file); + } else { + /* if the file is flagged, back it up to .pacsave */ + if(nb) { + if(pmo_upgrade) { + /* we're upgrading so just leave the file as is. pacman_add() will handle it */ } else { - /*vprint(" unlinking %s\n", line);*/ - if(unlink(line)) { - perror("cannot remove file"); + if(!pmo_nosave) { + newpath = (char*)realloc(newpath, strlen(line)+strlen(".pacsave")+1); + sprintf(newpath, "%s.pacsave", line); + rename(line, newpath); + logaction(stderr, "warning: %s saved as %s", line, newpath); + } else { + /*vprint(" unlinking %s\n", line);*/ + if(unlink(line)) { + perror("cannot remove file"); + } } } - } - } else { - /*vprint(" unlinking %s\n", line);*/ - if(unlink(line)) { - perror("cannot remove file"); + } else { + /*vprint(" unlinking %s\n", line);*/ + if(unlink(line)) { + perror("cannot remove file"); + } } } } @@ -2252,27 +2300,11 @@ int pacman_remove(pacdb_t *db, PMList *targets) } /* remove the package from the database */ - snprintf(line, PATH_MAX, "%s%s/%s/%s-%s", pmo_root, pmo_dbpath, db->treename, - info->name, info->version); - - /* DESC */ - snprintf(pm_install, PATH_MAX, "%s/desc", line); - unlink(pm_install); - /* FILES */ - snprintf(pm_install, PATH_MAX, "%s/files", line); - unlink(pm_install); - /* DEPENDS */ - snprintf(pm_install, PATH_MAX, "%s/depends", line); - unlink(pm_install); - /* INSTALL */ - snprintf(pm_install, PATH_MAX, "%s/install", line); - unlink(pm_install); - /* directory */ - rmdir(line); + db_remove(db, info); /* update dependency packages' REQUIREDBY fields */ for(lp = info->depends; lp; lp = lp->next) { - PMList *j; + PMList *k; if(splitdep((char*)lp->data, &depend)) { continue; @@ -2298,9 +2330,9 @@ int pacman_remove(pacdb_t *db, PMList *targets) } } /* splice out this entry from requiredby */ - for(j = depinfo->requiredby; j; j = j->next) { - if(!strcmp((char*)j->data, info->name)) { - depinfo->requiredby = list_remove(depinfo->requiredby, j); + for(k = depinfo->requiredby; k; k = k->next) { + if(!strcmp((char*)k->data, info->name)) { + depinfo->requiredby = list_remove(depinfo->requiredby, k); break; } } @@ -2673,6 +2705,7 @@ PMList* removedeps(pacdb_t *db, PMList *targs) FREELIST(k); } if(is_pkgin(dep, targs)) { + FREEPKG(dep); continue; } /* see if it was explicitly installed */ @@ -2687,10 +2720,11 @@ PMList* removedeps(pacdb_t *db, PMList *targs) if(!is_pkgin(dummy, targs)) { needed = 1; } + FREEPKG(dummy); } + FREEPKG(dep); if(!needed) { /* add it to the target list */ - freepkg(dep); dep = db_scan(db, depend.name, INFRQ_ALL); newtargs = list_add(newtargs, dep); newtargs = removedeps(db, newtargs); @@ -2922,6 +2956,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.version, depend.version, 64); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } FREEPKG(p); @@ -2969,6 +3005,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.name, dp->name, 256); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } } @@ -3002,6 +3040,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.name, otp->name, 256); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } } @@ -3036,6 +3076,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.name, info->name, 256); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } } @@ -3063,6 +3105,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.name, k->data, 256); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } }*/ @@ -3178,6 +3222,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.version, depend.version, 64); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } } @@ -3200,6 +3246,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) strncpy(miss->depend.name, (char*)j->data, 256); if(!list_isin(baddeps, miss)) { baddeps = list_add(baddeps, miss); + } else { + FREE(miss); } } } @@ -3326,10 +3374,10 @@ int runscriptlet(char *installfn, char *script, char *ver, char *oldver) vprint("Executing %s script...\n", script); if(oldver) { - snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s %s\" | chroot %s /bin/sh", + snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s %s\" | /usr/sbin/chroot %s /bin/sh", scriptpath, script, ver, oldver, pmo_root); } else { - snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s\" | chroot %s /bin/sh", + snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s\" | /usr/sbin/chroot %s /bin/sh", scriptpath, script, ver, pmo_root); } vprint("%s\n", cmdline); diff --git a/src/pacman.h b/src/pacman.h index 9e22bb31..79106eb1 100644 --- a/src/pacman.h +++ b/src/pacman.h @@ -33,7 +33,7 @@ #define min(X, Y) ((X) < (Y) ? (X) : (Y)) int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly); -int pacman_remove(pacdb_t *db, PMList *targets); +int pacman_remove(pacdb_t *db, PMList *targets, PMList *skiplist); int pacman_upgrade(pacdb_t *db, PMList *targets, PMList *dependonly); int pacman_query(pacdb_t *db, PMList *targets); int pacman_sync(pacdb_t *db, PMList *targets); diff --git a/src/pacsync.c b/src/pacsync.c index c2ff4bee..4b1f1b53 100644 --- a/src/pacsync.c +++ b/src/pacsync.c @@ -441,6 +441,13 @@ int downloadfiles_forreal(PMList *servers, const char *localpath, snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn); rename(output, completefile); } else if(filedone < 0) { + if(!pmo_xfercommand) { + if(!strcmp(server->protocol, "ftp") && !pmo_proxyhost) { + FtpQuit(control); + } else if(!strcmp(server->protocol, "http") || (pmo_proxyhost && strcmp(server->protocol, "file"))) { + HttpQuit(control); + } + } return(-1); } printf("\n"); diff --git a/src/strhash.c b/src/strhash.c index 1ee5498c..01e172a4 100644 --- a/src/strhash.c +++ b/src/strhash.c @@ -1,22 +1,22 @@ /* evtgen string hash functions. - Copyright (C) 2003 Julien Olivain and LSV, CNRS UMR 8643 & ENS Cachan. + Copyright (C) 2003 Julien Olivain and LSV, CNRS UMR 8643 & ENS Cachan. - This file is part of evtgen. + This file is part of evtgen. - evtgen is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + evtgen is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. - evtgen is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + evtgen is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with evtgen; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + You should have received a copy of the GNU General Public License + along with evtgen; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* Copyright (C) 2004 Tommi Rantala * @@ -24,8 +24,8 @@ */ /* -** strhash.c -- string hash utility functions -*/ + ** strhash.c -- string hash utility functions + */ #include #include @@ -35,161 +35,168 @@ #include "list.h" #include "strhash.h" -void -strhash_add_list(strhash_t *hash, PMList* list) +void strhash_add_list(strhash_t *hash, PMList* list) { - for(; list; list = list->next) + for(; list; list = list->next) { strhash_add(hash, list->data, NULL); + } } -strhash_t * -new_strhash(size_t hsize) +strhash_t* new_strhash(size_t hsize) { - strhash_t *h; + strhash_t *h; - MALLOC(h, sizeof (strhash_t)); - h->size = hsize; - h->elmts = 0; - h->hash = DEFAULT_STRHASH_FUNCTION; - MALLOC(h->htable, hsize * sizeof (strhash_elmt_t *)); - memset(h->htable, 0, hsize * sizeof(strhash_elmt_t *)); + MALLOC(h, sizeof(strhash_t)); + h->size = hsize; + h->elmts = 0; + h->hash = DEFAULT_STRHASH_FUNCTION; + MALLOC(h->htable, hsize * sizeof(strhash_elmt_t *)); + memset(h->htable, 0, hsize * sizeof(strhash_elmt_t *)); - return (h); + return(h); } -void -clear_strhash(strhash_t *hash) +void clear_strhash(strhash_t *hash) { - int i; - strhash_elmt_t *tmp; - strhash_elmt_t *tmp_next; - - for (i = 0; i < hash->size; i++) - { - tmp = hash->htable[i]; - while (tmp) - { - tmp_next = tmp->next; - free(tmp); - tmp = tmp_next; - } - } - hash->elmts = 0; - memset(hash->htable, 0, hash->size * sizeof (void *)); + int i; + strhash_elmt_t *tmp; + strhash_elmt_t *tmp_next; + + for(i = 0; i < hash->size; i++) { + tmp = hash->htable[i]; + while(tmp) { + tmp_next = tmp->next; + free(tmp); + tmp = tmp_next; + } + } + hash->elmts = 0; + memset(hash->htable, 0, hash->size * sizeof(void *)); } - -void -free_strhash(strhash_t *hash) +void free_strhash(strhash_t *hash) { - int i; - strhash_elmt_t *tmp; - strhash_elmt_t *tmp_next; - - for (i = 0; i < hash->size; i++) - { - tmp = hash->htable[i]; - while (tmp) - { - tmp_next = tmp->next; - free(tmp); - tmp = tmp_next; - } - } - - free(hash->htable); - free(hash); + int i; + strhash_elmt_t *tmp; + strhash_elmt_t *tmp_next; + + for(i = 0; i < hash->size; i++) { + tmp = hash->htable[i]; + while(tmp) { + tmp_next = tmp->next; + free(tmp); + tmp = tmp_next; + } + } + + free(hash->htable); + free(hash); } -void -strhash_add(strhash_t *hash, char *key, char *data) +void strhash_add(strhash_t *hash, char *key, char *data) { - strhash_elmt_t *elmt; - unsigned long hcode; + strhash_elmt_t *elmt; + unsigned long hcode; - MALLOC(elmt, sizeof (strhash_elmt_t)); - elmt->key = key; - elmt->data = data; + MALLOC(elmt, sizeof(strhash_elmt_t)); + elmt->key = key; + elmt->data = data; + + hcode = hash->hash(key) % hash->size; + elmt->next = hash->htable[hcode]; + hash->htable[hcode] = elmt; + hash->elmts++; +} - hcode = hash->hash(key) % hash->size; - elmt->next = hash->htable[hcode]; - hash->htable[hcode] = elmt; - hash->elmts++; +void strhash_remove(strhash_t *hash, char *key) +{ + unsigned long hcode; + strhash_elmt_t *elmt; + strhash_elmt_t *prev = NULL; + + hcode = hash->hash(key) % hash->size; + + elmt = hash->htable[hcode]; + for(; elmt; elmt = elmt->next) { + if(!strcmp(key, elmt->key)) { + if(prev) { + prev->next = elmt->next; + } else { + hash->htable[hcode] = elmt->next; + } + FREE(elmt); + return; + } + prev = elmt; + } } /* 1: Yes, the key exists in the hash table. - * 0: No, its not here. + * 0: No, it's not here. */ - -int -strhash_isin(strhash_t *hash, char* key) +int strhash_isin(strhash_t *hash, char* key) { - strhash_elmt_t *elmt; + strhash_elmt_t *elmt; - elmt = hash->htable[hash->hash(key) % hash->size]; - for (; elmt; elmt = elmt->next) - { - if (!strcmp(key, elmt->key)) - return 1; - } + elmt = hash->htable[hash->hash(key) % hash->size]; + for(; elmt; elmt = elmt->next) { + if(!strcmp(key, elmt->key)) { + return 1; + } + } - return 0; + return 0; } -char* -strhash_get(strhash_t *hash, char* key) +char* strhash_get(strhash_t *hash, char* key) { - strhash_elmt_t *elmt; + strhash_elmt_t *elmt; - elmt = hash->htable[hash->hash(key) % hash->size]; - for (; elmt; elmt = elmt->next) - { - if (!strcmp(key, elmt->key)) - return elmt->data; - } + elmt = hash->htable[hash->hash(key) % hash->size]; + for(; elmt; elmt = elmt->next) { + if(!strcmp(key, elmt->key)) { + return elmt->data; + } + } - return NULL; + return NULL; } /* -** fast hash function samples -*/ - -unsigned long -strhash_pjw(char *key) + ** fast hash function samples + */ +unsigned long strhash_pjw(char *key) { - unsigned long h; - unsigned long g; - - h = 0; - while (*key) - { - h = (h << 4) + *key++; - if ((g = h & 0xF0000000U) != 0) - { - h = h ^ (g >> 24); - h = h ^ g; - } - } - - return (h); + unsigned long h; + unsigned long g; + + h = 0; + while(*key) { + h = (h << 4) + *key++; + if((g = h & 0xF0000000U) != 0) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return (h); } -int -strhash_collide_count(strhash_t *hash) +int strhash_collide_count(strhash_t *hash) { - int count; - int i; + int count; + int i; - count = 0; - for (i = 0; i < hash->size; i++) - { - strhash_elmt_t *tmp; + count = 0; + for(i = 0; i < hash->size; i++) { + strhash_elmt_t *tmp; - for (tmp = hash->htable[i]; tmp; tmp = tmp->next) - if (tmp->next) - count++; - } + for(tmp = hash->htable[i]; tmp; tmp = tmp->next) { + if(tmp->next) { + count++; + } + } + } - return (count); + return(count); } diff --git a/src/strhash.h b/src/strhash.h index 65b7f4e1..9c2d63ec 100644 --- a/src/strhash.h +++ b/src/strhash.h @@ -55,6 +55,7 @@ void strhash_add_list(strhash_t *hash, PMList* list); strhash_t *new_strhash(size_t hsize); void free_strhash(strhash_t *hash); void clear_strhash(strhash_t *hash); +void strhash_remove(strhash_t *hash, char *key); void strhash_add(strhash_t *hash, char *key, char *data); int strhash_isin(strhash_t *hash, char* key); char* strhash_get(strhash_t *hash, char* key); -- cgit v1.2.3-24-g4f1b