diff options
Diffstat (limited to 'lib/libalpm/sync.c')
-rw-r--r-- | lib/libalpm/sync.c | 297 |
1 files changed, 238 insertions, 59 deletions
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 05746bbc..27bb380e 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -2,6 +2,9 @@ * sync.c * * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> + * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> + * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> * * 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 @@ -24,6 +27,7 @@ #include <stdio.h> #include <fcntl.h> #include <string.h> +#include <time.h> #ifdef CYGWIN #include <limits.h> /* PATH_MAX */ #endif @@ -31,7 +35,6 @@ #include <libintl.h> /* pacman */ #include "log.h" -#include "util.h" #include "error.h" #include "list.h" #include "package.h" @@ -41,10 +44,16 @@ #include "conflict.h" #include "provide.h" #include "trans.h" +#include "util.h" #include "sync.h" #include "versioncmp.h" #include "handle.h" +#include "util.h" #include "alpm.h" +#include "md5.h" +#include "sha1.h" +#include "handle.h" +#include "server.h" extern pmhandle_t *handle; @@ -102,34 +111,13 @@ static pmsyncpkg_t *find_pkginsync(char *needle, PMList *haystack) return(sync); } -/* It returns a PMList of packages extracted from the given archive - * (the archive must have been generated by gensync) - */ -PMList *_alpm_sync_load_dbarchive(char *archive) +static int istoonew(pmpkg_t *pkg) { - PMList *lp = NULL; - register struct archive *_archive; - struct archive_entry *entry; - - if((_archive = archive_read_new()) == NULL) { - pm_errno = PM_ERR_LIBARCHIVE_ERROR; - goto error; - } - archive_read_support_compression_all(_archive); - archive_read_support_format_all(_archive); - - if(archive_read_open_file(_archive, archive, 10240) != ARCHIVE_OK) { - pm_errno = PM_ERR_NOT_A_FILE; - goto error; - } - - archive_read_finish(_archive); - - return(lp); - -error: - archive_read_finish(_archive); - return(NULL); + time_t t; + if (!handle->upgradedelay) + return 0; + time(&t); + return((pkg->date + handle->upgradedelay) > t); } int _alpm_sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync) @@ -197,7 +185,7 @@ int _alpm_sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync) _alpm_log(PM_LOG_FLOW1, _("checking for package upgrades")); for(i = _alpm_db_get_pkgcache(db_local); i; i = i->next) { int cmp; - int replace = 0; + int replace=0; pmpkg_t *local = i->data; pmpkg_t *spkg = NULL; pmsyncpkg_t *sync; @@ -209,19 +197,19 @@ int _alpm_sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync) _alpm_log(PM_LOG_DEBUG, _("'%s' not found in sync db -- skipping"), local->name); continue; } - + /* we don't care about a to-be-replaced package's newer version */ - for(j = trans->packages; j && !replace; j = j->next) { + for(j = trans->packages; j && !replace; j=j->next) { sync = j->data; if(sync->type == PM_SYNC_TYPE_REPLACE) { if(_alpm_pkg_isin(spkg->name, sync->data)) { - replace = 1; + replace=1; } } } if(replace) { _alpm_log(PM_LOG_DEBUG, _("'%s' is already elected for removal -- skipping"), - spkg->name); + local->name); continue; } @@ -237,9 +225,14 @@ int _alpm_sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync) /* package should be ignored (IgnorePkg) */ _alpm_log(PM_LOG_WARNING, _("%s-%s: ignoring package upgrade (%s)"), local->name, local->version, spkg->version); + } else if(istoonew(spkg)) { + /* package too new (UpgradeDelay) */ + _alpm_log(PM_LOG_FLOW1, _("%s-%s: delaying upgrade of package (%s)\n"), + local->name, local->version, spkg->version); + /* check if spkg->name is already in the packages list. */ } else { _alpm_log(PM_LOG_FLOW2, _("%s-%s elected for upgrade (%s => %s)"), - local->name, local->version, local->version, spkg->version); + local->name, local->version, local->version, spkg->version); if(!find_pkginsync(spkg->name, trans->packages)) { pmpkg_t *dummy = _alpm_pkg_new(local->name, local->version); if(dummy == NULL) { @@ -367,20 +360,25 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, c return(0); } -/* Helper function for _alpm_list_remove +/* Helper functions for _alpm_list_remove */ static int ptr_cmp(const void *s1, const void *s2) { return(strcmp(((pmsyncpkg_t *)s1)->pkg->name, ((pmsyncpkg_t *)s2)->pkg->name)); } +static int pkg_cmp(const void *p1, const void *p2) +{ + return(strcmp(((pmpkg_t *)p1)->name, ((pmsyncpkg_t *)p2)->pkg->name)); +} + int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PMList **data) { PMList *deps = NULL; PMList *list = NULL; /* list allowing checkdeps usage with data from trans->packages */ PMList *trail = NULL; /* breadcrum list to avoid running into circles */ - PMList *asked = NULL; - PMList *i, *j; + PMList *asked = NULL; + PMList *i, *j, *k, *l; int ret = 0; ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); @@ -409,6 +407,7 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML goto cleanup; } } + for(i = list; i; i = i->next) { /* add the dependencies found by resolvedeps to the transaction set */ pmpkg_t *spkg = i->data; @@ -420,13 +419,39 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML } trans->packages = _alpm_list_add(trans->packages, sync); _alpm_log(PM_LOG_FLOW2, _("adding package %s-%s to the transaction targets"), - spkg->name, spkg->version); + spkg->name, spkg->version); + } else { + /* remove the original targets from the list if requested */ + if((trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) { + pmpkg_t *p; + trans->packages = _alpm_list_remove(trans->packages, spkg, pkg_cmp, (void**)&p); + FREEPKG(p); + } } } + + /* re-order w.r.t. dependencies */ + k = l = NULL; + for(i=trans->packages; i; i=i->next) { + pmsyncpkg_t *s = (pmsyncpkg_t*)i->data; + k = _alpm_list_add(k, s->pkg); + } + k = _alpm_sortbydeps(k, PM_TRANS_TYPE_ADD); + for(i=k; i; i=i->next) { + for(j=trans->packages; j; j=j->next) { + pmsyncpkg_t *s = (pmsyncpkg_t*)j->data; + if(s->pkg==i->data) { + l = _alpm_list_add(l, s); + } + } + } + FREELISTPTR(trans->packages); + trans->packages = l; + EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_DONE, NULL, NULL); _alpm_log(PM_LOG_FLOW1, _("looking for unresolvable dependencies")); - deps = _alpm_checkdeps(db_local, PM_TRANS_TYPE_UPGRADE, list); + deps = _alpm_checkdeps(trans, db_local, PM_TRANS_TYPE_UPGRADE, list); if(deps) { if(data) { *data = deps; @@ -470,19 +495,18 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML } } if(found) { - _alpm_log(PM_LOG_FLOW2, "'%s' is already elected for removal -- skipping", - miss->depend.name); + _alpm_log(PM_LOG_DEBUG, _("'%s' is already elected for removal -- skipping"), + miss->depend.name); continue; } sync = find_pkginsync(miss->target, trans->packages); if(sync == NULL) { - _alpm_log(PM_LOG_DEBUG, "'%s' not found in transaction set -- skipping", + _alpm_log(PM_LOG_DEBUG, _("'%s' not found in transaction set -- skipping"), miss->target); continue; } local = _alpm_db_get_pkgfromcache(db_local, miss->depend.name); - /* check if this package also "provides" the package it's conflicting with */ if(_alpm_list_is_strin(miss->depend.name, sync->pkg->provides)) { @@ -513,16 +537,18 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML depend = _alpm_list_is_strin(miss->depend.name, trans->targets); if(depend && !target) { _alpm_log(PM_LOG_DEBUG, _("'%s' is in the target list -- keeping it"), - miss->depend.name); + miss->depend.name); /* remove miss->target */ rmpkg = miss->target; } else if(target && !depend) { _alpm_log(PM_LOG_DEBUG, _("'%s' is in the target list -- keeping it"), - miss->target); + miss->target); /* remove miss->depend.name */ rmpkg = miss->depend.name; } else { - /* something's not right, bail out with a conflict error */ + /* miss->depend.name is not needed, miss->target already provides + * it, let's resolve the conflict */ + rmpkg = miss->depend.name; } if(rmpkg) { pmsyncpkg_t *rsync = find_pkginsync(rmpkg, trans->packages); @@ -534,9 +560,8 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML } } } - /* It's a conflict -- see if they want to remove it - */ + */ _alpm_log(PM_LOG_DEBUG, _("resolving package '%s' conflict"), miss->target); if(local) { int doremove = 0; @@ -639,8 +664,8 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML } } if(list) { - _alpm_log(PM_LOG_FLOW1, "checking dependencies of packages designated for removal"); - deps = _alpm_checkdeps(db_local, PM_TRANS_TYPE_REMOVE, list); + _alpm_log(PM_LOG_FLOW1, _("checking dependencies of packages designated for removal")); + deps = _alpm_checkdeps(trans, db_local, PM_TRANS_TYPE_REMOVE, list); if(deps) { int errorout = 0; for(i = deps; i; i = i->next) { @@ -673,7 +698,7 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML if(!strcmp(m->data, o->data)) { /* found matching provisio -- we're good to go */ _alpm_log(PM_LOG_FLOW2, _("found '%s' as a provision for '%s' -- conflict aborted"), - sp->pkg->name, (char *)o->data); + sp->pkg->name, (char *)o->data); pfound = 1; } } @@ -710,25 +735,172 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, PMList *dbs_sync, PML /*EVENT(trans, PM_TRANS_EVT_CHECKDEPS_DONE, NULL, NULL);*/ } +#ifndef __sun__ + /* check for free space only in case the packages will be extracted */ + if(!(trans->flags & PM_TRANS_FLAG_NOCONFLICTS)) { + if(_alpm_check_freespace(trans, data) == -1) { + /* pm_errno is set by check_freespace */ + ret = -1; + goto cleanup; + } + } +#endif + cleanup: FREELISTPTR(list); FREELISTPTR(trail); FREELIST(asked); - FREELIST(deps); return(ret); } int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, PMList **data) { - PMList *i; + PMList *i, *j, *files = NULL; pmtrans_t *tr = NULL; - int replaces = 0; + int replaces = 0, retval = 0; + char ldir[PATH_MAX]; + int varcache = 1; ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); + trans->state = STATE_DOWNLOADING; + /* group sync records by repository and download */ + snprintf(ldir, PATH_MAX, "%s%s", handle->root, handle->cachedir); + + for(i = handle->dbs_sync; i; i = i->next) { + pmdb_t *current = i->data; + + for(j = trans->packages; j; j = j->next) { + pmsyncpkg_t *sync = j->data; + pmpkg_t *spkg = sync->pkg; + pmdb_t *dbs = spkg->data; + + if(current == dbs) { + char path[PATH_MAX]; + + if(trans->flags & PM_TRANS_FLAG_PRINTURIS) { + snprintf(path, PATH_MAX, "%s-%s" PM_EXT_PKG, spkg->name, spkg->version); + EVENT(trans, PM_TRANS_EVT_PRINTURI, alpm_db_getinfo(current, PM_DB_FIRSTSERVER), path); + } else { + struct stat buf; + snprintf(path, PATH_MAX, "%s/%s-%s" PM_EXT_PKG, ldir, spkg->name, spkg->version); + if(stat(path, &buf)) { + /* file is not in the cache dir, so add it to the list */ + snprintf(path, PATH_MAX, "%s-%s" PM_EXT_PKG, spkg->name, spkg->version); + files = _alpm_list_add(files, strdup(path)); + } else { + _alpm_log(PM_LOG_DEBUG, _("%s-%s%s is already in the cache\n"), + spkg->name, spkg->version, PM_EXT_PKG); + } + } + } + } + + if(files) { + struct stat buf; + EVENT(trans, PM_TRANS_EVT_RETRIEVE_START, current->treename, NULL); + if(stat(ldir, &buf)) { + /* no cache directory.... try creating it */ + _alpm_log(PM_LOG_WARNING, _("no %s cache exists. creating...\n"), ldir); + alpm_logaction(_("warning: no %s cache exists. creating..."), ldir); + if(_alpm_makepath(ldir)) { + /* couldn't mkdir the cache directory, so fall back to /tmp and unlink + * the package afterwards. + */ + _alpm_log(PM_LOG_WARNING, _("couldn't create package cache, using /tmp instead\n")); + alpm_logaction(_("warning: couldn't create package cache, using /tmp instead")); + snprintf(ldir, PATH_MAX, "%s/tmp", handle->root); + if(_alpm_handle_set_option(handle, PM_OPT_CACHEDIR, (long)"/tmp") == -1) { + _alpm_log(PM_LOG_WARNING, _("failed to set option CACHEDIR (%s)\n"), alpm_strerror(pm_errno)); + RET_ERR(PM_ERR_RETRIEVE, -1); + } + varcache = 0; + } + } + if(_alpm_downloadfiles(current->servers, ldir, files)) { + _alpm_log(PM_LOG_WARNING, _("failed to retrieve some files from %s\n"), current->treename); + RET_ERR(PM_ERR_RETRIEVE, -1); + } + FREELIST(files); + } + } + if(trans->flags & PM_TRANS_FLAG_PRINTURIS) { + return(0); + } + + /* Check integrity of files */ + EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL); + + for(i = trans->packages; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + pmpkg_t *spkg = sync->pkg; + char str[PATH_MAX], pkgname[PATH_MAX]; + char *md5sum1, *md5sum2, *sha1sum1, *sha1sum2; + char *ptr=NULL; + + snprintf(pkgname, PATH_MAX, "%s-%s" PM_EXT_PKG, + spkg->name, spkg->version); + md5sum1 = spkg->md5sum; + sha1sum1 = spkg->sha1sum; + + if((md5sum1 == NULL) && (sha1sum1 == NULL)) { + if((ptr = (char *)malloc(512)) == NULL) { + RET_ERR(PM_ERR_MEMORY, -1); + } + snprintf(ptr, 512, _("can't get md5 or sha1 checksum for package %s\n"), pkgname); + *data = _alpm_list_add(*data, ptr); + retval = 1; + continue; + } + snprintf(str, PATH_MAX, "%s/%s/%s", handle->root, handle->cachedir, pkgname); + md5sum2 = _alpm_MDFile(str); + sha1sum2 = _alpm_SHAFile(str); + if(md5sum2 == NULL && sha1sum2 == NULL) { + if((ptr = (char *)malloc(512)) == NULL) { + RET_ERR(PM_ERR_MEMORY, -1); + } + snprintf(ptr, 512, _("can't get md5 or sha1 checksum for package %s\n"), pkgname); + *data = _alpm_list_add(*data, ptr); + retval = 1; + continue; + } + if((strcmp(md5sum1, md5sum2) != 0) && (strcmp(sha1sum1, sha1sum2) != 0)) { + int doremove=0; + if((ptr = (char *)malloc(512)) == NULL) { + RET_ERR(PM_ERR_MEMORY, -1); + } + if(trans->flags & PM_TRANS_FLAG_ALLDEPS) { + doremove=1; + } else { + QUESTION(trans, PM_TRANS_CONV_CORRUPTED_PKG, pkgname, NULL, NULL, &doremove); + } + if(doremove) { + char str[PATH_MAX]; + snprintf(str, PATH_MAX, "%s%s/%s-%s" PM_EXT_PKG, handle->root, handle->cachedir, spkg->name, spkg->version); + unlink(str); + snprintf(ptr, 512, _("archive %s was corrupted (bad MD5 or SHA1 checksum)\n"), pkgname); + } else { + snprintf(ptr, 512, _("archive %s is corrupted (bad MD5 or SHA1 checksum)\n"), pkgname); + } + *data = _alpm_list_add(*data, ptr); + retval = 1; + } + FREE(md5sum2); + FREE(sha1sum2); + } + if(retval) { + pm_errno = PM_ERR_PKG_CORRUPTED; + goto error; + } + EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL); + if(trans->flags & PM_TRANS_FLAG_DOWNLOADONLY) { + return(0); + } + /* remove conflicting and to-be-replaced packages */ + trans->state = STATE_COMMITING; tr = _alpm_trans_new(); if(tr == NULL) { _alpm_log(PM_LOG_ERROR, _("could not create removal transaction")); @@ -736,8 +908,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, PMList **data) goto error; } - if(_alpm_trans_init(tr, PM_TRANS_TYPE_REMOVE, PM_TRANS_FLAG_NODEPS, - trans->cb_event, trans->cb_conv) == -1) { + if(_alpm_trans_init(tr, PM_TRANS_TYPE_REMOVE, PM_TRANS_FLAG_NODEPS, NULL, NULL, NULL) == -1) { _alpm_log(PM_LOG_ERROR, _("could not initialize the removal transaction")); goto error; } @@ -780,8 +951,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, PMList **data) pm_errno = PM_ERR_MEMORY; goto error; } - if(_alpm_trans_init(tr, PM_TRANS_TYPE_UPGRADE, trans->flags | PM_TRANS_FLAG_NODEPS, - trans->cb_event, trans->cb_conv) == -1) { + if(_alpm_trans_init(tr, PM_TRANS_TYPE_UPGRADE, trans->flags | PM_TRANS_FLAG_NODEPS, trans->cb_event, trans->cb_conv, trans->cb_progress) == -1) { _alpm_log(PM_LOG_ERROR, _("could not initialize transaction")); goto error; } @@ -802,6 +972,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, PMList **data) } if(_alpm_trans_prepare(tr, data) == -1) { _alpm_log(PM_LOG_ERROR, _("could not prepare transaction")); + /* pm_errno is set by trans_prepare */ goto error; } if(_alpm_trans_commit(tr, NULL) == -1) { @@ -812,7 +983,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, PMList **data) /* propagate replaced packages' requiredby fields to their new owners */ if(replaces) { - _alpm_log(PM_LOG_FLOW1, _("updating database for replaced packages dependencies")); + _alpm_log(PM_LOG_FLOW1, _("updating database for replaced packages' dependencies")); for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; if(sync->type == PM_SYNC_TYPE_REPLACE) { @@ -857,10 +1028,18 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, PMList **data) } } + if(!varcache && !(trans->flags & PM_TRANS_FLAG_DOWNLOADONLY)) { + /* delete packages */ + for(i = files; i; i = i->next) { + unlink(i->data); + } + } return(0); error: FREETRANS(tr); + /* commiting failed, so this is still just a prepared transaction */ + trans->state = STATE_PREPARED; return(-1); } |