From a11fb0b581356b23b343683302e201ff7dfcfe48 Mon Sep 17 00:00:00 2001 From: Judd Vinet Date: Wed, 18 Feb 2004 07:09:00 +0000 Subject: Imported from pacman-2.7.4.tar.gz --- ChangeLog | 10 + Makefile.in | 2 +- TODO | 6 - doc/pacman.8.in | 5 + etc/pacman.conf | 11 +- scripts/gensync | 2 +- scripts/makepkg | 2 +- scripts/makeworld | 2 +- src/db.c | 9 +- src/package.c | 40 +- src/package.h | 3 +- src/pacman.c | 140 ++- src/pacman.c~ | 3145 ----------------------------------------------------- src/pacman.h | 2 +- 14 files changed, 189 insertions(+), 3190 deletions(-) delete mode 100644 src/pacman.c~ diff --git a/ChangeLog b/ChangeLog index 5ae7e954..f1b87d4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ VERSION DESCRIPTION ----------------------------------------------------------------------------- +2.7.4 - fixed a bug in conflict handling, where installing a + conflicting package would fail even if the new package + "provided" it + - if pacman sees a newer version of itself during an upgrade, + it will ask to install itself first, then be re-run to upgrade + the other packages. + - You can now use the --info option with --sync to display an + uninstalled package's dependency info. + - Added a sane umask before db writes + - buffer overflow fix (bug #442) 2.7.3 - makepkg not longer strips files with .exe or .dll extensions - Added Aurelien's patch: - proxy support (no authentication yet) diff --git a/Makefile.in b/Makefile.in index 13a24109..d9fa642b 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.7.3 +PACVER = 2.7.4 TOPDIR = @srcdir@ SRCDIR = $(TOPDIR)/src/ diff --git a/TODO b/TODO index 022d7f53..ec0fea3c 100644 --- a/TODO +++ b/TODO @@ -3,13 +3,7 @@ - replaces code doesn't run with -U or -A - when performing replaces, pacman should not remove old packages until the conflict checks are passed -- --info should work with --sync to display dependencies -- add an ETA to the download progress bar -- add HTTP/1.1 support -- fix the broken pipe bug - handle version comparators in makepkg dep resolution (eg, glibc>=2.2.5) - add post_remove, pre_install, pre_upgrade functions to scriptlets -? record md5sums of all files in a package -? use 'set -e' in makepkg? - check $PACCONF env var - add a --pretend option diff --git a/doc/pacman.8.in b/doc/pacman.8.in index 491604ce..622b6860 100644 --- a/doc/pacman.8.in +++ b/doc/pacman.8.in @@ -100,6 +100,11 @@ diskspace, you can remove these packages by using the --clean option. Display all the members for each package group specified. If no group names are provided, all groups will be listed. .TP +.B "\-i, \-\-info" +Display dependency information for a given package. This will search +through all repositories for a matching package and display the +dependencies, conflicts, etc. +.TP .B "\-l, \-\-list" List all files in the specified repositories. Multiple repositories can be specified on the command line. diff --git a/etc/pacman.conf b/etc/pacman.conf index 73c9dcbf..7117c85d 100644 --- a/etc/pacman.conf +++ b/etc/pacman.conf @@ -5,6 +5,11 @@ # move it to the top of the server list, so pacman will choose it # first. # +# To re-sort your mirror lists by ping/traceroute results, use the +# /usr/bin/sortmirrors.pl script. It requires the "netselect" package. +# +# # sortmirrors.pl pacman.conf.new +# # See the pacman manpage for option directives @@ -25,10 +30,10 @@ NoUpgrade = etc/lilo.conf boot/grub/menu.lst # [current] Server = ftp://ftp.archlinux.org/current +Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/current Server = ftp://ftp.archlinux.de/pub/archlinux/current Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/current Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/current -Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/current Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/current Server = ftp://ftp.parrswood.net/Mirrors/ftp.archlinux.org/current Server = ftp://ftp.kegep.tuc.gr/archlinux/current @@ -41,12 +46,12 @@ Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/current # Uncomment this block to access the EXTRA package set # [extra] -Server = ftp://ftp.archlinux.org/extra +Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/extra Server = ftp://ftp.archlinux.de/pub/archlinux/extra Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/extra Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/extra -Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/extra Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/extra +Server = ftp://ftp.archlinux.org/extra Server = ftp://ftp.parrswood.net/Mirrors/ftp.archlinux.org/extra Server = ftp://ftp.kegep.tuc.gr/archlinux/extra Server = http://darkstar.ist.utl.pt/archlinux/extra diff --git a/scripts/gensync b/scripts/gensync index 85774781..4af3a86b 100755 --- a/scripts/gensync +++ b/scripts/gensync @@ -20,7 +20,7 @@ # USA. # -myver='2.7.3' +myver='2.7.4' usage() { echo "gensync $myver" diff --git a/scripts/makepkg b/scripts/makepkg index df6db755..f3922b2b 100755 --- a/scripts/makepkg +++ b/scripts/makepkg @@ -20,7 +20,7 @@ # USA. # -myver='2.7.3' +myver='2.7.4' startdir=`pwd` USE_COLOR="n" diff --git a/scripts/makeworld b/scripts/makeworld index 20a5b8d9..bf273472 100755 --- a/scripts/makeworld +++ b/scripts/makeworld @@ -21,7 +21,7 @@ # toplevel=`pwd` -version="2.7.3" +version="2.7.4" usage() { echo "makeworld version $version" diff --git a/src/db.c b/src/db.c index 862d8020..e70d0196 100644 --- a/src/db.c +++ b/src/db.c @@ -41,7 +41,7 @@ pacdb_t* db_open(char *root, char *pkgdir, char *treename) if(db->dir == NULL) { return(NULL); } - strncpy(db->treename, treename, 128); + strncpy(db->treename, treename, sizeof(db->treename)); return(db); } @@ -355,13 +355,15 @@ int db_write(pacdb_t *db, pkginfo_t *info) info->name, info->version); oldmask = umask(0000); mkdir(topdir, 0755); - umask(oldmask); + /* make sure we have a sane umask */ + umask(0022); /* DESC */ snprintf(path, PATH_MAX, "%s/desc", topdir); fp = fopen(path, "w"); if(fp == NULL) { perror("db_write"); + umask(oldmask); return(1); } fputs("%NAME%\n", fp); @@ -392,6 +394,7 @@ int db_write(pacdb_t *db, pkginfo_t *info) fp = fopen(path, "w"); if(fp == NULL) { perror("db_write"); + umask(oldmask); return(1); } fputs("%FILES%\n", fp); @@ -411,6 +414,7 @@ int db_write(pacdb_t *db, pkginfo_t *info) fp = fopen(path, "w"); if(fp == NULL) { perror("db_write"); + umask(oldmask); return(1); } fputs("%DEPENDS%\n", fp); @@ -438,6 +442,7 @@ int db_write(pacdb_t *db, pkginfo_t *info) /* INSTALL */ /* nothing needed here (script is automatically extracted) */ + umask(oldmask); return(0); } diff --git a/src/package.c b/src/package.c index 0f6b0c91..6eeccd01 100644 --- a/src/package.c +++ b/src/package.c @@ -302,9 +302,9 @@ int is_pkgin(pkginfo_t *needle, PMList *haystack) return(0); } -/* Display the content of a package +/* Display the content of an installed package */ -void dump_pkg(pkginfo_t *info) +void dump_pkg_full(pkginfo_t *info) { PMList *pm; @@ -335,7 +335,41 @@ void dump_pkg(pkginfo_t *info) pm = list_sort(info->conflicts); list_display("Conflicts With :", pm); FREELIST(pm); - printf("Description : %s\n", info->desc); + printf("Description : "); + indentprint(info->desc, 17); + printf("\n"); +} + +/* Display the content of a sync package + */ +void dump_pkg_sync(pkginfo_t *info) +{ + PMList *pm; + + if(info == NULL) { + return; + } + + printf("Name : %s\n", info->name); + printf("Version : %s\n", info->version); + pm = list_sort(info->groups); + list_display("Groups :", pm); + FREELIST(pm); + pm = list_sort(info->provides); + list_display("Provides :", pm); + FREELIST(pm); + pm = list_sort(info->depends); + list_display("Depends On :", pm); + FREELIST(pm); + pm = list_sort(info->conflicts); + list_display("Conflicts With :", pm); + FREELIST(pm); + pm = list_sort(info->replaces); + list_display("Replaces :", pm); + FREELIST(pm); + printf("Description : "); + indentprint(info->desc, 17); + printf("\nMD5 Sum : %s\n", info->md5sum); } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/package.h b/src/package.h index b7d72f8f..4246486b 100644 --- a/src/package.h +++ b/src/package.h @@ -80,7 +80,8 @@ pkginfo_t* newpkg(); void freepkg(pkginfo_t *pkg); int pkgcmp(const void *p1, const void *p2); int is_pkgin(pkginfo_t *needle, PMList *haystack); -void dump_pkg(pkginfo_t *info); +void dump_pkg_full(pkginfo_t *info); +void dump_pkg_sync(pkginfo_t *info); #endif /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman.c b/src/pacman.c index 803f39d6..18e36395 100644 --- a/src/pacman.c +++ b/src/pacman.c @@ -136,7 +136,8 @@ int main(int argc, char *argv[]) /* check for permission */ pm_access = READ_ONLY; if(pmo_op != PM_MAIN && pmo_op != PM_QUERY && pmo_op != PM_DEPTEST) { - if(pmo_op == PM_SYNC && !pmo_s_sync && (pmo_s_search || pmo_group || pmo_q_list)) { + if(pmo_op == PM_SYNC && !pmo_s_sync && + (pmo_s_search || pmo_group || pmo_q_list || pmo_q_info)) { /* special case: PM_SYNC can be used w/ pmo_s_search by any user */ } else { if(geteuid() != 0) { @@ -178,7 +179,7 @@ int main(int argc, char *argv[]) /* check for db existence */ /* add a trailing '/' if there isn't one */ if(pmo_root[strlen(pmo_root)-1] != '/') { - MALLOC(ptr, strlen(pmo_root)+1); + MALLOC(ptr, strlen(pmo_root)+2); strcpy(ptr, pmo_root); strcat(ptr, "/"); FREE(pmo_root); @@ -459,6 +460,48 @@ int pacman_sync(pacdb_t *db, PMList *targets) FREELIST(pkg); } FREELIST(groups); + } else if(pmo_q_info) { + PMList *pkgs = NULL; + int found; + if(targets) { + for(i = targets; i; i = i->next) { + pkgs = list_add(pkgs, strdup(i->data)); + } + } else { + for(i = databases; i; i = i->next) { + dbsync_t *dbs = (dbsync_t *)i->data; + for(j = dbs->pkgcache; j; j = j->next) { + pkgs = list_add(pkgs, strdup(((pkginfo_t*)j->data)->name)); + } + } + } + for(i = pkgs; i; i = i->next) { + found = 0; + for(j = databases; j; j = j->next) { + dbsync_t *dbs = (dbsync_t *)j->data; + for(k = dbs->pkgcache; k; k = k->next) { + pkginfo_t *p = (pkginfo_t*)k->data; + if(!strcmp(p->name, i->data)) { + /* re-fetch with dependency info */ + p = db_scan(dbs->db, p->name, INFRQ_DESC | INFRQ_DEPENDS); + if(p == NULL) { + /* wtf */ + continue; + } + dump_pkg_sync(p); + printf("\n"); + freepkg(p); + found = 1; + } + } + } + if(!found) { + fprintf(stderr, "Package \"%s\" was not found.\n", (char *)i->data); + allgood = 0; + break; + } + } + FREELIST(pkgs); } else if(pmo_q_list) { PMList *reps = NULL; int found; @@ -493,6 +536,8 @@ int pacman_sync(pacdb_t *db, PMList *targets) } else if(pmo_s_upgrade) { int newer = 0; int ignore = 0; + syncpkg_t *s = NULL; + logaction(NULL, "starting full system upgrade"); /* check for "recommended" package replacements */ for(i = databases; i && allgood; i = i->next) { @@ -507,7 +552,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* if confirmed, add this to the 'final' list, designating 'p' as * the package to replace. */ - if(yesno(":: replace %s with %s from \"%s\"? [Y/n] ", p->name, pkg->name, dbs->db->treename)) { + if(yesno(":: Replace %s with %s from \"%s\"? [Y/n] ", p->name, pkg->name, dbs->db->treename)) { syncpkg_t *sync = NULL; /* we save the dependency info so we can move p's requiredby stuff * over to the replacing package @@ -523,8 +568,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* none found -- enter pkg into the final sync list */ MALLOC(sync, sizeof(syncpkg_t)); sync->dbs = dbs; - sync->replaces = NULL; - sync->replaces = list_add(sync->replaces, q); + sync->replaces = list_add(NULL, q); sync->pkg = db_scan(sync->dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); /* add to the targets list */ allgood = !resolvedeps(db, databases, sync, final, trail); @@ -603,6 +647,27 @@ int pacman_sync(pacdb_t *db, PMList *targets) if((newer || ignore) && allgood) { fprintf(stderr, ":: Above packages will be skipped. To manually upgrade use 'pacman -S '\n"); } + /* check if pacman itself is one of the packages to upgrade. if so, we + * we should upgrade ourselves first and then re-exec as the new version. + * + * this can prevent some of the "syntax error" problems users can have + * when sysupgrade'ing with an older version of pacman. + */ + s = find_pkginsync("pacman", final); + if(s && list_count(final) > 1) { + fprintf(stderr, "\n:: pacman has detected a newer version of the \"pacman\" package.\n"); + fprintf(stderr, ":: It is recommended that you allow pacman to upgrade itself\n"); + fprintf(stderr, ":: first, then you can re-run the operation with the newer version.\n"); + fprintf(stderr, "::\n"); + if(yesno(":: Upgrade pacman first? [Y/n] ")) { + /* XXX: leaving final un-freed is a big memory leak, but pacman quits + * right after this upgrade anyway, so... + */ + /* and create a new final list with only "pacman" in it */ + final = list_add(NULL, s); + trail = NULL; + } + } } else { /* process targets */ for(i = targets; i && allgood; i = i->next) { @@ -664,7 +729,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) } else { PMList *l; for(l = k; l; l = l->next) { - if(yesno(":: install %s from group %s? [Y/n] ", (char*)l->data, targ)) { + if(yesno(":: Install %s from group %s? [Y/n] ", (char*)l->data, targ)) { targets = list_add(targets, strdup((char*)l->data)); } } @@ -762,30 +827,54 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* no unresolvable deps, so look for conflicts */ for(i = deps; i && !errorout; i = i->next) { depmissing_t *miss = (depmissing_t*)i->data; - if(miss->type == CONFLICT) { - /* check if the conflicting package is one that's about to be removed/replaced. - * if so, then just ignore it - */ - found = 0; - for(j = final; j && !found; j = j->next) { - syncpkg_t *sync = (syncpkg_t*)j->data; - for(k = sync->replaces; k && !found; k = k->next) { - pkginfo_t *p = (pkginfo_t*)k->data; - if(!strcmp(p->name, miss->depend.name)) { - found = 1; - } + if(miss->type != CONFLICT) { + continue; + } + + /* check if the conflicting package is one that's about to be removed/replaced. + * if so, then just ignore it + */ + found = 0; + for(j = final; j && !found; j = j->next) { + syncpkg_t *sync = (syncpkg_t*)j->data; + for(k = sync->replaces; k && !found; k = k->next) { + pkginfo_t *p = (pkginfo_t*)k->data; + if(!strcmp(p->name, miss->depend.name)) { + found = 1; } } - /* if we didn't find it in any sync->replaces lists, then it's a conflict */ - if(!found && !is_in(miss->depend.name, rmtargs)) { + } + /* if we didn't find it in any sync->replaces lists, then it's a conflict */ + if(!found && !is_in(miss->depend.name, rmtargs)) { + int solved = 0; + syncpkg_t *sync = find_pkginsync(miss->target, final); + for(j = sync->pkg->provides; j && j->data && !solved; j = j->next) { + if(!strcmp(j->data, miss->depend.name)) { + /* this package also "provides" the package it's conflicting with, + * so just treat it like a "replaces" item so the REQUIREDBY + * fields are inherited properly. + */ + + /* we save the dependency info so we can move p's requiredby stuff + * over to the replacing package + */ + pkginfo_t *q = db_scan(db, miss->depend.name, INFRQ_DESC | INFRQ_DEPENDS); + /* append to the replaces list */ + sync->replaces = list_add(sync->replaces, q); + solved = 1; + } + } + if(!solved) { + /* It's a conflict -- see if they want to remove it + */ pkginfo_t p1; /* build a "fake" pkginfo_t so we can search with is_pkgin() */ snprintf(p1.name, sizeof(p1.name), miss->depend.name); sprintf(p1.version, "1.0-1"); - + if(is_pkgin(&p1, pm_packages)) { if(yesno(":: %s conflicts with %s. Remove %s? [Y/n] ", - miss->target, miss->depend.name, miss->depend.name)) { + miss->target, miss->depend.name, miss->depend.name)) { /* remove miss->depend.name */ rmtargs = list_add(rmtargs, strdup(miss->depend.name)); } else { @@ -796,7 +885,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) } else { if(!is_in(miss->depend.name, rmtargs) & !is_in(miss->target, rmtargs)) { fprintf(stderr, "\nerror: %s conflicts with %s\n", miss->target, - miss->depend.name); + miss->depend.name); errorout = 1; } } @@ -1705,7 +1794,7 @@ int pacman_remove(pacdb_t *db, PMList *targets) } } else { for(j = pkgs; j; j = j->next) { - if(yesno(":: remove %s from group %s? [Y/n] ", (char*)j->data, (char*)lp->data)) { + if(yesno(":: Remove %s from group %s? [Y/n] ", (char*)j->data, (char*)lp->data)) { info = db_scan(db, (char *)j->data, INFRQ_ALL); alltargs = list_add(alltargs, info); } @@ -2049,7 +2138,7 @@ int pacman_query(pacdb_t *db, PMList *targets) fprintf(stderr, "Package \"%s\" was not found.\n", package); return(2); } - dump_pkg(info); + dump_pkg_full(info); if(pmo_q_info > 1 && info->backup) { /* extra info */ printf("\n"); @@ -3049,6 +3138,7 @@ void usage(int op, char *myname) printf(" -d, --nodeps skip dependency checks\n"); printf(" -f, --force force install, overwrite conflicting files\n"); printf(" -g, --groups view all members of a package group\n"); + printf(" -i, --info view package information\n"); printf(" -l, --list list all packages belonging to the specified repository\n"); printf(" -s, --search search sync database for matching strings\n"); printf(" -u, --sysupgrade upgrade all packages that are out of date\n"); diff --git a/src/pacman.c~ b/src/pacman.c~ deleted file mode 100644 index e0018ba6..00000000 --- a/src/pacman.c~ +++ /dev/null @@ -1,3145 +0,0 @@ -/* - * pacman.c - * - * Copyright (c) 2002 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. - */ - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* pacman */ -#include "rpmvercmp.h" -#include "md5.h" -#include "list.h" -#include "package.h" -#include "util.h" -#include "db.h" -#include "pacsync.h" -#include "pacman.h" - -/* - * GLOBALS - * - */ - -/* command line options */ -char *pmo_root = NULL; -unsigned short pmo_op = PM_MAIN; -unsigned short pmo_verbose = 0; -unsigned short pmo_version = 0; -unsigned short pmo_help = 0; -unsigned short pmo_force = 0; -unsigned short pmo_nodeps = 0; -unsigned short pmo_upgrade = 0; -unsigned short pmo_freshen = 0; -unsigned short pmo_nosave = 0; -unsigned short pmo_d_vertest = 0; -unsigned short pmo_d_resolve = 0; -unsigned short pmo_q_isfile = 0; -unsigned short pmo_q_info = 0; -unsigned short pmo_q_list = 0; -unsigned short pmo_q_orphans = 0; -unsigned short pmo_q_owns = 0; -unsigned short pmo_r_cascade = 0; -unsigned short pmo_s_upgrade = 0; -unsigned short pmo_s_downloadonly = 0; -unsigned short pmo_s_sync = 0; -unsigned short pmo_s_search = 0; -unsigned short pmo_s_clean = 0; -unsigned short pmo_group = 0; -/* configuration file options */ -char *pmo_dbpath = NULL; -char *pmo_logfile = NULL; -PMList *pmo_noupgrade = NULL; -PMList *pmo_ignorepkg = NULL; -unsigned short pmo_usesyslog = 0; -unsigned short pmo_nopassiveftp = 0; - - -/* list of sync_t structs for sync locations */ -PMList *pmc_syncs = NULL; -/* list of installed packages */ -PMList *pm_packages = NULL; -/* list of targets specified on command line */ -PMList *pm_targets = NULL; - -FILE *logfd = NULL; -char *lckfile = "/tmp/pacman.lck"; -char *workfile = NULL; -enum {READ_ONLY, READ_WRITE} pm_access; -int maxcols = 80; - -int main(int argc, char *argv[]) -{ - int ret = 0; - char *ptr = NULL; - char path[PATH_MAX]; - pacdb_t *db_local = NULL; - char *cenv = NULL; - - cenv = getenv("COLUMNS"); - if(cenv) { - maxcols = atoi(cenv); - } - - if(argc < 2) { - usage(PM_MAIN, (char*)basename(argv[0])); - return(0); - } - - /* default root */ - MALLOC(pmo_root, PATH_MAX); - strcpy(pmo_root, "/"); - /* default dbpath */ - MALLOC(pmo_dbpath, PATH_MAX); - strcpy(pmo_dbpath, PKGDIR); - - /* parse the command line */ - ret = parseargs(PM_ADD, argc, argv); - if(ret) { - FREE(pmo_root); - FREE(pmo_dbpath); - return(ret); - } - - /* check for permission */ - pm_access = READ_ONLY; - if(pmo_op != PM_MAIN && pmo_op != PM_QUERY && pmo_op != PM_DEPTEST) { - if(pmo_op == PM_SYNC && !pmo_s_sync && (pmo_s_search || pmo_group)) { - /* special case: PM_SYNC can be used w/ pmo_s_search by any user */ - } else { - if(geteuid() != 0) { - fprintf(stderr, "error: you cannot perform this operation unless you are root.\n"); - return(1); - } - pm_access = READ_WRITE; - /* lock */ - if(lckmk(lckfile, 1, 1) == -1) { - fprintf(stderr, "error: unable to lock pacman database.\n"); - fprintf(stderr, " if you're sure pacman is not already running, you\n"); - fprintf(stderr, " can remove %s\n", lckfile); - return(32); - } - } - } - - /* set signal handlers */ - signal(SIGINT, cleanup); - signal(SIGTERM, cleanup); - - /* parse the system-wide config file */ - snprintf(path, PATH_MAX, "/%s", PACCONF); - if(parseconfig(path)) { - cleanup(1); - } - - if(pmo_usesyslog) { - openlog("pacman", 0, LOG_USER); - } - if(pmo_logfile && geteuid() == 0) { - /* open the log file */ - logfd = fopen(pmo_logfile, "a"); - if(logfd == NULL) { - perror("warning: cannot open logfile"); - } - } - - /* check for db existence */ - /* add a trailing '/' if there isn't one */ - if(pmo_root[strlen(pmo_root)-1] != '/') { - MALLOC(ptr, strlen(pmo_root)+1); - strcpy(ptr, pmo_root); - strcat(ptr, "/"); - FREE(pmo_root); - pmo_root = ptr; - } - - vprint("Installation Root: %s\n", pmo_root); - /* db location */ - vprint("Top-level DB Path: %s%s\n", pmo_root, pmo_dbpath); - if(pmo_verbose) { - list_display("Targets:", pm_targets); - } - - db_local = db_open(pmo_root, pmo_dbpath, "local"); - if(db_local == NULL) { - /* couldn't open the db directory - try creating it */ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "%s%s/local", pmo_root, pmo_dbpath); - vprint("initializing database %s...\n", path); - ret = makepath(path); - - if(ret) { - fprintf(stderr, "error: could not create database.\n"); - cleanup(1); - } - if((db_local = db_open(pmo_root, pmo_dbpath, "local")) == NULL) { - fprintf(stderr, "error: could not open database.\n"); - cleanup(1); - } - } - - /* load pm_packages cache */ - pm_packages = db_loadpkgs(db_local); - - /* start the requested operation */ - switch(pmo_op) { - case PM_ADD: ret = pacman_add(db_local, pm_targets); break; - case PM_REMOVE: ret = pacman_remove(db_local, pm_targets); break; - case PM_UPGRADE: ret = pacman_upgrade(db_local, pm_targets); break; - case PM_QUERY: ret = pacman_query(db_local, pm_targets); break; - case PM_SYNC: ret = pacman_sync(db_local, pm_targets); break; - case PM_DEPTEST: ret = pacman_deptest(db_local, pm_targets); break; - case PM_MAIN: ret = 0; break; - default: fprintf(stderr, "error: no operation specified (use -h for help)\n\n"); - ret = 1; - } - db_close(db_local); - cleanup(ret); - /* not reached */ - return(0); -} - -int pacman_deptest(pacdb_t *db, PMList *targets) -{ - PMList *list = NULL; - PMList *lp, *deps; - pkginfo_t *dummy; - - if(pmo_d_vertest) { - if(targets && targets->data && targets->next && targets->next->data) { - int ret = rpmvercmp(targets->data, targets->next->data); - printf("%d\n", ret); - return(ret); - } - return(0); - } - - dummy = newpkg(); - sprintf(dummy->name, "_dummy_"); - sprintf(dummy->version, "1.0-1"); - for(lp = targets; lp; lp = lp->next) { - if(lp->data == NULL) continue; - dummy->depends = list_add(dummy->depends, lp->data); - } - list = list_add(list, dummy); - deps = checkdeps(db, PM_ADD, list); - FREELIST(list); - FREEPKG(dummy); - - if(deps) { - /* return 126 = deps were missing, but successfully resolved - * return 127 = deps were missing, and failed to resolve; OR - * = deps were missing, but no resolution was attempted; OR - * = unresolvable conflicts were found - */ - int ret = 126; - PMList *synctargs = NULL; - for(lp = deps; lp; lp = lp->next) { - depmissing_t *miss = (depmissing_t*)lp->data; - if(miss->type == CONFLICT) { - /* we can't auto-resolve conflicts */ - printf("conflict: %s\n", miss->depend.name); - ret = 127; - } else if(miss->type == DEPEND || miss->type == REQUIRED) { - if(!pmo_d_resolve) { - printf("requires: %s", miss->depend.name); - switch(miss->depend.mod) { - case DEP_EQ: printf("=%s", miss->depend.version); break; - case DEP_GE: printf(">=%s", miss->depend.version); break; - case DEP_LE: printf("<=%s", miss->depend.version); break; - } - printf("\n"); - } - synctargs = list_add(synctargs, strdup(miss->depend.name)); - } - FREE(miss); - lp->data = NULL; - } - FREE(deps); - /* attempt to resolve missing dependencies */ - /* TODO: handle version comparators (eg, glibc>=2.2.5) */ - if(ret == 126 && synctargs != NULL) { - if(!pmo_d_resolve || pacman_sync(db, synctargs)) { - /* error (or -D not used) */ - ret = 127; - } - } - FREELIST(synctargs); - return(ret); - } - return(0); -} - -int pacman_sync(pacdb_t *db, PMList *targets) -{ - int allgood = 1, confirm = 0; - PMList *i, *j, *k; - PMList *rmtargs = NULL; /* conflicting packages to remove */ - PMList *final = NULL; /* packages to upgrade */ - PMList *trail = NULL; /* a breadcrumb trail to avoid running in circles */ - PMList *databases = NULL; - - if(!list_count(pmc_syncs)) { - fprintf(stderr, "error: no usable package repositories configured.\n"); - return(1); - } - - if(pmo_s_clean) { - mode_t oldmask; - - printf("removing packages from cache... "); - if(rmrf("/var/cache/pacman/pkg")) { - fprintf(stderr, "error: could not remove cache directory: %s\n", strerror(errno)); - return(1); - } - - oldmask = umask(0000); - if(makepath("/var/cache/pacman/pkg")) { - fprintf(stderr, "error: could not create new cache directory: %s\n", strerror(errno)); - return(1); - } - umask(oldmask); - - printf("done.\n"); - return(0); - } - - if(pmo_s_sync) { - /* grab a fresh package list */ - printf(":: Synchronizing package databases... \n"); - logaction(NULL, "synchronizing package lists"); - sync_synctree(); - } - - /* open the database(s) */ - for(i = pmc_syncs; i; i = i->next) { - pacdb_t *db_sync = NULL; - dbsync_t *dbs = NULL; - sync_t *sync = (sync_t*)i->data; - - db_sync = db_open(pmo_root, pmo_dbpath, sync->treename); - if(db_sync == NULL) { - fprintf(stderr, "error: could not open sync database: %s\n", sync->treename); - fprintf(stderr, " have you used --refresh yet?\n"); - return(1); - } - MALLOC(dbs, sizeof(dbsync_t)); - dbs->sync = sync; - dbs->db = db_sync; - /* cache packages */ - dbs->pkgcache = db_loadpkgs(db_sync); - databases = list_add(databases, dbs); - } - - final = list_new(); - trail = list_new(); - - if(pmo_s_search) { - /* search sync databases */ - if(targets) { - for(i = targets; i; i = i->next) { - char *targ = strdup(i->data); - strtoupper(targ); - for(j = databases; j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - for(k = dbs->pkgcache; k; k = k->next) { - pkginfo_t *pkg = (pkginfo_t*)k->data; - char *haystack; - /* check name */ - haystack = strdup(pkg->name); - strtoupper(haystack); - if(strstr(haystack, targ)) { - printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version); - indentprint(pkg->desc, 4); - printf("\n"); - } else { - /* check description */ - FREE(haystack); - haystack = strdup(pkg->desc); - strtoupper(haystack); - if(strstr(haystack, targ)) { - printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version); - indentprint(pkg->desc, 4); - printf("\n"); - } - } - FREE(haystack); - } - } - FREE(targ); - } - } else { - for(j = databases; j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - for(k = dbs->pkgcache; k; k = k->next) { - pkginfo_t *pkg = (pkginfo_t*)k->data; - printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version); - indentprint(pkg->desc, 4); - printf("\n"); - } - } - } - } else if(pmo_group) { - PMList *pm, *allgroups, *groups; - i = NULL; - /* fetch the list of existing groups */ - for(j = databases; j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - k = find_groups(dbs->db); - for(pm = k; pm; pm = pm->next) { - if(!is_in((char *)pm->data, i)) { - i = list_add(i, strdup((char *)pm->data)); - } - } - FREELIST(k); - } - allgroups = list_sort(i); - FREELIST(i); - if(targets) { - groups = NULL; - for(j = targets; j; j = j->next) { - if(is_in((char *)j->data, allgroups)) { - groups = list_add(groups, strdup((char *)j->data)); - } - } - FREELIST(allgroups); - } else { - groups = allgroups; - } - /* display the packages belonging to groups */ - for(pm = groups; pm; pm = pm->next) { - PMList *pkg; - printf("%s\n", (char *)pm->data); - if(targets == NULL) { - continue; - } - i = NULL; - for(j = databases; j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - PMList *l = pkg_ingroup(dbs->db, (char *)pm->data); - i = list_merge(i, l); - FREELIST(l); - } - pkg = list_sort(i); - FREELIST(i); - list_display(" ", pkg); - FREELIST(pkg); - } - FREELIST(groups); - } else if(pmo_s_upgrade) { - int newer = 0; - int ignore = 0; - logaction(NULL, "starting full system upgrade"); - /* check for "recommended" package replacements */ - for(i = databases; i && allgood; i = i->next) { - dbsync_t *dbs = (dbsync_t*)i->data; - for(j = dbs->pkgcache; j; j = j->next) { - pkginfo_t *pkg = (pkginfo_t*)j->data; - for(k = pkg->replaces; k; k = k->next) { - PMList *m; - for(m = pm_packages; m; m = m->next) { - pkginfo_t *p = (pkginfo_t*)m->data; - if(!strcmp(k->data, p->name)) { - /* if confirmed, add this to the 'final' list, designating 'p' as - * the package to replace. - */ - if(yesno(":: replace %s with %s from \"%s\"? [Y/n] ", p->name, pkg->name, dbs->db->treename)) { - syncpkg_t *sync = NULL; - /* we save the dependency info so we can move p's requiredby stuff - * over to the replacing package - */ - pkginfo_t *q = db_scan(db, p->name, INFRQ_DESC | INFRQ_DEPENDS); - - /* check if pkg->name is already in the final list. */ - sync = find_pkginsync(pkg->name, final); - if(sync) { - /* found it -- just append to the replaces list */ - sync->replaces = list_add(sync->replaces, q); - } else { - /* none found -- enter pkg into the final sync list */ - MALLOC(sync, sizeof(syncpkg_t)); - sync->dbs = dbs; - sync->replaces = NULL; - sync->replaces = list_add(sync->replaces, q); - sync->pkg = db_scan(sync->dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); - /* add to the targets list */ - allgood = !resolvedeps(db, databases, sync, final, trail); - /* check again, as resolvedeps could have added our target for us */ - if(find_pkginsync(sync->pkg->name, final) == NULL) { - final = list_add(final, sync); - } - } - } - break; - } - } - } - } - } - /* match installed packages with the sync dbs and compare versions */ - for(i = pm_packages; i && allgood; i = i->next) { - int cmp, found = 0; - pkginfo_t *local = (pkginfo_t*)i->data; - syncpkg_t *sync = NULL; - MALLOC(sync, sizeof(syncpkg_t)); - sync->replaces = NULL; - - for(j = databases; !found && j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - for(k = dbs->pkgcache; !found && k; k = k->next) { - pkginfo_t *pkg = (pkginfo_t*)k->data; - if(!strcmp(local->name, pkg->name)) { - found = 1; - sync->pkg = pkg; - sync->dbs = dbs; - } - } - } - if(!found) { - /*fprintf(stderr, "%s: not found in sync db. skipping.", local->name);*/ - FREE(sync); - continue; - } - /* compare versions and see if we need to upgrade */ - cmp = rpmvercmp(local->version, sync->pkg->version); - if(cmp > 0) { - /* local version is newer */ - fprintf(stderr, ":: %s-%s: local version is newer\n", - local->name, local->version); - newer = 1; - FREE(sync); - continue; - } else if(cmp == 0) { - /* versions are identical */ - FREE(sync); - continue; - } else if(is_in((char*)i->data, pmo_ignorepkg)) { - /* package should be ignored (IgnorePkg) */ - fprintf(stderr, ":: %s-%s: ignoring package upgrade (%s)\n", - local->name, local->version, sync->pkg->version); - ignore = 1; - FREE(sync); - continue; - } - - /* re-fetch the package record with dependency info */ - sync->pkg = db_scan(sync->dbs->db, sync->pkg->name, INFRQ_DESC | INFRQ_DEPENDS); - - /* add to the targets list */ - found = (find_pkginsync(sync->pkg->name, final) != NULL); - if(!found) { - allgood = !resolvedeps(db, databases, sync, final, trail); - /* check again, as resolvedeps could have added our target for us */ - found = (find_pkginsync(sync->pkg->name, final) != NULL); - if(!found) { - final = list_add(final, sync); - } - } - } - if((newer || ignore) && allgood) { - fprintf(stderr, ":: Above packages will be skipped. To manually upgrade use 'pacman -S '\n"); - } - } else { - /* process targets */ - for(i = targets; i && allgood; i = i->next) { - if(i->data) { - int cmp, found = 0; - char *treename; - char *targ; - char *targline; - pkginfo_t *local; - syncpkg_t *sync = NULL; - MALLOC(sync, sizeof(syncpkg_t)); - sync->replaces = NULL; - - targline = strdup((char*)i->data); - targ = index(targline, '/'); - if(targ) { - *targ = '\0'; - targ++; - treename = targline; - } else { - targ = targline; - treename = NULL; - } - - for(j = databases; !found && j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - for(k = dbs->pkgcache; !found && k; k = k->next) { - pkginfo_t *pkg = (pkginfo_t*)k->data; - if(!strcmp(targ, pkg->name)) { - if(treename == NULL || - (treename && !strcmp(treename, dbs->sync->treename))) { - found = 1; - sync->dbs = dbs; - /* re-fetch the package record with dependency info */ - sync->pkg = db_scan(sync->dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); - if(sync->pkg == NULL) { - found = 0; - } - } - } - } - } - if(!found) { - if(treename == NULL) { - /* target not found: check if it's a group */ - k = NULL; - for(j = databases; j; j = j->next) { - dbsync_t *dbs = (dbsync_t*)j->data; - PMList *l = pkg_ingroup(dbs->db, targ); - k = list_merge(k, l); - FREELIST(l); - } - if(k != NULL) { - printf(":: group %s:\n", targ); - list_display(" ", k); - if(yesno(" Install whole content? [Y/n] ")) { - targets = list_merge(targets, k); - FREELIST(k); - } else { - PMList *l; - for(l = k; l; l = l->next) { - if(yesno(":: install %s from group %s? [Y/n] ", (char*)l->data, targ)) { - targets = list_add(targets, strdup((char*)l->data)); - } - } - } - FREELIST(k); - } else { - fprintf(stderr, "%s: not found in sync db\n", targ); - allgood = 0; - } - } else { - fprintf(stderr, "%s: not present in \"%s\" repository\n", targ, treename); - allgood = 0; - } - FREE(sync); - FREE(targline); - continue; - } - local = db_scan(db, targ, INFRQ_DESC); - if(local && !pmo_s_downloadonly) { - /* this is an upgrade, compare versions and determine if it is necessary */ - cmp = rpmvercmp(local->version, sync->pkg->version); - if(cmp > 0) { - /* local version is newer - get confirmation first */ - if(!yesno(":: %s-%s: local version is newer. Upgrade anyway? [Y/n] ", local->name, local->version)) { - FREEPKG(local); - FREEPKG(sync->pkg); - FREE(sync); - FREE(targline); - continue; - } - } else if(cmp == 0) { - /* versions are identical */ - if(!yesno(":: %s-%s: is up to date. Upgrade anyway? [Y/n] ", local->name, local->version)) { - FREEPKG(local); - FREEPKG(sync->pkg); - FREE(sync); - FREE(targline); - continue; - } - } - } - FREEPKG(local); - - found = (find_pkginsync(sync->pkg->name, final) != NULL); - if(!found && !pmo_nodeps) { - allgood = !resolvedeps(db, databases, sync, final, trail); - /* check again, as resolvedeps could have added our target for us */ - found = (find_pkginsync(sync->pkg->name, final) != NULL); - } - if(!found) { - final = list_add(final, sync); - } - } - } - } - - if(allgood && !pmo_s_search) { - /* check for inter-conflicts and whatnot */ - if(!pmo_nodeps && !pmo_s_downloadonly) { - int errorout = 0; - PMList *deps = NULL; - PMList *list = NULL; - - for(i = final; i; i = i->next) { - syncpkg_t *s = (syncpkg_t*)i->data; - if(s) { - list = list_add(list, s->pkg); - } - } - deps = checkdeps(db, PM_UPGRADE, list); - if(deps) { - for(i = deps; i; i = i->next) { - depmissing_t *miss = (depmissing_t*)i->data; - if(miss->type == DEPEND || miss->type == REQUIRED) { - if(!errorout) { - fprintf(stderr, "error: unresolvable dependencies:\n"); - errorout = 1; - } - fprintf(stderr, " %s: requires %s", miss->target, miss->depend.name); - switch(miss->depend.mod) { - case DEP_EQ: fprintf(stderr, "=%s", miss->depend.version); break; - case DEP_GE: fprintf(stderr, ">=%s", miss->depend.version); break; - case DEP_LE: fprintf(stderr, "<=%s", miss->depend.version); break; - } - if(miss->type == DEPEND) { - fprintf(stderr, " but it is not in the sync db\n"); - } else { - fprintf(stderr, "\n"); - } - } - } - if(!errorout) { - int found; - errorout = 0; - /* no unresolvable deps, so look for conflicts */ - for(i = deps; i && !errorout; i = i->next) { - depmissing_t *miss = (depmissing_t*)i->data; - if(miss->type == CONFLICT) { - /* check if the conflicting package is one that's about to be removed/replaced. - * if so, then just ignore it - */ - found = 0; - for(j = final; j && !found; j = j->next) { - syncpkg_t *sync = (syncpkg_t*)j->data; - for(k = sync->replaces; k && !found; k = k->next) { - pkginfo_t *p = (pkginfo_t*)k->data; - if(!strcmp(p->name, miss->depend.name)) { - found = 1; - } - } - } - /* if we didn't find it in any sync->replaces lists, then it's a conflict */ - if(!found && !is_in(miss->depend.name, rmtargs)) { - pkginfo_t p1; - /* build a "fake" pkginfo_t so we can search with is_pkgin() */ - snprintf(p1.name, sizeof(p1.name), miss->depend.name); - sprintf(p1.version, "1.0-1"); - - if(is_pkgin(&p1, pm_packages)) { - if(yesno(":: %s conflicts with %s. Remove %s? [Y/n] ", - miss->target, miss->depend.name, miss->depend.name)) { - /* remove miss->depend.name */ - rmtargs = list_add(rmtargs, strdup(miss->depend.name)); - } else { - /* abort */ - fprintf(stderr, "\nerror: package conflicts detected\n"); - errorout = 1; - } - } else { - if(!is_in(miss->depend.name, rmtargs) & !is_in(miss->target, rmtargs)) { - fprintf(stderr, "\nerror: %s conflicts with %s\n", miss->target, - miss->depend.name); - errorout = 1; - } - } - } - } - } - } - list_free(deps); - if(errorout) { - /* abort mission */ - allgood = 0; - } - } - /* cleanup */ - for(i = list; i; i = i->next) { - i->data = NULL; - } - FREELIST(list); - } - - /* any packages in rmtargs need to be removed from final. */ - /* rather than ripping out nodes from final, we just copy over */ - /* our "good" nodes to a new list and reassign. */ - k = NULL; - for(i = final; i; i = i->next) { - syncpkg_t *s = (syncpkg_t*)i->data; - int keepit = 1; - for(j = rmtargs; j && keepit; j = j->next) { - if(!strcmp(j->data, s->pkg->name)) { - FREE(i->data); - keepit = 0; - } - } - if(keepit) { - k = list_add(k, s); - } - i->data = NULL; - } - FREELIST(final); - final = k; - - /* list targets */ - if(final && final->data && allgood) { - PMList *list = NULL; - char *str; - for(i = rmtargs; i; i = i->next) { - list = list_add(list, strdup(i->data)); - } - for(i = final; i; i = i->next) { - syncpkg_t *s = (syncpkg_t*)i->data; - for(j = s->replaces; j; j = j->next) { - pkginfo_t *p = (pkginfo_t*)j->data; - list = list_add(list, strdup(p->name)); - } - } - if(list) { - printf("\nRemove: "); - str = buildstring(list); - indentprint(str, 9); - printf("\n"); - FREELIST(list); - FREE(str); - } - for(i = final; i; i = i->next) { - syncpkg_t *s = (syncpkg_t*)i->data; - if(s && s->pkg) { - char *str = NULL; - MALLOC(str, strlen(s->pkg->name)+strlen(s->pkg->version)+2); - sprintf(str, "%s-%s", s->pkg->name, s->pkg->version); - list = list_add(list, str); - } - } - printf("\nTargets: "); - str = buildstring(list); - indentprint(str, 9); - printf("\n"); - FREELIST(list); - FREE(str); - } - - /* get confirmation */ - confirm = 0; - if(allgood && final && final->data) { - if(pmo_s_downloadonly) { - confirm = yesno("\nProceed with download? [Y/n] "); - } else { - /* don't get any confirmation if we're called from makepkg */ - if(pmo_d_resolve) { - confirm = 1; - } else { - confirm = yesno("\nProceed with upgrade? [Y/n] "); - } - } - } - } - - if(allgood && confirm && final && final->data) { - char ldir[PATH_MAX]; - int varcache = 1; - int done = 0; - int count = 0; - sync_t *current = NULL; - PMList *processed = NULL; - PMList *files = NULL; - - snprintf(ldir, PATH_MAX, "%svar/cache/pacman/pkg", pmo_root); - - /* group sync records by repository and download */ - while(!done) { - if(current) { - processed = list_add(processed, current); - current = NULL; - } - for(i = final; i; i = i->next) { - syncpkg_t *sync = (syncpkg_t*)i->data; - if(current == NULL) { - /* we're starting on a new repository */ - if(!list_isin(processed, sync->dbs->sync)) { - current = sync->dbs->sync; - } - } - if(current && !strcmp(current->treename, sync->dbs->sync->treename)) { - struct stat buf; - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "%s/%s-%s.pkg.tar.gz", - ldir, sync->pkg->name, sync->pkg->version); - if(stat(path, &buf)) { - /* file is not in the cache dir, so add it to the list */ - snprintf(path, PATH_MAX, "%s-%s.pkg.tar.gz", sync->pkg->name, sync->pkg->version); - files = list_add(files, strdup(path)); - } else { - vprint(" %s-%s.pkg.tar.gz is already in the cache\n", sync->pkg->name, sync->pkg->version); - count++; - } - } - } - - if(files) { - struct stat buf; - - printf("\n:: Retrieving packages from %s...\n", current->treename); - fflush(stdout); - if(stat(ldir, &buf)) { - mode_t oldmask; - char parent[PATH_MAX]; - - /* no cache directory.... try creating it */ - snprintf(parent, PATH_MAX, "%svar/cache/pacman", pmo_root); - logaction(stderr, "warning: no %s cache exists. creating...", ldir); - oldmask = umask(0000); - mkdir(parent, 0755); - if(mkdir(ldir, 0755)) { - /* couldn't mkdir the cache directory, so fall back to /tmp and unlink - * the package afterwards. - */ - logaction(stderr, "warning: couldn't create package cache, using /tmp instead"); - snprintf(ldir, PATH_MAX, "/tmp"); - varcache = 0; - } - umask(oldmask); - } - if(downloadfiles(current->servers, ldir, files)) { - fprintf(stderr, "error: failed to retrieve some files from %s\n", current->treename); - allgood = 0; - } - count += list_count(files); - FREELIST(files); - } - if(count == list_count(final)) { - done = 1; - } - } - printf("\n"); - - /* double-check */ - FREELIST(files); - - if(allgood) { - /* Check integrity of files */ - printf("checking package integrity... "); - fflush(stdout); - - for(i = final; i; i = i->next) { - syncpkg_t *sync; - char str[PATH_MAX], pkgname[PATH_MAX]; - char *md5sum1, *md5sum2; - - sync = (syncpkg_t*)i->data; - snprintf(pkgname, PATH_MAX, "%s-%s.pkg.tar.gz", sync->pkg->name, sync->pkg->version); - - md5sum1 = sync->pkg->md5sum; - if(md5sum1 == NULL || md5sum1[0] == '\0') { - if(allgood) { - printf("\n"); - } - fprintf(stderr, "error: can't get md5 checksum for package %s\n", pkgname); - allgood = 0; - continue; - } - snprintf(str, PATH_MAX, "%s/%s", ldir, pkgname); - md5sum2 = MDFile(str); - if(md5sum2 == NULL || md5sum2[0] == '\0') { - if(allgood) { - printf("\n"); - } - fprintf(stderr, "error: can't get md5 checksum for archive %s\n", pkgname); - allgood = 0; - continue; - } - - if(strcmp(md5sum1, md5sum2) != 0) { - if(allgood) { - printf("\n"); - } - fprintf(stderr, "error: archive %s is corrupted\n", pkgname); - allgood = 0; - } - - FREE(md5sum2); - } - if(allgood) { - printf("done.\n"); - } else { - fprintf(stderr, "\n"); - } - } - - if(!pmo_s_downloadonly && allgood) { - /* remove any conflicting packages (WITH dep checks) */ - if(rmtargs) { - int retcode; - retcode = pacman_remove(db, rmtargs); - FREELIST(rmtargs); - if(retcode == 1) { - fprintf(stderr, "\nupgrade aborted.\n"); - allgood = 0; - } - /* reload package cache */ - FREELISTPKGS(pm_packages); - pm_packages = db_loadpkgs(db); - } - FREELIST(rmtargs); - for(i = final; allgood && i; i = i->next) { - char *str; - syncpkg_t *sync = (syncpkg_t*)i->data; - if(sync->pkg) { - MALLOC(str, PATH_MAX); - snprintf(str, PATH_MAX, "%s/%s-%s.pkg.tar.gz", ldir, sync->pkg->name, sync->pkg->version); - files = list_add(files, str); - } - for(j = sync->replaces; j; j = j->next) { - pkginfo_t *pkg = (pkginfo_t*)j->data; - rmtargs = list_add(rmtargs, strdup(pkg->name)); - } - } - /* remove to-be-replaced packages */ - if(allgood && rmtargs) { - int oldval = pmo_nodeps; - /* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */ - pmo_nodeps = 1; - allgood = !pacman_remove(db, rmtargs); - pmo_nodeps = oldval; - if(!allgood) { - fprintf(stderr, "package removal failed. aborting...\n"); - } - } - /* install targets */ - if(allgood) { - allgood = !pacman_upgrade(db, files); - } - /* propagate replaced packages' requiredby fields to their new owners */ - 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_ALL); - for(j = sync->replaces; j; j = j->next) { - pkginfo_t *old = (pkginfo_t*)j->data; - /* merge lists */ - for(k = old->requiredby; k; k = k->next) { - if(!is_in(k->data, new->requiredby)) { - /* replace old's name with new's name in the requiredby's dependency list */ - PMList *m; - pkginfo_t *depender = db_scan(db, k->data, INFRQ_ALL); - for(m = depender->depends; m; m = m->next) { - if(!strcmp(m->data, old->name)) { - FREE(m->data); - m->data = strdup(new->name); - } - } - db_write(db, depender); - - /* add the new requiredby */ - new->requiredby = list_add(new->requiredby, strdup(k->data)); - } - } - } - db_write(db, new); - FREEPKG(new); - } - } - } - } - - if(!varcache && !pmo_s_downloadonly && allgood) { - /* delete packages */ - for(i = files; i; i = i->next) { - unlink(i->data); - } - } - } - - /* cleanup */ - for(i = final; i; i = i->next) { - syncpkg_t *sync = (syncpkg_t*)i->data; - if(sync) { - FREEPKG(sync->pkg); - FREELISTPKGS(sync->replaces); - } - FREE(sync); - i->data = NULL; - } - for(i = trail; i; i = i->next) { - /* this list used the same pointers as final, so they're already freed */ - i->data = NULL; - } - for(i = databases; i; i = i->next) { - dbsync_t *dbs = (dbsync_t*)i->data; - db_close(dbs->db); - dbs->db = NULL; - FREELISTPKGS(dbs->pkgcache); - FREE(dbs); - i->data = NULL; - } - FREELIST(databases); - FREELIST(final); - FREELIST(trail); - FREELIST(rmtargs); - return(!allgood); -} - -int pacman_add(pacdb_t *db, PMList *targets) -{ - int i, ret = 0, errors = 0; - TAR *tar = NULL; - char expath[PATH_MAX]; - char pm_install[PATH_MAX]; - pkginfo_t *info = NULL; - struct stat buf; - PMList *targ, *file, *lp, *j, *k; - PMList *alltargs = NULL; - PMList *filenames = NULL; - unsigned short real_pmo_upgrade; - tartype_t gztype = { - (openfunc_t) gzopen_frontend, - (closefunc_t)gzclose, - (readfunc_t) gzread, - (writefunc_t)gzwrite - }; - - if(targets == NULL) { - return(0); - } - - printf("loading package data... "); - fflush(stdout); - for(targ = targets; targ; targ = targ->next) { - /* Populate the package struct */ - vprint("reading %s... ", (char*)targ->data); - info = load_pkg((char*)targ->data, 0); - if(info == NULL) { - return(1); - } - if(pmo_freshen) { - /* only upgrade/install this package if it is already installed and at a lesser version */ - pkginfo_t *dummy = db_scan(db, info->name, INFRQ_DESC); - if(dummy == NULL || rpmvercmp(dummy->version, info->version) >= 0) { - vprint("not installed or lesser version\n"); - FREEPKG(info); - FREEPKG(dummy); - continue; - } - FREEPKG(dummy); - } - /* check if an older version of said package is already in alltargs. - * if so, replace it in the list */ - for(j = alltargs, k = filenames; j && j->data && k; j = j->next, k = k->next) { - pkginfo_t *pkg = (pkginfo_t*)j->data; - if(!strcmp(pkg->name, info->name)) { - if(rpmvercmp(pkg->version, info->version) < 0) { - vprint("replacing older version in target list. "); - FREEPKG(j->data); - j->data = info; - FREE(k->data); - k->data = strdup(targ->data); - } - } - } - vprint("done\n"); - alltargs = list_add(alltargs, info); - filenames = list_add(filenames, strdup(targ->data)); - } - printf("done.\n"); - - /* No need to check deps if pacman_add was called during a sync: - * it is already done in pacman_sync. */ - if(!pmo_nodeps && pmo_op != PM_SYNC) { - int errorout = 0; - vprint("checking dependencies...\n"); - lp = checkdeps(db, (pmo_upgrade ? PM_UPGRADE : PM_ADD), alltargs); - if(lp) { - /* look for unsatisfied dependencies */ - for(j = lp; j; j = j->next) { - depmissing_t* miss = (depmissing_t*)j->data; - if(miss->type == DEPEND || miss->type == REQUIRED) { - if(!errorout) { - fprintf(stderr, "error: unsatisfied dependencies:\n"); - errorout = 1; - } - printf(" %s: requires %s", miss->target, miss->depend.name); - switch(miss->depend.mod) { - case DEP_EQ: printf("=%s", miss->depend.version); break; - case DEP_GE: printf(">=%s", miss->depend.version); break; - case DEP_LE: printf("<=%s", miss->depend.version); break; - } - printf("\n"); - } - } - if(!errorout) { - PMList *rmtargs = NULL; - errorout = 0; - /* no unsatisfied deps, so look for conflicts */ - for(j = lp; j && !errorout; j = j->next) { - depmissing_t* miss = (depmissing_t*)j->data; - if(miss->type == CONFLICT && !is_in(miss->depend.name, rmtargs)) { - pkginfo_t p1; - /* build a "fake" pkginfo_t so we can search with is_pkgin() */ - snprintf(p1.name, sizeof(p1.name), miss->depend.name); - sprintf(p1.version, "1.0-1"); - - if(is_pkgin(&p1, pm_packages)) { - if(yesno(":: %s conflicts with %s. Remove %s? [Y/n] ", - miss->target, miss->depend.name, miss->depend.name)) { - /* remove miss->depend.name */ - rmtargs = list_add(rmtargs, strdup(miss->depend.name)); - } else { - /* abort */ - fprintf(stderr, "\nerror: package conflicts detected\n"); - errorout = 1; - } - } else { - if(!is_in(miss->depend.name, rmtargs) & !is_in(miss->target, rmtargs)) { - fprintf(stderr, "\nerror: %s conflicts with %s\n", miss->target, - miss->depend.name); - errorout = 1; - } - } - } - } - if(rmtargs && !errorout) { - int retcode; - int oldupg = pmo_upgrade; - /* any packages in rmtargs need to be removed from alltargs. */ - /* rather than ripping out nodes from alltargs, we just copy over */ - /* our "good" nodes to a new list and reassign. */ - k = NULL; - for(lp = alltargs; lp; lp = lp->next) { - pkginfo_t *p = (pkginfo_t*)lp->data; - int keepit = 1; - for(j = rmtargs; j && keepit; j = j->next) { - if(!strcmp(j->data, p->name)) { - /* gone! */ - FREE(lp->data); - keepit = 0; - } - } - if(keepit) { - k = list_add(k, p); - } - lp->data = NULL; - } - FREELIST(alltargs); - alltargs = k; - /* make sure pacman_remove does it's own dependency check */ - pmo_upgrade = 0; - retcode = pacman_remove(db, rmtargs); - list_free(rmtargs); - if(retcode == 1) { - fprintf(stderr, "\n%s aborted.\n", oldupg ? "upgrade" : "install"); - return(1); - } - /* reload package cache */ - FREELISTPKGS(pm_packages); - pm_packages = db_loadpkgs(db); - pmo_upgrade = oldupg; - } - } - if(errorout) { - FREELIST(lp); - return(1); - } - list_free(lp); - } - - /* re-order w.r.t. dependencies */ - vprint("sorting by dependencies\n"); - lp = sortbydeps(alltargs); - /* free the old alltargs */ - for(j = alltargs; j; j = j->next) { - j->data = NULL; - } - FREELIST(alltargs); - alltargs = lp; - } - - if(!pmo_force) { - printf("checking for file conflicts... "); - fflush(stdout); - lp = db_find_conflicts(db, alltargs, pmo_root); - if(lp) { - printf("\nerror: the following file conflicts were found:\n"); - for(j = lp; j; j = j->next) { - printf(" %s\n", (char*)j->data); - } - printf("\n"); - FREELIST(lp); - return(1); - } - printf("done.\n"); - FREELIST(lp); - } - - /* this can get modified in the next for loop, so we reset it on each iteration */ - real_pmo_upgrade = pmo_upgrade; - - for(targ = alltargs, file = filenames; targ && file; targ = targ->next, file = file->next) { - pkginfo_t* oldpkg = NULL; - info = (pkginfo_t*)targ->data; - errors = 0; - - pmo_upgrade = real_pmo_upgrade; - /* check for an already installed package */ - if(!pmo_upgrade && is_pkgin(info, pm_packages)) { - fprintf(stderr, "error: %s is already installed. (try --upgrade)\n", info->name); - continue; - } - - /* see if this is an upgrade. if so, remove the old package first */ - if(pmo_upgrade) { - if(is_pkgin(info, pm_packages)) { - PMList* tmp = list_new(); - int retcode; - - printf("upgrading %s... ", info->name); - /* we'll need the full record for backup checks later */ - oldpkg = db_scan(db, info->name, INFRQ_ALL); - - if(oldpkg) { - list_add(tmp, strdup(info->name)); - vprint("removing old package first...\n"); - retcode = pacman_remove(db, tmp); - list_free(tmp); - if(retcode == 1) { - fprintf(stderr, "\nupgrade aborted.\n"); - return(1); - } - /* reload package cache */ - FREELISTPKGS(pm_packages); - pm_packages = db_loadpkgs(db); - } - } else { - /* no previous package version is installed, so this is actually just an - * install - */ - pmo_upgrade = 0; - } - } - if(!pmo_upgrade) { - printf("installing %s... ", info->name); - } - fflush(stdout); - - /* open the .tar.gz package */ - if(tar_open(&tar, (char*)file->data, &gztype, O_RDONLY, 0, TAR_GNU) == -1) { - perror("could not open package"); - return(1); - } - vprint("extracting files...\n"); - for(i = 0; !th_read(tar); i++) { - int nb = 0; - int notouch = 0; - char *md5_orig = NULL; - char pathname[PATH_MAX]; - strncpy(pathname, th_get_pathname(tar), PATH_MAX); - - if(!strcmp(pathname, ".PKGINFO") || !strcmp(pathname, ".FILELIST")) { - tar_skip_regfile(tar); - continue; - } - - if(!strcmp(pathname, "._install") || !strcmp(pathname, ".INSTALL")) { - /* the install script goes inside the db */ - snprintf(expath, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, - pmo_dbpath, db->treename, info->name, info->version); - } else { - /* build the new pathname relative to pmo_root */ - snprintf(expath, PATH_MAX, "%s%s", pmo_root, pathname); - } - - if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) { - /* file already exists */ - if(is_in(pathname, pmo_noupgrade)) { - notouch = 1; - } else { - if(!pmo_upgrade || oldpkg == NULL) { - nb = is_in(pathname, info->backup); - } else { - /* op == PM_UPGRADE */ - md5_orig = needbackup(pathname, oldpkg->backup); - if(md5_orig) { - nb = 1; - } - } - } - } - - if(nb) { - char *temp; - char *md5_local, *md5_pkg; - - md5_local = MDFile(expath); - /* extract the package's version to a temporary file and md5 it */ - temp = strdup("/tmp/pacman_XXXXXX"); - mkstemp(temp); - if(tar_extract_file(tar, temp)) { - logaction(stderr, "could not extract %s: %s", pathname, strerror(errno)); - errors++; - continue; - } - md5_pkg = MDFile(temp); - /* append the new md5 hash to it's respective entry in info->backup - * (it will be the new orginal) - */ - for(lp = info->backup; lp; lp = lp->next) { - char *fn; - - if(!lp->data) continue; - if(!strcmp((char*)lp->data, pathname)) { - /* 32 for the hash, 1 for the terminating NULL, and 1 for the tab delimiter */ - MALLOC(fn, strlen(lp->data)+34); - sprintf(fn, "%s\t%s", (char*)lp->data, md5_pkg); - FREE(lp->data); - lp->data = fn; - } - } - - vprint("checking md5 hashes for %s\n", expath); - vprint(" current: %s\n", md5_local); - vprint(" new: %s\n", md5_pkg); - if(md5_orig) { - vprint(" original: %s\n", md5_orig); - } - - if(!pmo_upgrade) { - /* PM_ADD */ - - /* if a file already exists with a different md5 hash, - * then we rename it to a .pacorig extension and continue */ - if(strcmp(md5_local, md5_pkg)) { - char newpath[PATH_MAX]; - snprintf(newpath, PATH_MAX, "%s.pacorig", expath); - if(rename(expath, newpath)) { - logaction(stderr, "error: could not rename %s: %s", expath, strerror(errno)); - } - if(copyfile(temp, expath)) { - logaction(stderr, "error: could not copy %s to %s: %s", temp, expath, strerror(errno)); - errors++; - } else { - logaction(stderr, "warning: %s saved as %s", expath, newpath); - } - } - } else if(md5_orig) { - /* PM_UPGRADE */ - int installnew = 0; - - /* the fun part */ - if(!strcmp(md5_orig, md5_local)) { - if(!strcmp(md5_local, md5_pkg)) { - vprint(" action: installing new file\n"); - installnew = 1; - } else { - vprint(" action: installing new file\n"); - installnew = 1; - } - } else if(!strcmp(md5_orig, md5_pkg)) { - vprint(" action: leaving existing file in place\n"); - } else if(!strcmp(md5_local, md5_pkg)) { - vprint(" action: installing new file\n"); - installnew = 1; - } else { - char newpath[PATH_MAX]; - vprint(" action: saving current file and installing new one\n"); - installnew = 1; - snprintf(newpath, PATH_MAX, "%s.pacsave", expath); - if(rename(expath, newpath)) { - logaction(stderr, "error: could not rename %s: %s", expath, strerror(errno)); - } else { - logaction(stderr, "warning: %s saved as %s", expath, newpath); - } - } - - if(installnew) { - /*vprint(" %s\n", expath);*/ - if(copyfile(temp, expath)) { - fprintf(stderr, "error: could not copy %s to %s: %s\n", temp, expath, strerror(errno)); - errors++; - } - } - } - - FREE(md5_local); - FREE(md5_pkg); - FREE(md5_orig); - unlink(temp); - FREE(temp); - } else { - if(!notouch) { - /*vprint(" %s\n", expath);*/ - } else { - 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(tar_extract_file(tar, expath)) { - logaction(stderr, "could not extract %s: %s", pathname, strerror(errno)); - errors++; - } - /* calculate an md5 hash if this is in info->backup */ - for(lp = info->backup; lp; lp = lp->next) { - char *fn, *md5; - char path[PATH_MAX]; - - if(!lp->data) continue; - if(!strcmp((char*)lp->data, pathname)) { - snprintf(path, PATH_MAX, "%s%s", pmo_root, (char*)lp->data); - md5 = MDFile(path); - /* 32 for the hash, 1 for the terminating NULL, and 1 for the tab delimiter */ - MALLOC(fn, strlen(lp->data)+34); - sprintf(fn, "%s\t%s", (char*)lp->data, md5); - free(lp->data); - lp->data = fn; - } - } - } - } - tar_close(tar); - if(errors) { - ret = 1; - logaction(stderr, "errors occurred while %s %s", - (pmo_upgrade ? "upgrading" : "installing"), info->name); - -/* XXX: this "else" is disabled so the db_write() ALWAYS occurs. If it doesn't - * packages can get lost during an upgrade. - */ - } /*else*/ { - time_t t = time(NULL); - - /* Update the requiredby field by scaning the whole database - * looking for packages depending on the package to add */ - for(lp = pm_packages; lp; lp = lp->next) { - pkginfo_t *tmpp = NULL; - PMList *tmppm = NULL; - - tmpp = db_scan(db, ((pkginfo_t*)lp->data)->name, INFRQ_DEPENDS); - if(tmpp == NULL) { - continue; - } - for(tmppm = tmpp->depends; tmppm; tmppm = tmppm->next) { - depend_t depend; - if(splitdep(tmppm->data, &depend)) { - continue; - } - if(tmppm->data && !strcmp(depend.name, info->name)) { - info->requiredby = list_add(info->requiredby, strdup(tmpp->name)); - continue; - } - } - } - - vprint("Updating database..."); - /* make an install date (in UTC) */ - strncpy(info->installdate, asctime(gmtime(&t)), sizeof(info->installdate)); - if(db_write(db, info)) { - logaction(stderr, "error updating database for %s!", info->name); - return(1); - } - vprint("done.\n"); - if(pmo_upgrade && oldpkg) { - logaction(NULL, "upgraded %s (%s -> %s)", info->name, - oldpkg->version, info->version); - } else { - logaction(NULL, "installed %s (%s)", info->name, info->version); - } - - /* update dependency packages' REQUIREDBY fields */ - for(lp = info->depends; lp; lp = lp->next) { - pkginfo_t *depinfo = NULL; - depend_t depend; - - if(splitdep(lp->data, &depend)) { - continue; - } - depinfo = db_scan(db, depend.name, INFRQ_ALL); - if(depinfo == NULL) { - /* look for a provides package */ - PMList *provides = whatprovides(db, depend.name); - if(provides) { - /* use the first one */ - depinfo = db_scan(db, provides->data, INFRQ_ALL); - if(depinfo == NULL) { - /* wtf */ - continue; - } - } else { - continue; - } - } - depinfo->requiredby = list_add(depinfo->requiredby, strdup(info->name)); - db_write(db, depinfo); - freepkg(depinfo); - } - printf("done.\n"); fflush(stdout); - - /* run the post-install script if it exists */ - snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, pmo_dbpath, db->treename, info->name, info->version); - if(!stat(pm_install, &buf)) { - char cmdline[PATH_MAX+1]; - snprintf(pm_install, PATH_MAX, "%s/%s/%s-%s/install", pmo_dbpath, db->treename, info->name, info->version); - vprint("Executing post-install script...\n"); - snprintf(cmdline, PATH_MAX, "chroot %s /bin/sh %s post_%s %s %s", pmo_root, pm_install, - (pmo_upgrade ? "upgrade" : "install"), info->version, ((pmo_upgrade && oldpkg) ? oldpkg->version : "")); - system(cmdline); - } - } - - freepkg(oldpkg); - } - - /* clean up */ - for(lp = alltargs; lp; lp = lp->next) { - FREEPKG(lp->data); - } - FREELIST(alltargs); - FREELIST(filenames); - - /* run ldconfig if it exists */ - snprintf(expath, PATH_MAX, "%setc/ld.so.conf", pmo_root); - if(!stat(expath, &buf)) { - snprintf(expath, PATH_MAX, "%ssbin/ldconfig", pmo_root); - if(!stat(expath, &buf)) { - char cmd[PATH_MAX]; - snprintf(cmd, PATH_MAX, "%s -r %s", expath, pmo_root); - vprint("running \"%s\"\n", cmd); - system(cmd); - } - } - - return(ret); -} - -int pacman_remove(pacdb_t *db, PMList *targets) -{ - char line[PATH_MAX+1]; - char pm_install[PATH_MAX+1]; - pkginfo_t *info = NULL; - pkginfo_t *depinfo = NULL; - struct stat buf; - char *newpath = NULL; - depend_t depend; - PMList *alltargs = NULL; - PMList *targ, *lp, *j; - - if(targets == NULL) { - return(0); - } - - /* load package info from all targets */ - for(lp = targets; lp; lp = lp->next) { - info = db_scan(db, (char*)lp->data, INFRQ_ALL); - if(info == NULL) { - PMList *groups; - /* if the target is a group, ask if its packages should be removed */ - groups = find_groups(db); - if(is_in((char *)lp->data, groups)) { - PMList *pkgs = pkg_ingroup(db, (char *)lp->data); - printf(":: group %s:\n", (char*)lp->data); - list_display(" ", pkgs); - if(yesno(" Remove whole content? [Y/n] ")) { - for(j = pkgs; j; j = j->next) { - info = db_scan(db, (char *)j->data, INFRQ_ALL); - alltargs = list_add(alltargs, info); - } - } else { - for(j = pkgs; j; j = j->next) { - if(yesno(":: remove %s from group %s? [Y/n] ", (char*)j->data, (char*)lp->data)) { - info = db_scan(db, (char *)j->data, INFRQ_ALL); - alltargs = list_add(alltargs, info); - } - } - } - FREELIST(pkgs); - FREELIST(groups); - continue; - } - FREELIST(groups); - fprintf(stderr, "error: could not find %s in database\n", (char*)lp->data); - return(1); - } - alltargs = list_add(alltargs, info); - } - if(!pmo_nodeps && !pmo_upgrade) { - vprint("checking dependencies...\n"); - lp = checkdeps(db, PM_REMOVE, alltargs); - if(lp) { - if(pmo_r_cascade) { - while(lp) { - for(j = lp; j; j = j->next) { - depmissing_t* miss = (depmissing_t*)j->data; - info = db_scan(db, miss->depend.name, INFRQ_ALL); - if(!is_pkgin(info, alltargs)) { - list_add(alltargs, info); - } - } - list_free(lp); - lp = checkdeps(db, PM_REMOVE, alltargs); - } - /* list targets */ - list_display("\nTargets:", alltargs); - /* get confirmation */ - if(yesno("\nDo you want to remove these packages? [Y/n] ") == 0) { - list_free(alltargs); - list_free(lp); - return(1); - } - } else { - fprintf(stderr, "error: this will break the following dependencies:\n"); - for(j = lp; j; j = j->next) { - depmissing_t* miss = (depmissing_t*)j->data; - printf(" %s: is required by %s\n", miss->target, miss->depend.name); - } - list_free(alltargs); - list_free(lp); - return(1); - } - } - list_free(lp); - } - - for(targ = alltargs; targ; targ = targ->next) { - info = (pkginfo_t*)targ->data; - - if(!pmo_upgrade) { - printf("removing %s... ", info->name); - fflush(stdout); - /* run the pre-remove script if it exists */ - snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, pmo_dbpath, db->treename, info->name, info->version); - if(!stat(pm_install, &buf)) { - vprint("Executing pre-remove script...\n"); - snprintf(pm_install, PATH_MAX, "%s/%s/%s-%s/install", pmo_dbpath, db->treename, info->name, info->version); - snprintf(line, PATH_MAX, "chroot %s /bin/sh %s pre_remove %s", pmo_root, pm_install, info->version); - - system(line); - } - } - - /* 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)) { - nb = 1; - } - if(!nb && pmo_upgrade) { - /* check pmo_noupgrade */ - if(is_in((char*)lp->data, pmo_noupgrade)) { - nb = 1; - } - } - snprintf(line, PATH_MAX, "%s%s", pmo_root, (char*)lp->data); - if(lstat(line, &buf)) { - vprint("file %s does not exist\n", line); - continue; - } - if(S_ISDIR(buf.st_mode)) { - /*vprint(" removing directory %s\n", line);*/ - if(rmdir(line)) { - /* 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); - } 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"); - } - } - } - } - - /* 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); - - /* update dependency packages' REQUIREDBY fields */ - for(lp = info->depends; lp; lp = lp->next) { - PMList *last, *j; - - if(splitdep((char*)lp->data, &depend)) { - continue; - } - depinfo = db_scan(db, depend.name, INFRQ_ALL); - if(depinfo == NULL) { - /* look for a provides package */ - PMList *provides = whatprovides(db, depend.name); - if(provides) { - /* TODO: should check _all_ packages listed in provides, not just - * the first one. - */ - /* use the first one */ - depinfo = db_scan(db, provides->data, INFRQ_ALL); - list_free(provides); - if(depinfo == NULL) { - /* wtf */ - continue; - } - } else { - list_free(provides); - continue; - } - } - /* splice out this entry from requiredby */ - last = list_last(depinfo->requiredby); - for(j = depinfo->requiredby; j; j = j->next) { - if(!strcmp((char*)j->data, info->name)) { - if(j == depinfo->requiredby) { - depinfo->requiredby = j->next; - } - if(j->prev) j->prev->next = j->next; - if(j->next) j->next->prev = j->prev; - /* free the spliced node */ - j->prev = j->next = NULL; - list_free(j); - break; - } - } - db_write(db, depinfo); - freepkg(depinfo); - } - if(!pmo_upgrade) { - printf("done.\n"); - logaction(NULL, "removed %s (%s)", info->name, info->version); - } - } - - FREELIST(alltargs); - - /* run ldconfig if it exists */ - snprintf(line, PATH_MAX, "%setc/ld.so.conf", pmo_root); - if(!stat(line, &buf)) { - snprintf(line, PATH_MAX, "%ssbin/ldconfig", pmo_root); - if(!stat(line, &buf)) { - char cmd[PATH_MAX]; - snprintf(cmd, PATH_MAX, "%s -r %s", line, pmo_root); - vprint("running \"%s\"\n", cmd); - system(cmd); - } - } - - return(0); -} - -int pacman_query(pacdb_t *db, PMList *targets) -{ - char *package = NULL; - char path[PATH_MAX+1]; - pkginfo_t *info = NULL; - PMList *targ, *lp, *q; - int done = 0; - - for(targ = targets; !done; targ = (targ ? targ->next : NULL)) { - if(targets == NULL) { - done = 1; - } else { - if(targ->next == NULL) { - done = 1; - } - package = (char*)targ->data; - } - - /* looking for groups */ - if(pmo_group) { - PMList *pkg, *groups; - groups = find_groups(db); - if(package == NULL) { - for(lp = groups; lp; lp = lp->next) { - pkg = pkg_ingroup(db, (char *)lp->data); - for(q = pkg; q; q = q->next) { - printf("%s %s\n", (char *)lp->data, (char *)q->data); - } - FREELIST(pkg); - } - } else { - if(!is_in(package, groups)) { - fprintf(stderr, "Group \"%s\" was not found.\n", package); - FREELIST(groups); - return(2); - } - pkg = pkg_ingroup(db, package); - for(q = pkg; q; q = q->next) { - printf("%s %s\n", package, (char *)q->data); - } - FREELIST(pkg); - } - FREELIST(groups); - continue; - } - - /* output info for a .tar.gz package */ - if(pmo_q_isfile) { - if(package == NULL) { - fprintf(stderr, "error: no package file was specified for --file\n"); - return(1); - } - info = load_pkg(package, pmo_q_info); - if(info == NULL) { - fprintf(stderr, "error: %s is not a package\n", package); - return(1); - } - if(pmo_q_info) { - printf("\n"); - } else if(pmo_q_list) { - for(lp = info->files; lp; lp = lp->next) { - printf("%s %s\n", info->name, (char*)lp->data); - } - } else { - printf("%s %s\n", info->name, info->version); - } - FREEPKG(info); - continue; - } - - /* determine the owner of a file */ - if(pmo_q_owns) { - char rpath[PATH_MAX]; - if(package == NULL) { - fprintf(stderr, "error: no file was specified for --owns\n"); - return(1); - } - if(realpath(package, rpath)) { - int gotcha = 0; - rewinddir(db->dir); - while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL && !gotcha) { - for(lp = info->files; lp && !gotcha; lp = lp->next) { - sprintf(path, "%s%s", pmo_root, (char*)lp->data); - if(!strcmp(path, rpath)) { - printf("%s is owned by %s %s\n", package, info->name, info->version); - gotcha = 1; - } - } - FREEPKG(info); - } - if(!gotcha) { - fprintf(stderr, "No package owns %s\n", package); - } - continue; - } else { - fprintf(stderr, "error: %s is not a file.\n", package); - return(1); - } - } - - /* find packages in the db */ - if(package == NULL) { - /* no target */ - for(lp = pm_packages; lp; lp = lp->next) { - pkginfo_t *tmpp = (pkginfo_t*)lp->data; - if(pmo_q_list) { - info = db_scan(db, tmpp->name, INFRQ_DESC | INFRQ_FILES); - if(info == NULL) { - /* something weird happened */ - return(1); - } - for(q = info->files; q; q = q->next) { - printf("%s %s%s\n", info->name, pmo_root, (char*)q->data); - } - FREEPKG(info); - } else if(pmo_q_orphans) { - info = db_scan(db, tmpp->name, INFRQ_DESC | INFRQ_DEPENDS); - if(info == NULL) { - return(1); - } - if(info->requiredby == NULL) { - printf("%s %s\n", tmpp->name, tmpp->version); - } - FREEPKG(info); - } else { - printf("%s %s\n", tmpp->name, tmpp->version); - } - } - } else { - /* find a target */ - if(pmo_q_info) { - info = db_scan(db, package, INFRQ_ALL); - if(info == NULL) { - fprintf(stderr, "Package \"%s\" was not found.\n", package); - return(2); - } - dump_pkg(info); - if(pmo_q_info > 1 && info->backup) { - /* extra info */ - printf("\n"); - for(lp = info->backup; lp; lp = lp->next) { - struct stat buf; - char path[PATH_MAX]; - char *md5sum; - char *str = strdup(lp->data); - char *ptr = index(str, '\t'); - if(ptr == NULL) { - FREE(str); - continue; - } - *ptr = '\0'; - ptr++; - snprintf(path, PATH_MAX-1, "%s%s", pmo_root, str); - if(!stat(path, &buf)) { - md5sum = MDFile(path); - if(md5sum == NULL) { - fprintf(stderr, "error calculating md5sum for %s\n", path); - continue; - } - if(strcmp(md5sum, ptr)) { - printf("MODIFIED\t%s\n", path); - } else { - printf("NOT MODIFIED\t%s\n", path); - } - } else { - printf("MISSING\t\t%s\n", path); - } - FREE(str); - } - } - printf("\n"); - } else if(pmo_q_list) { - info = db_scan(db, package, INFRQ_DESC | INFRQ_FILES); - if(info == NULL) { - fprintf(stderr, "Package \"%s\" was not found.\n", package); - return(2); - } - for(lp = info->files; lp; lp = lp->next) { - printf("%s %s%s\n", info->name, pmo_root, (char*)lp->data); - } - } else if(pmo_q_orphans) { - info = db_scan(db, package, INFRQ_DESC | INFRQ_DEPENDS); - if(info == NULL) { - fprintf(stderr, "Package \"%s\" was not found.\n", package); - return(2); - } - if(info->requiredby == NULL) { - printf("%s %s\n", info->name, info->version); - } - } else { - info = db_scan(db, package, INFRQ_DESC); - if(info == NULL) { - fprintf(stderr, "Package \"%s\" was not found.\n", package); - return(2); - } - printf("%s %s\n", info->name, info->version); - } - FREEPKG(info); - } - } - - return(0); -} - -int pacman_upgrade(pacdb_t *db, PMList *targets) -{ - /* this is basically just a remove-then-add process. pacman_add() will */ - /* handle it */ - pmo_upgrade = 1; - return(pacman_add(db, targets)); -} - -/* Re-order a list of target packages with respect to their dependencies. - * - * Example: - * A depends on C - * B depends on A - * Target order is A,B,C,D - * - * Should be re-ordered to C,A,B,D - * - * This function returns the new PMList* target list. - * - */ -PMList* sortbydeps(PMList *targets) -{ - PMList *newtargs = NULL; - PMList *i, *j, *k; - int change = 1; - int numscans = 0; - int numtargs = 0; - int clean = 0; - - /* count the number of targets */ - numtargs = list_count(targets); - - while(change) { - change = 0; - if(numscans > numtargs) { - vprint("warning: possible dependency cycle detected\n"); - change = 0; - continue; - } - newtargs = NULL; - numscans++; - /* run thru targets, moving up packages as necessary */ - for(i = targets; i; i = i->next) { - pkginfo_t *p = (pkginfo_t*)i->data; - for(j = p->depends; j; j = j->next) { - depend_t dep; - int found = 0; - pkginfo_t *q = NULL; - - splitdep(j->data, &dep); - /* look for dep.name -- if it's farther down in the list, then - * move it up above p - */ - for(k = i->next; k && !found; k = k->next) { - q = (pkginfo_t*)k->data; - if(!strcmp(dep.name, q->name)) { - found = 1; - } - } - if(found) { - if(!is_pkgin(q, newtargs)) { - change = 1; - newtargs = list_add(newtargs, q); - } - } - } - if(!is_pkgin(p, newtargs)) { - newtargs = list_add(newtargs, p); - } - } - if(clean && change) { - /* free up targets -- it's local now */ - for(i = targets; i; i = i->next) { - i->data = NULL; - } - list_free(targets); - } - targets = newtargs; - clean = 1; - } - return(targets); -} - -/* populates *list with packages that need to be installed to satisfy all - * dependencies (recursive) for *syncpkg->pkg - * - * make sure *list and *trail are already initialized - */ -int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *list, PMList *trail) -{ - PMList *i, *j, *k; - PMList *targ = NULL; - PMList *deps = NULL; - - targ = list_new(); - targ = list_add(targ, syncpkg->pkg); - deps = checkdeps(local, PM_ADD, targ); - targ->data = NULL; - list_free(targ); - for(i = deps; i; i = i->next) { - int found = 0; - depmissing_t *miss = (depmissing_t*)i->data; - - /* XXX: conflicts are now treated specially in the _add and _sync functions */ - - /*if(miss->type == CONFLICT) { - fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target); - fprintf(stderr, " %s conflicts with %s\n", miss->target, miss->depend.name); - return(1); - } else*/ - if(miss->type == DEPEND) { - syncpkg_t *sync = NULL; - MALLOC(sync, sizeof(syncpkg_t)); - sync->replaces = NULL; - - /* find the package in one of the repositories */ - for(j = databases; !found && j; j = j->next) { - PMList *provides; - dbsync_t *dbs = (dbsync_t*)j->data; - /* check literals */ - for(k = dbs->pkgcache; !found && k; k = k->next) { - pkginfo_t *pkg = (pkginfo_t*)k->data; - if(!strcmp(miss->depend.name, pkg->name)) { - found = 1; - /* re-fetch the package record with dependency info */ - sync->pkg = db_scan(dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); - sync->dbs = dbs; - } - } - /* check provides */ - if(!found) { - provides = whatprovides(dbs->db, miss->depend.name); - if(provides) { - found = 1; - /* re-fetch the package record with dependency info */ - sync->pkg = db_scan(dbs->db, provides->data, INFRQ_DESC | INFRQ_DEPENDS); - sync->dbs = dbs; - } - list_free(provides); - } - } - if(!found) { - fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target); - fprintf(stderr, " \"%s\" is not in the package set\n", miss->depend.name); - return(1); - } - found = 0; - for(j = list; j; j = j->next) { - syncpkg_t *tmp = (syncpkg_t*)j->data; - if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { - found = 1; - } - } - if(found) { - /* this dep is already in the target list */ - continue; - } - vprint("resolving %s\n", sync->pkg->name); - found = 0; - for(j = trail; j; j = j->next) { - syncpkg_t *tmp = (syncpkg_t*)j->data; - if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { - found = 1; - } - } - if(!found) { - list_add(trail, sync); - if(resolvedeps(local, databases, sync, list, trail)) { - return(1); - } - vprint("adding %s-%s\n", sync->pkg->name, sync->pkg->version); - list_add(list, sync); - } else { - /* cycle detected -- skip it */ - vprint("dependency cycle detected: %s\n", sync->pkg->name); - } - } - } - return(0); -} - -/* - * returns a PMList* of missing_t pointers. - * - * conflicts are always name only, but dependencies can include versions - * with depmod operators. - * - */ -PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) -{ - pkginfo_t *info = NULL; - depend_t depend; - PMList *i, *j, *k; - int cmp; - int found = 0; - PMList *baddeps = NULL; - depmissing_t *miss = NULL; - - if(op == PM_UPGRADE) { - /* PM_UPGRADE handles the backwards dependencies, ie, the packages - * listed in the requiredby field. - */ - for(i = targets; i; i = i->next) { - pkginfo_t *tp, *oldpkg; - if(i->data == NULL) { - continue; - } - tp = (pkginfo_t*)i->data; - - if((oldpkg = db_scan(db, tp->name, INFRQ_DESC | INFRQ_DEPENDS)) == NULL) { - continue; - } - for(j = oldpkg->requiredby; j; j = j->next) { - char *ver; - pkginfo_t *p; - found = 0; - if((p = db_scan(db, j->data, INFRQ_DESC | INFRQ_DEPENDS)) == NULL) { - /* hmmm... package isn't installed.. */ - continue; - } - if(is_pkgin(p, targets)) { - /* this package is also in the upgrade list, so don't worry about it */ - continue; - } - for(k = p->depends; k && !found; k = k->next) { - /* find the dependency info in p->depends */ - if(splitdep(k->data, &depend)) { - continue; - } - if(!strcmp(depend.name, oldpkg->name)) { - found = 1; - } - } - if(found == 0) { - /* look for packages that list depend.name as a "provide" */ - PMList *provides = whatprovides(db, depend.name); - if(provides == NULL) { - /* not found */ - continue; - } - /* we found an installed package that provides depend.name */ - } - found = 0; - if(depend.mod == DEP_ANY) { - found = 1; - } else { - /* note that we use the version from the NEW package in the check */ - ver = strdup(tp->version); - if(!index(depend.version,'-')) { - char *ptr; - for(ptr = ver; *ptr != '-'; ptr++); - *ptr = '\0'; - } - cmp = rpmvercmp(ver, depend.version); - switch(depend.mod) { - case DEP_EQ: found = (cmp == 0); break; - case DEP_GE: found = (cmp >= 0); break; - case DEP_LE: found = (cmp <= 0); break; - } - FREE(ver); - } - if(!found) { - MALLOC(miss, sizeof(depmissing_t)); - miss->type = REQUIRED; - miss->depend.mod = depend.mod; - strncpy(miss->target, p->name, 256); - strncpy(miss->depend.name, depend.name, 256); - strncpy(miss->depend.version, depend.version, 64); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - } - freepkg(oldpkg); - } - } - if(op == PM_ADD || op == PM_UPGRADE) { - for(i = targets; i; i = i->next) { - pkginfo_t *tp; - if(i->data == NULL) { - continue; - } - tp = (pkginfo_t*)i->data; - - /* CONFLICTS */ - for(j = tp->conflicts; j; j = j->next) { - /* check targets against database */ - for(k = pm_packages; k; k = k->next) { - pkginfo_t *dp = (pkginfo_t*)k->data; - if(!strcmp(j->data, dp->name)) { - MALLOC(miss, sizeof(depmissing_t)); - miss->type = CONFLICT; - miss->depend.mod = DEP_ANY; - miss->depend.version[0] = '\0'; - strncpy(miss->target, tp->name, 256); - strncpy(miss->depend.name, dp->name, 256); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - } - /* check targets against targets */ - for(k = targets; k; k = k->next) { - pkginfo_t *a = (pkginfo_t*)k->data; - if(!strcmp(a->name, (char*)j->data)) { - MALLOC(miss, sizeof(depmissing_t)); - miss->type = CONFLICT; - miss->depend.mod = DEP_ANY; - miss->depend.version[0] = '\0'; - strncpy(miss->target, tp->name, 256); - strncpy(miss->depend.name, a->name, 256); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - } - } - /* check database against targets */ - rewinddir(db->dir); - while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_DEPENDS)) != NULL) { - for(j = info->conflicts; j; j = j->next) { - if(!strcmp((char*)j->data, tp->name)) { - MALLOC(miss, sizeof(depmissing_t)); - miss->type = CONFLICT; - miss->depend.mod = DEP_ANY; - miss->depend.version[0] = '\0'; - strncpy(miss->target, tp->name, 256); - strncpy(miss->depend.name, info->name, 256); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - } - } - - /* PROVIDES -- check to see if another package already provides what - * we offer - */ - /* XXX: disabled -- we allow multiple packages to provide the same thing. - * list packages in conflicts if they really do conflict. - for(j = tp->provides; j; j = j->next) { - PMList *provs = whatprovides(db, j->data); - for(k = provs; k; k = k->next) { - if(!strcmp(tp->name, k->data)) { - // this is the same package -- skip it - continue; - } - // we treat this just like a conflict - MALLOC(miss, sizeof(depmissing_t)); - miss->type = CONFLICT; - miss->depend.mod = DEP_ANY; - miss->depend.version[0] = '\0'; - strncpy(miss->target, tp->name, 256); - strncpy(miss->depend.name, k->data, 256); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - }*/ - - /* DEPENDENCIES -- look for unsatisfied dependencies */ - for(j = tp->depends; j; j = j->next) { - /* split into name/version pairs */ - if(splitdep((char*)j->data, &depend)) { - logaction(stderr, "warning: invalid dependency in %s", (char*)tp->name); - continue; - } - found = 0; - /* check database for literal packages */ - for(k = pm_packages; k && !found; k = k->next) { - pkginfo_t *p = (pkginfo_t*)k->data; - if(!strcmp(p->name, depend.name)) { - if(depend.mod == DEP_ANY) { - /* accept any version */ - found = 1; - } else { - char *ver = strdup(p->version); - /* check for a release in depend.version. if it's - * missing remove it from p->version as well. - */ - if(!index(depend.version,'-')) { - char *ptr; - for(ptr = ver; *ptr != '-'; ptr++); - *ptr = '\0'; - } - cmp = rpmvercmp(ver, depend.version); - switch(depend.mod) { - case DEP_EQ: found = (cmp == 0); break; - case DEP_GE: found = (cmp >= 0); break; - case DEP_LE: found = (cmp <= 0); break; - } - FREE(ver); - } - } - } - /* check other targets */ - for(k = targets; k && !found; k = k->next) { - pkginfo_t *p = (pkginfo_t*)k->data; - /* see if the package names match OR if p provides depend.name */ - if(!strcmp(p->name, depend.name) || is_in(depend.name, p->provides)) { - if(depend.mod == DEP_ANY) { - /* accept any version */ - found = 1; - } else { - char *ver = strdup(p->version); - /* check for a release in depend.version. if it's - * missing remove it from p->version as well. - */ - if(!index(depend.version,'-')) { - char *ptr; - for(ptr = ver; *ptr != '-'; ptr++); - *ptr = '\0'; - } - cmp = rpmvercmp(ver, depend.version); - switch(depend.mod) { - case DEP_EQ: found = (cmp == 0); break; - case DEP_GE: found = (cmp >= 0); break; - case DEP_LE: found = (cmp <= 0); break; - } - FREE(ver); - } - } - } - /* check database for provides matches */ - if(!found){ - k = whatprovides(db, depend.name); - if(k) { - /* grab the first one (there should only really be one, anyway) */ - pkginfo_t *p = db_scan(db, k->data, INFRQ_DESC); - if(p == NULL) { - /* wtf */ - fprintf(stderr, "data error: %s supposedly provides %s, but it was not found in db\n", - (char*)k->data, depend.name); - list_free(k); - continue; - } - if(depend.mod == DEP_ANY) { - /* accept any version */ - found = 1; - } else { - char *ver = strdup(p->version); - /* check for a release in depend.version. if it's - * missing remove it from p->version as well. - */ - if(!index(depend.version,'-')) { - char *ptr; - for(ptr = ver; *ptr != '-'; ptr++); - *ptr = '\0'; - } - cmp = rpmvercmp(ver, depend.version); - switch(depend.mod) { - case DEP_EQ: found = (cmp == 0); break; - case DEP_GE: found = (cmp >= 0); break; - case DEP_LE: found = (cmp <= 0); break; - } - FREE(ver); - } - } - list_free(k); - } - /* else if still not found... */ - if(!found) { - MALLOC(miss, sizeof(depmissing_t)); - miss->type = DEPEND; - miss->depend.mod = depend.mod; - strncpy(miss->target, tp->name, 256); - strncpy(miss->depend.name, depend.name, 256); - strncpy(miss->depend.version, depend.version, 64); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - } - } - } else if(op == PM_REMOVE) { - /* check requiredby fields */ - for(i = targets; i; i = i->next) { - pkginfo_t* tp; - if(i->data == NULL) { - continue; - } - tp = (pkginfo_t*)i->data; - for(j = tp->requiredby; j; j = j->next) { - if(!is_in((char*)j->data, targets)) { - MALLOC(miss, sizeof(depmissing_t)); - miss->type = REQUIRED; - miss->depend.mod = DEP_ANY; - miss->depend.version[0] = '\0'; - strncpy(miss->target, tp->name, 256); - strncpy(miss->depend.name, (char*)j->data, 256); - if(!list_isin(baddeps, miss)) { - baddeps = list_add(baddeps, miss); - } - } - } - } - } - - return(baddeps); -} - -int splitdep(char *depstr, depend_t *depend) -{ - char *str = NULL; - char *ptr = NULL; - - str = strdup(depstr); - - if((ptr = strstr(str, ">="))) { - depend->mod = DEP_GE; - } else if((ptr = strstr(str, "<="))) { - depend->mod = DEP_LE; - } else if((ptr = strstr(str, "="))) { - depend->mod = DEP_EQ; - } else { - /* no version specified - accept any */ - depend->mod = DEP_ANY; - strncpy(depend->name, str, sizeof(depend->name)); - strncpy(depend->version, "", sizeof(depend->version)); - } - - if(ptr == NULL) { - FREE(str); - return(0); - } - *ptr = '\0'; - strncpy(depend->name, str, sizeof(depend->name)); - ptr++; - if(depend->mod != DEP_EQ) { - ptr++; - } - strncpy(depend->version, ptr, sizeof(depend->version)); - FREE(str); - return(0); -} - -/* Look for a filename in a pkginfo_t.backup list. If we find it, - * then we return the md5 hash (parsed from the same line) - */ -char* needbackup(char* file, PMList *backup) -{ - PMList *lp; - - /* run through the backup list and parse out the md5 hash for our file */ - for(lp = backup; lp; lp = lp->next) { - char* str = strdup(lp->data); - char* ptr; - - /* tab delimiter */ - ptr = index(str, '\t'); - if(ptr == NULL) { - FREE(str); - continue; - } - *ptr = '\0'; - ptr++; - /* now str points to the filename and ptr points to the md5 hash */ - if(!strcmp(file, str)) { - char *md5 = strdup(ptr); - FREE(str); - return(md5); - } - FREE(str); - } - return(NULL); -} - -/* Parse command-line arguments for each operation - * op: the operation code requested - * argc: argc - * argv: argv - * - * Returns: 0 on success, 1 on error - */ -int parseargs(int op, int argc, char **argv) -{ - int opt; - int option_index = 0; - static struct option opts[] = - { - {"add", no_argument, 0, 'A'}, - {"remove", no_argument, 0, 'R'}, - {"upgrade", no_argument, 0, 'U'}, - {"freshen", no_argument, 0, 'F'}, - {"query", no_argument, 0, 'Q'}, - {"sync", no_argument, 0, 'S'}, - {"deptest", no_argument, 0, 'T'}, - {"vertest", no_argument, 0, 'Y'}, - {"resolve", no_argument, 0, 'D'}, - {"root", required_argument, 0, 'r'}, - {"dbpath", required_argument, 0, 'b'}, - {"verbose", no_argument, 0, 'v'}, - {"version", no_argument, 0, 'V'}, - {"help", no_argument, 0, 'h'}, - {"search", no_argument, 0, 's'}, - {"clean", no_argument, 0, 'c'}, - {"force", no_argument, 0, 'f'}, - {"nodeps", no_argument, 0, 'd'}, - {"orphans", no_argument, 0, 'e'}, - {"nosave", no_argument, 0, 'n'}, - {"owns", no_argument, 0, 'o'}, - {"list", no_argument, 0, 'l'}, - {"file", no_argument, 0, 'p'}, - {"info", no_argument, 0, 'i'}, - {"sysupgrade", no_argument, 0, 'u'}, - {"downloadonly", no_argument, 0, 'w'}, - {"refresh", no_argument, 0, 'y'}, - {"cascade", no_argument, 0, 'c'}, - {"groups", no_argument, 0, 'g'}, - {0, 0, 0, 0} - }; - - while((opt = getopt_long(argc, argv, "ARUFQSTDYr:b:vhscVfnoldepiuwyg", opts, &option_index))) { - if(opt < 0) { - break; - } - switch(opt) { - case 0: break; - case 'A': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_ADD); break; - case 'R': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_REMOVE); break; - case 'U': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_UPGRADE); break; - case 'F': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_UPGRADE); pmo_freshen = 1; break; - case 'Q': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_QUERY); break; - case 'S': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_SYNC); break; - case 'T': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_DEPTEST); break; - case 'Y': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_DEPTEST); pmo_d_vertest = 1; break; - case 'D': pmo_op = (pmo_op != PM_MAIN ? 0 : PM_DEPTEST); pmo_d_resolve = 1; break; - case 'h': pmo_help = 1; break; - case 'V': pmo_version = 1; break; - case 'b': strcpy(pmo_dbpath, optarg); break; - case 'c': pmo_s_clean = 1; pmo_r_cascade = 1; break; - case 'd': pmo_nodeps = 1; break; - case 'e': pmo_q_orphans = 1; break; - case 'f': pmo_force = 1; break; - case 'g': pmo_group = 1; break; - case 'i': pmo_q_info++; break; - case 'l': pmo_q_list = 1; break; - case 'n': pmo_nosave = 1; break; - case 'p': pmo_q_isfile = 1; break; - case 'o': pmo_q_owns = 1; break; - case 'r': if(realpath(optarg, pmo_root) == NULL) { - perror("bad root path"); - return(1); - } break; - case 's': pmo_s_search = 1; break; - case 'u': pmo_s_upgrade = 1; break; - case 'v': pmo_verbose = 1; break; - case 'w': pmo_s_downloadonly = 1; break; - case 'y': pmo_s_sync = 1; break; - case '?': return(1); - default: return(1); - } - } - - if(pmo_op == 0) { - fprintf(stderr, "error: only one operation may be used at a time\n\n"); - return(1); - } - - if(pmo_help) { - usage(pmo_op, (char*)basename(argv[0])); - return(2); - } - if(pmo_version) { - version(); - return(2); - } - - while(optind < argc) { - /* add the target to our target array */ - char *s = strdup(argv[optind]); - pm_targets = list_add(pm_targets, s); - optind++; - } - - return(0); -} - -int parseconfig(char *configfile) -{ - FILE *fp = NULL; - char line[PATH_MAX+1]; - char *ptr = NULL; - char *key = NULL; - int linenum = 0; - char section[256] = ""; - sync_t *sync = NULL; - - if((fp = fopen(configfile, "r")) == NULL) { - perror(configfile); - return(1); - } - - while(fgets(line, PATH_MAX, fp)) { - linenum++; - trim(line); - if(strlen(line) == 0 || line[0] == '#') { - continue; - } - if(line[0] == '[' && line[strlen(line)-1] == ']') { - /* new config section */ - ptr = line; - ptr++; - strncpy(section, ptr, min(255, strlen(ptr)-1)); - section[min(255, strlen(ptr)-1)] = '\0'; - vprint("config: new section '%s'\n", section); - if(!strlen(section)) { - fprintf(stderr, "config: line %d: bad section name\n", linenum); - return(1); - } - if(!strcmp(section, "local")) { - fprintf(stderr, "config: line %d: %s is reserved and cannot be used as a package tree\n", - linenum, section); - return(1); - } - if(strcmp(section, "options")) { - /* start a new sync record */ - MALLOC(sync, sizeof(sync_t)); - sync->treename = strdup(section); - sync->servers = NULL; - pmc_syncs = list_add(pmc_syncs, sync); - } - } else { - /* directive */ - if(!strlen(section)) { - fprintf(stderr, "config: line %d: all directives must belong to a section\n", linenum); - return(1); - } - ptr = line; - key = strsep(&ptr, "="); - if(key == NULL) { - fprintf(stderr, "config: line %d: syntax error\n", linenum); - return(1); - } - trim(key); - key = strtoupper(key); - if(ptr == NULL) { - if(!strcmp(key, "NOPASSIVEFTP")) { - pmo_nopassiveftp = 1; - vprint("config: nopassiveftp\n"); - } else if(!strcmp(key, "USESYSLOG")) { - pmo_usesyslog = 1; - vprint("config: usesyslog\n"); - } else { - fprintf(stderr, "config: line %d: syntax error\n", linenum); - return(1); - } - } else { - trim(ptr); - if(!strcmp(section, "options")) { - if(!strcmp(key, "NOUPGRADE")) { - char *p = ptr; - char *q; - while((q = strchr(p, ' '))) { - *q = '\0'; - pmo_noupgrade = list_add(pmo_noupgrade, strdup(p)); - vprint("config: noupgrade: %s\n", p); - p = q; - p++; - } - pmo_noupgrade = list_add(pmo_noupgrade, strdup(p)); - vprint("config: noupgrade: %s\n", p); - } else if(!strcmp(key, "IGNOREPKG")) { - char *p = ptr; - char *q; - while((q = strchr(p, ' '))) { - *q = '\0'; - pmo_ignorepkg = list_add(pmo_ignorepkg, strdup(p)); - vprint("config: ignorepkg: %s\n", p); - p = q; - p++; - } - pmo_ignorepkg = list_add(pmo_ignorepkg, strdup(p)); - vprint("config: ignorepkg: %s\n", p); - } else if(!strcmp(key, "DBPATH")) { - /* shave off the leading slash, if there is one */ - if(*ptr == '/') { - ptr++; - } - strncpy(pmo_dbpath, ptr, PATH_MAX); - vprint("config: dbpath: %s\n", pmo_dbpath); - } else if (!strcmp(key, "LOGFILE")) { - pmo_logfile = strndup(ptr, PATH_MAX); - vprint("config: log file: %s\n", pmo_logfile); - } else { - fprintf(stderr, "config: line %d: syntax error\n", linenum); - return(1); - } - } else { - if(!strcmp(key, "SERVER")) { - /* parse our special url */ - server_t *server; - char *p; - - MALLOC(server, sizeof(server_t)); - server->server = server->path = NULL; - server->protocol = NULL; - - p = strstr(ptr, "://"); - if(p == NULL) { - fprintf(stderr, "config: line %d: bad server location\n", linenum); - return(1); - } - *p = '\0'; - p++; p++; p++; - if(p == NULL || *p == '\0') { - fprintf(stderr, "config: line %d: bad server location\n", linenum); - return(1); - } - server->protocol = strdup(ptr); - if(!strcmp(server->protocol, "ftp") || !strcmp(server->protocol, "http")) { - char *slash; - /* split the url into domain and path */ - slash = strchr(p, '/'); - if(slash == NULL) { - /* no path included, default to / */ - server->path = strdup("/"); - } else { - /* add a trailing slash if we need to */ - if(slash[strlen(slash)-1] == '/') { - server->path = strdup(slash); - } else { - MALLOC(server->path, strlen(slash)+2); - sprintf(server->path, "%s/", slash); - } - *slash = '\0'; - } - server->server = strdup(p); - } else if(!strcmp(server->protocol, "file")){ - /* add a trailing slash if we need to */ - if(p[strlen(p)-1] == '/') { - server->path = strdup(p); - } else { - MALLOC(server->path, strlen(p)+2); - sprintf(server->path, "%s/", p); - } - } else { - fprintf(stderr, "config: line %d: protocol %s is not supported\n", linenum, ptr); - return(1); - } - /* add to the list */ - vprint("config: %s: server: %s %s %s\n", section, server->protocol, server->server, server->path); - sync->servers = list_add(sync->servers, server); - } else { - fprintf(stderr, "config: line %d: syntax error\n", linenum); - return(1); - } - } - line[0] = '\0'; - } - } - } - fclose(fp); - - return(0); -} - -/* Display usage/syntax for the specified operation. - * op: the operation code requested - * myname: basename(argv[0]) - */ -void usage(int op, char *myname) -{ - if(op == PM_MAIN) { - printf("usage: %s {-h --help}\n", myname); - printf(" %s {-V --version}\n", myname); - printf(" %s {-A --add} [options] \n", myname); - printf(" %s {-R --remove} [options] \n", myname); - printf(" %s {-U --upgrade} [options] \n", myname); - printf(" %s {-F --freshen} [options] \n", myname); - printf(" %s {-Q --query} [options] [package]\n", myname); - printf(" %s {-S --sync} [options] [package]\n", myname); - printf("\nuse '%s --help' with other options for more syntax\n\n", myname); - } else { - if(op == PM_ADD) { - printf("usage: %s {-A --add} [options] \n", myname); - printf("options:\n"); - printf(" -d, --nodeps skip dependency checks\n"); - printf(" -f, --force force install, overwrite conflicting files\n"); - } else if(op == PM_REMOVE) { - printf("usage: %s {-R --remove} [options] \n", myname); - printf("options:\n"); - printf(" -c, --cascade remove packages and all packages that depend on them\n"); - printf(" -d, --nodeps skip dependency checks\n"); - printf(" -n, --nosave remove configuration files as well\n"); - } else if(op == PM_UPGRADE) { - if(pmo_freshen) { - printf("usage: %s {-F --freshen} [options] \n", myname); - } else { - printf("usage: %s {-U --upgrade} [options] \n", myname); - } - printf("options:\n"); - printf(" -d, --nodeps skip dependency checks\n"); - printf(" -f, --force force install, overwrite conflicting files\n"); - } else if(op == PM_QUERY) { - printf("usage: %s {-Q --query} [options] [package]\n", myname); - printf("options:\n"); - printf(" -i, --info view package information\n"); - printf(" -g, --groups view all members of a package group\n"); - printf(" -l, --list list the contents of the queried package\n"); - printf(" -o, --owns query the package that owns \n"); - printf(" -p, --file pacman will query the package file [package] instead of\n"); - printf(" looking in the database\n"); - } else if(op == PM_SYNC) { - printf("usage: %s {-S --sync} [options] [package]\n", myname); - printf("options:\n"); - printf(" -c, --clean remove packages from cache directory to free up diskspace\n"); - printf(" -d, --nodeps skip dependency checks\n"); - printf(" -f, --force force install, overwrite conflicting files\n"); - printf(" -g, --groups view all members of a package group\n"); - printf(" -s, --search search sync database for matching strings\n"); - printf(" -u, --sysupgrade upgrade all packages that are out of date\n"); - printf(" -w, --downloadonly download packages, but do not install/upgrade anything\n"); - printf(" -y, --refresh download a fresh package sync database from the server\n"); - } - printf(" -v, --verbose be verbose\n"); - printf(" -r, --root set an alternate installation root\n"); - printf(" -b, --dbpath set an alternate database location\n"); - } -} - -/* Version - */ -void version(void) -{ - printf("\n"); - printf(" .--. Pacman v%s\n", PACVER); - printf("/ _.-' .-. .-. .-. Copyright (C) 2002-2003 Judd Vinet \n"); - printf("\\ '-. '-' '-' '-' \n"); - printf(" '--' This program may be freely redistributed under\n"); - printf(" the terms of the GNU General Public License\n\n"); -} - -/* Check verbosity option and, if set, print the - * string to stdout - */ -void vprint(char *fmt, ...) -{ - va_list args; - if(pmo_verbose) { - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - fflush(stdout); - } -} - -/* Output a message to stderr, and (optionally) syslog and/or a logfile */ -void logaction(FILE *fp, char *fmt, ...) -{ - char msg[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(msg, 1024, fmt, args); - va_end(args); - if(fp) { - fprintf(fp, "%s\n", msg); - fflush(fp); - } - if(pmo_usesyslog) { - syslog(LOG_WARNING, "%s", msg); - } - if(logfd) { - time_t t; - struct tm *tm; - t = time(NULL); - tm = localtime(&t); - - fprintf(logfd, "[%02d/%02d/%02d %02d:%02d] %s\n", tm->tm_mon+1, tm->tm_mday, - tm->tm_year-100, tm->tm_hour, tm->tm_min, msg); - } -} - -/* Condense a list of strings into one long (space-delimited) string - */ -char* buildstring(PMList *strlist) -{ - char* str; - int size = 1; - PMList *lp; - - for(lp = strlist; lp; lp = lp->next) { - size += strlen(lp->data) + 1; - } - MALLOC(str, size); - str[0] = '\0'; - for(lp = strlist; lp; lp = lp->next) { - strcat(str, lp->data); - strcat(str, " "); - } - /* shave off the last space */ - str[strlen(str)-1] = '\0'; - - return(str); -} - - -int lckmk(char *file, int retries, unsigned int sleep_secs) -{ - int fd, count = 0; - - while((fd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0000)) == -1 && errno == EACCES) { - if(++count < retries) { - sleep(sleep_secs); - } else { - return(-1); - } - } - return(fd > 0 ? 0 : -1); -} - -int lckrm(char *file) -{ - return(unlink(file)); -} - -void cleanup(int signum) -{ - PMList *lp; - - if(pm_access == READ_WRITE && lckrm(lckfile)) { - logaction(stderr, "warning: could not remove lock file %s", lckfile); - } - if(workfile) { - /* remove the current file being downloaded (as it's not complete) */ - unlink(workfile); - FREE(workfile); - } - if(pmo_usesyslog) { - closelog(); - } - if(logfd) { - fclose(logfd); - } - - /* free memory */ - for(lp = pmc_syncs; lp; lp = lp->next) { - sync_t *sync = (sync_t *)lp->data; - PMList *i; - for(i = sync->servers; i; i = i->next) { - server_t *server = (server_t *)i->data; - FREE(server->protocol); - FREE(server->server); - FREE(server->path); - } - FREELIST(sync->servers); - FREE(sync->treename); - } - FREELIST(pmc_syncs); - FREELIST(pmo_noupgrade); - FREELIST(pmo_ignorepkg); - FREE(pmo_root); - FREE(pmo_dbpath); - - FREELIST(pm_targets); - - /* this is segfaulting... quick fix for now - FREELISTPKGS(pm_packages);*/ - - exit(signum); -} - -/* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman.h b/src/pacman.h index 4f64519d..9c693a69 100644 --- a/src/pacman.h +++ b/src/pacman.h @@ -22,7 +22,7 @@ #define _PAC_PACMAN_H #ifndef PACVER -#define PACVER "2.7.3" +#define PACVER "2.7.4" #endif #ifndef PKGDIR -- cgit v1.2.3-24-g4f1b