summaryrefslogtreecommitdiffstats
path: root/lib/libalpm/db.c
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2007-06-04 05:57:38 +0200
committerDan McGee <dan@archlinux.org>2007-06-05 04:52:04 +0200
commit64d36db5f45db15997c6a3987d6f4b0ce147df27 (patch)
treed18340215958e82d4a9a30ec491d5ee2219645ba /lib/libalpm/db.c
parente0afe6e94a71a6aeb964e9624c2df4f4a2821704 (diff)
downloadpacman-64d36db5f45db15997c6a3987d6f4b0ce147df27.tar.gz
pacman-64d36db5f45db15997c6a3987d6f4b0ce147df27.tar.xz
Move functions out of alpm.c to where they belong
alpm.h is the only "publically viewable" file, so there is no reason to have functions in alpm.c that belong in package.c, db.c, etc. Move the functions where they belong and leave only the library init functions in alpm.c. Signed-off-by: Dan McGee <dan@archlinux.org>
Diffstat (limited to 'lib/libalpm/db.c')
-rw-r--r--lib/libalpm/db.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index 0aa8de18..a3226335 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -48,10 +48,450 @@
#include "util.h"
#include "error.h"
#include "server.h"
+#include "provide.h"
#include "handle.h"
#include "cache.h"
#include "alpm.h"
+#include "sync.h" /* alpm_db_get_upgrades() */
+
+/** \addtogroup alpm_databases Database Functions
+ * @brief Functions to query and manipulate the database of libalpm
+ * @{
+ */
+
+/** Register a package database
+ * @param treename the name of the repository
+ * @return a pmdb_t* on success (the value), NULL on error
+ */
+pmdb_t SYMEXPORT *alpm_db_register(char *treename)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, NULL));
+ ASSERT(treename != NULL && strlen(treename) != 0, RET_ERR(PM_ERR_WRONG_ARGS, NULL));
+ /* Do not register a database if a transaction is on-going */
+ ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, NULL));
+
+ return(_alpm_db_register(treename, NULL));
+}
+
+/** Unregister a package database
+ * @param db pointer to the package database to unregister
+ * @return 0 on success, -1 on error (pm_errno is set accordingly)
+ */
+int alpm_db_unregister(pmdb_t *db)
+{
+ int found = 0;
+
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
+ ASSERT(db != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ /* Do not unregister a database if a transaction is on-going */
+ ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
+
+ if(db == handle->db_local) {
+ handle->db_local = NULL;
+ found = 1;
+ } else {
+ void *data;
+ handle->dbs_sync = alpm_list_remove(handle->dbs_sync, db, _alpm_db_cmp, &data);
+ if(data) {
+ found = 1;
+ }
+ }
+
+ if(!found) {
+ RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, _("unregistering database '%s'"), db->treename);
+
+ /* Cleanup */
+ _alpm_db_free_pkgcache(db);
+
+ _alpm_log(PM_LOG_DEBUG, _("closing database '%s'"), db->treename);
+ _alpm_db_close(db);
+
+ _alpm_db_free(db);
+
+ return(0);
+}
+
+/** Set the serverlist of a database.
+ * @param db database pointer
+ * @param url url of the server
+ * @return 0 on success, -1 on error (pm_errno is set accordingly)
+ */
+int alpm_db_setserver(pmdb_t *db, const char *url)
+{
+ int found = 0;
+
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
+
+ if(strcmp(db->treename, "local") == 0) {
+ if(handle->db_local != NULL) {
+ found = 1;
+ }
+ } else {
+ alpm_list_t *i;
+ for(i = handle->dbs_sync; i && !found; i = i->next) {
+ pmdb_t *sdb = i->data;
+ if(strcmp(db->treename, sdb->treename) == 0) {
+ found = 1;
+ }
+ }
+ }
+ if(!found) {
+ RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+ }
+
+ if(url && strlen(url)) {
+ pmserver_t *server;
+ if((server = _alpm_server_new(url)) == NULL) {
+ /* pm_errno is set by _alpm_server_new */
+ return(-1);
+ }
+ db->servers = alpm_list_add(db->servers, server);
+ _alpm_log(PM_LOG_DEBUG, _("adding new server to database '%s': protocol '%s', server '%s', path '%s'"),
+ db->treename, server->s_url->scheme, server->s_url->host, server->s_url->doc);
+ } else {
+ FREELIST(db->servers);
+ _alpm_log(PM_LOG_DEBUG, _("serverlist flushed for '%s'"), db->treename);
+ }
+
+ return(0);
+}
+
+/** Update a package database
+ * @param force if true, then forces the update, otherwise update only in case
+ * the database isn't up to date
+ * @param db pointer to the package database to update
+ * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
+ * to date
+ */
+int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
+{
+ alpm_list_t *lp;
+ char path[PATH_MAX];
+ alpm_list_t *files = NULL;
+ char newmtime[16] = "";
+ char lastupdate[16] = "";
+ const char *dbpath;
+ int ret;
+
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
+ ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ /* Verify we are in a transaction. This is done _mainly_ because we need a DB
+ * lock - if we update without a db lock, we may kludge some other pacman
+ * process that _has_ a lock.
+ */
+ ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
+ ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
+ ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1));
+
+ if(!alpm_list_find(handle->dbs_sync, db)) {
+ RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+ }
+
+ if(!force) {
+ /* get the lastupdate time */
+ _alpm_db_getlastupdate(db, lastupdate);
+ if(strlen(lastupdate) == 0) {
+ _alpm_log(PM_LOG_DEBUG, _("failed to get lastupdate time for %s (no big deal)"), db->treename);
+ }
+ }
+
+ /* build a one-element list */
+ snprintf(path, PATH_MAX, "%s" DBEXT, db->treename);
+ files = alpm_list_add(files, strdup(path));
+
+ dbpath = alpm_option_get_dbpath();
+
+ ret = _alpm_downloadfiles_forreal(db->servers, dbpath, files, lastupdate, newmtime);
+ FREELIST(files);
+ if(ret == 1) {
+ /* mtimes match, do nothing */
+ pm_errno = 0;
+ return(1);
+ } else if(ret == -1) {
+ /* we use downloadLastErrString and downloadLastErrCode here, error returns from
+ * libdownload */
+ _alpm_log(PM_LOG_DEBUG, _("failed to sync db: %s [%d]"), downloadLastErrString, downloadLastErrCode);
+ RET_ERR(PM_ERR_DB_SYNC, -1);
+ } else {
+ if(strlen(newmtime)) {
+ _alpm_log(PM_LOG_DEBUG, _("sync: new mtime for %s: %s"), db->treename, newmtime);
+ _alpm_db_setlastupdate(db, newmtime);
+ }
+ snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename);
+
+ /* remove the old dir */
+ _alpm_log(PM_LOG_DEBUG, _("flushing database %s%s"), db->path);
+ for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
+ pmpkg_t *pkg = lp->data;
+ if(pkg && _alpm_db_remove(db, pkg) == -1) {
+ _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s%s"), db->treename,
+ alpm_pkg_get_name(pkg));
+ RET_ERR(PM_ERR_DB_REMOVE, -1);
+ }
+ }
+
+ /* Cache needs to be rebuild */
+ _alpm_db_free_pkgcache(db);
+
+ /* uncompress the sync database */
+ if(_alpm_db_install(db, path) == -1) {
+ return -1;
+ }
+ }
+
+ return(0);
+}
+
+/** Get a package entry from a package database
+ * @param db pointer to the package database to get the package from
+ * @param name of the package
+ * @return the package entry on success, NULL on error
+ */
+pmpkg_t SYMEXPORT *alpm_db_get_pkg(pmdb_t *db, const char *name)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(db != NULL, return(NULL));
+ ASSERT(name != NULL && strlen(name) != 0, return(NULL));
+
+ return(_alpm_db_get_pkgfromcache(db, name));
+}
+
+/** Get the package cache of a package database
+ * @param db pointer to the package database to get the package from
+ * @return the list of packages on success, NULL on error
+ */
+alpm_list_t SYMEXPORT *alpm_db_getpkgcache(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(db != NULL, return(NULL));
+
+ return(_alpm_db_get_pkgcache(db));
+}
+
+/** Get the list of packages that a package provides
+ * @param db pointer to the package database to get the package from
+ * @param name name of the package
+ * @return the list of packages on success, NULL on error
+ */
+alpm_list_t SYMEXPORT *alpm_db_whatprovides(pmdb_t *db, const char *name)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(db != NULL, return(NULL));
+ ASSERT(name != NULL && strlen(name) != 0, return(NULL));
+
+ return(_alpm_db_whatprovides(db, name));
+}
+
+/** Get a group entry from a package database
+ * @param db pointer to the package database to get the group from
+ * @param name of the group
+ * @return the groups entry on success, NULL on error
+ */
+pmgrp_t SYMEXPORT *alpm_db_readgrp(pmdb_t *db, const char *name)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(db != NULL, return(NULL));
+ ASSERT(name != NULL && strlen(name) != 0, return(NULL));
+
+ return(_alpm_db_get_grpfromcache(db, name));
+}
+
+/** Get the group cache of a package database
+ * @param db pointer to the package database to get the group from
+ * @return the list of groups on success, NULL on error
+ */
+alpm_list_t SYMEXPORT *alpm_db_getgrpcache(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(db != NULL, return(NULL));
+
+ return(_alpm_db_get_grpcache(db));
+}
+
+/** Searches a database
+ * @param db pointer to the package database to search in
+ * @param needles the list of strings to search for
+ * @return the list of packages on success, NULL on error
+ */
+alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, alpm_list_t* needles)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(db != NULL, return(NULL));
+
+ return(_alpm_db_search(db, needles));
+}
+
+/* This function is mostly the same as sync.c find_replacements and sysupgrade
+ * functions, and we should be able to combine them - this is an interim
+ * solution made for -Qu operation */
+alpm_list_t SYMEXPORT *alpm_db_get_upgrades()
+{
+ alpm_list_t *syncpkgs = NULL;
+ alpm_list_t *i, *j, *k, *m;
+
+ ALPM_LOG_FUNC;
+
+ /* TODO holy nested loops, Batman! */
+ /* check for "recommended" package replacements */
+ _alpm_log(PM_LOG_DEBUG, _("checking for package replacements"));
+ for(i = handle->dbs_sync; i; i = i->next) {
+ for(j = _alpm_db_get_pkgcache(i->data); j; j = j->next) {
+ pmpkg_t *spkg = j->data;
+
+ for(k = alpm_pkg_get_replaces(spkg); k; k = k->next) {
+
+ for(m = _alpm_db_get_pkgcache(handle->db_local); m; m = m->next) {
+ pmpkg_t *lpkg = m->data;
+
+ if(strcmp(k->data, alpm_pkg_get_name(lpkg)) == 0) {
+ _alpm_log(PM_LOG_DEBUG, _("checking replacement '%s' for package '%s'"), k->data,
+ alpm_pkg_get_name(spkg));
+ if(alpm_list_find_str(handle->ignorepkg, alpm_pkg_get_name(lpkg))) {
+ _alpm_log(PM_LOG_WARNING, _("%s-%s: ignoring package upgrade (to be replaced by %s-%s)"),
+ alpm_pkg_get_name(lpkg), alpm_pkg_get_version(lpkg),
+ alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg));
+ } else {
+ /* assume all replaces=() packages are accepted */
+ pmsyncpkg_t *sync = NULL;
+ pmpkg_t *dummy = _alpm_pkg_new(alpm_pkg_get_name(lpkg), NULL);
+ if(dummy == NULL) {
+ pm_errno = PM_ERR_MEMORY;
+ goto error;
+ }
+ dummy->requiredby = alpm_list_strdup(alpm_pkg_get_requiredby(lpkg));
+
+ pmsyncpkg_t *syncpkg;
+ syncpkg = _alpm_sync_find(syncpkgs, alpm_pkg_get_name(spkg));
+
+ if(syncpkg) {
+ /* found it -- just append to the replaces list */
+ sync->data = alpm_list_add(sync->data, dummy);
+ } else {
+ /* none found -- enter pkg into the final sync list */
+ sync = _alpm_sync_new(PM_SYNC_TYPE_REPLACE, spkg, NULL);
+ if(sync == NULL) {
+ _alpm_pkg_free(dummy);
+ pm_errno = PM_ERR_MEMORY;
+ goto error;
+ }
+ sync->data = alpm_list_add(NULL, dummy);
+ syncpkgs = alpm_list_add(syncpkgs, sync);
+ }
+ _alpm_log(PM_LOG_DEBUG, _("%s-%s elected for upgrade (to be replaced by %s-%s)"),
+ alpm_pkg_get_name(lpkg), alpm_pkg_get_version(lpkg),
+ alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg));
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* now do normal upgrades */
+ for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) {
+ int replace=0;
+ pmpkg_t *local = i->data;
+ pmpkg_t *spkg = NULL;
+ pmsyncpkg_t *sync;
+
+ for(j = handle->dbs_sync; !spkg && j; j = j->next) {
+ spkg = _alpm_db_get_pkgfromcache(j->data, alpm_pkg_get_name(local));
+ }
+ if(spkg == NULL) {
+ _alpm_log(PM_LOG_DEBUG, _("'%s' not found in sync db -- skipping"), alpm_pkg_get_name(local));
+ continue;
+ }
+
+ /* we don't care about a to-be-replaced package's newer version */
+ for(j = syncpkgs; j && !replace; j=j->next) {
+ sync = j->data;
+ if(sync->type == PM_SYNC_TYPE_REPLACE) {
+ if(_alpm_pkg_find(alpm_pkg_get_name(spkg), sync->data)) {
+ replace=1;
+ }
+ }
+ }
+ if(replace) {
+ _alpm_log(PM_LOG_DEBUG, _("'%s' is already elected for removal -- skipping"),
+ alpm_pkg_get_name(local));
+ continue;
+ }
+
+ if(alpm_pkg_compare_versions(local, spkg)) {
+ _alpm_log(PM_LOG_DEBUG, _("%s elected for upgrade (%s => %s)"),
+ alpm_pkg_get_name(local), alpm_pkg_get_version(local),
+ alpm_pkg_get_version(spkg));
+
+ pmsyncpkg_t *syncpkg;
+ syncpkg = _alpm_sync_find(syncpkgs, alpm_pkg_get_name(local));
+
+ if(!syncpkg) {
+ pmpkg_t *dummy = _alpm_pkg_new(alpm_pkg_get_name(local),
+ alpm_pkg_get_version(local));
+ if(dummy == NULL) {
+ goto error;
+ }
+ sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, dummy);
+ if(sync == NULL) {
+ _alpm_pkg_free(dummy);
+ goto error;
+ }
+ syncpkgs = alpm_list_add(syncpkgs, sync);
+ }
+ }
+ }
+
+ return(syncpkgs);
+error:
+ if(syncpkgs) {
+ alpm_list_t *tmp;
+ for(tmp = syncpkgs; tmp; tmp = alpm_list_next(tmp)) {
+ if(tmp->data) {
+ _alpm_sync_free(tmp->data);
+ }
+ }
+ alpm_list_free(syncpkgs);
+ }
+ return(NULL);
+}
+
+/** @} */
+
pmdb_t *_alpm_db_new(const char *dbpath, const char *treename)
{
pmdb_t *db;