db.c

Go to the documentation of this file.
00001 /*
00002  *  db.c
00003  *
00004  *  Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
00005  *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
00006  *  Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
00007  *  Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
00008  *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00022  */
00023 
00024 #include "config.h"
00025 
00026 #include <unistd.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <errno.h>
00030 #include <string.h>
00031 #include <stdint.h> /* uintmax_t */
00032 #include <sys/stat.h>
00033 #include <dirent.h>
00034 #include <regex.h>
00035 #include <time.h>
00036 
00037 /* libalpm */
00038 #include "db.h"
00039 #include "alpm_list.h"
00040 #include "log.h"
00041 #include "util.h"
00042 #include "error.h"
00043 #include "server.h"
00044 #include "handle.h"
00045 #include "cache.h"
00046 #include "alpm.h"
00047 
00048 /** \addtogroup alpm_databases Database Functions
00049  * @brief Functions to query and manipulate the database of libalpm
00050  * @{
00051  */
00052 
00053 /** Register a sync database of packages.
00054  * @param treename the name of the sync repository
00055  * @return a pmdb_t* on success (the value), NULL on error
00056  */
00057 pmdb_t SYMEXPORT *alpm_db_register_sync(const char *treename)
00058 {
00059     ALPM_LOG_FUNC;
00060 
00061     /* Sanity checks */
00062     ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, NULL));
00063     ASSERT(treename != NULL && strlen(treename) != 0, RET_ERR(PM_ERR_WRONG_ARGS, NULL));
00064     /* Do not register a database if a transaction is on-going */
00065     ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, NULL));
00066 
00067     return(_alpm_db_register_sync(treename));
00068 }
00069 
00070 /** Register the local package database.
00071  * @return a pmdb_t* representing the local database, or NULL on error
00072  */
00073 pmdb_t SYMEXPORT *alpm_db_register_local(void)
00074 {
00075     ALPM_LOG_FUNC;
00076 
00077     /* Sanity checks */
00078     ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, NULL));
00079     /* Do not register a database if a transaction is on-going */
00080     ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, NULL));
00081 
00082     return(_alpm_db_register_local());
00083 }
00084 
00085 /* Helper function for alpm_db_unregister{_all} */
00086 static void _alpm_db_unregister(pmdb_t *db)
00087 {
00088     if(db == NULL) {
00089         return;
00090     }
00091 
00092     _alpm_log(PM_LOG_DEBUG, "closing database '%s'\n", db->treename);
00093     _alpm_db_close(db);
00094 
00095     _alpm_log(PM_LOG_DEBUG, "unregistering database '%s'\n", db->treename);
00096     _alpm_db_free(db);
00097 }
00098 
00099 /** Unregister all package databases
00100  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00101  */
00102 int SYMEXPORT alpm_db_unregister_all(void)
00103 {
00104     alpm_list_t *i;
00105 
00106     ALPM_LOG_FUNC;
00107 
00108     /* Sanity checks */
00109     ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
00110     /* Do not unregister a database if a transaction is on-going */
00111     ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
00112 
00113     /* close local database */
00114     _alpm_db_unregister(handle->db_local);
00115     handle->db_local = NULL;
00116 
00117     /* and also sync ones */
00118     for(i = handle->dbs_sync; i; i = i->next) {
00119         pmdb_t *db = i->data;
00120         _alpm_db_unregister(db);
00121         i->data = NULL;
00122     }
00123     FREELIST(handle->dbs_sync);
00124     return(0);
00125 }
00126 
00127 /** Unregister a package database
00128  * @param db pointer to the package database to unregister
00129  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00130  */
00131 int SYMEXPORT alpm_db_unregister(pmdb_t *db)
00132 {
00133     int found = 0;
00134 
00135     ALPM_LOG_FUNC;
00136 
00137     /* Sanity checks */
00138     ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
00139     ASSERT(db != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
00140     /* Do not unregister a database if a transaction is on-going */
00141     ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
00142 
00143     if(db == handle->db_local) {
00144         handle->db_local = NULL;
00145         found = 1;
00146     } else {
00147         /* Warning : this function shouldn't be used to unregister all sync
00148          * databases by walking through the list returned by
00149          * alpm_option_get_syncdbs, because the db is removed from that list here.
00150          */
00151         void *data;
00152         handle->dbs_sync = alpm_list_remove(handle->dbs_sync,
00153                 db, _alpm_db_cmp, &data);
00154         if(data) {
00155             found = 1;
00156         }
00157     }
00158 
00159     if(!found) {
00160         RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
00161     }
00162 
00163     _alpm_db_unregister(db);
00164     return(0);
00165 }
00166 
00167 /** Set the serverlist of a database.
00168  * @param db database pointer
00169  * @param url url of the server
00170  * @return 0 on success, -1 on error (pm_errno is set accordingly)
00171  */
00172 int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url)
00173 {
00174     alpm_list_t *i;
00175     int found = 0;
00176 
00177     ALPM_LOG_FUNC;
00178 
00179     /* Sanity checks */
00180     ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
00181 
00182     for(i = handle->dbs_sync; i && !found; i = i->next) {
00183         pmdb_t *sdb = i->data;
00184         if(strcmp(db->treename, sdb->treename) == 0) {
00185             found = 1;
00186         }
00187     }
00188     if(!found) {
00189         RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
00190     }
00191 
00192     if(url && strlen(url)) {
00193         pmserver_t *server;
00194         if((server = _alpm_server_new(url)) == NULL) {
00195             /* pm_errno is set by _alpm_server_new */
00196             return(-1);
00197         }
00198         db->servers = alpm_list_add(db->servers, server);
00199         _alpm_log(PM_LOG_DEBUG, "adding new server to database '%s': protocol '%s', server '%s', path '%s'\n",
00200                             db->treename, server->s_url->scheme, server->s_url->host, server->s_url->doc);
00201     } else {
00202         FREELIST(db->servers);
00203         _alpm_log(PM_LOG_DEBUG, "serverlist flushed for '%s'\n", db->treename);
00204     }
00205 
00206     return(0);
00207 }
00208 
00209 /** Update a package database
00210  * @param force if true, then forces the update, otherwise update only in case
00211  * the database isn't up to date
00212  * @param db pointer to the package database to update
00213  * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
00214  * to date
00215  */
00216 int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
00217 {
00218     alpm_list_t *lp;
00219     char path[PATH_MAX];
00220     alpm_list_t *files = NULL;
00221     time_t newmtime = 0, lastupdate = 0;
00222     const char *dbpath;
00223     int ret;
00224 
00225     ALPM_LOG_FUNC;
00226 
00227     /* Sanity checks */
00228     ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
00229     ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
00230     /* Verify we are in a transaction.  This is done _mainly_ because we need a DB
00231      * lock - if we update without a db lock, we may kludge some other pacman
00232      * process that _has_ a lock.
00233      */
00234     ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
00235     ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
00236     ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1));
00237 
00238     if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
00239         RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
00240     }
00241 
00242     if(!force) {
00243         /* get the lastupdate time */
00244         lastupdate = _alpm_db_getlastupdate(db);
00245         if(lastupdate == 0) {
00246             _alpm_log(PM_LOG_DEBUG, "failed to get lastupdate time for %s\n",
00247                     db->treename);
00248         }
00249     }
00250 
00251     /* build a one-element list */
00252     snprintf(path, PATH_MAX, "%s" DBEXT, db->treename);
00253     files = alpm_list_add(files, strdup(path));
00254 
00255     dbpath = alpm_option_get_dbpath();
00256 
00257     ret = _alpm_downloadfiles_forreal(db->servers, dbpath, files, lastupdate,
00258             &newmtime, NULL, 0);
00259     FREELIST(files);
00260     if(ret == 1) {
00261         /* mtimes match, do nothing */
00262         pm_errno = 0;
00263         return(1);
00264     } else if(ret == -1) {
00265         /* we use downloadLastErrString and downloadLastErrCode here, error returns from
00266          * libdownload */
00267         _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s [%d]\n",
00268                 downloadLastErrString, downloadLastErrCode);
00269         RET_ERR(PM_ERR_DB_SYNC, -1);
00270     } else {
00271         if(newmtime != 0) {
00272             _alpm_log(PM_LOG_DEBUG, "sync: new mtime for %s: %ju\n",
00273                     db->treename, (uintmax_t)newmtime);
00274             _alpm_db_setlastupdate(db, newmtime);
00275         }
00276         snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename);
00277 
00278         /* remove the old dir */
00279         _alpm_log(PM_LOG_DEBUG, "flushing database %s\n", db->path);
00280         for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
00281             pmpkg_t *pkg = lp->data;
00282             if(pkg && _alpm_db_remove(db, pkg) == -1) {
00283                 _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s%s\n"), db->treename,
00284                                     alpm_pkg_get_name(pkg));
00285                 RET_ERR(PM_ERR_DB_REMOVE, -1);
00286             }
00287         }
00288 
00289         /* Cache needs to be rebuild */
00290         _alpm_db_free_pkgcache(db);
00291 
00292         /* uncompress the sync database */
00293         if(_alpm_db_install(db, path) == -1) {
00294             return -1;
00295         }
00296     }
00297 
00298     return(0);
00299 }
00300 
00301 /** Get the name of a package database
00302  * @param db pointer to the package database
00303  * @return the name of the package database, NULL on error
00304  */
00305 const char SYMEXPORT *alpm_db_get_name(const pmdb_t *db)
00306 {
00307     ALPM_LOG_FUNC;
00308 
00309     /* Sanity checks */
00310     ASSERT(handle != NULL, return(NULL));
00311     ASSERT(db != NULL, return(NULL));
00312 
00313     return db->treename;
00314 }
00315 
00316 /** Get a download URL for the package database
00317  * @param db pointer to the package database
00318  * @return a fully-specified download URL, NULL on error
00319  */
00320 const char SYMEXPORT *alpm_db_get_url(const pmdb_t *db)
00321 {
00322     char path[PATH_MAX];
00323     pmserver_t *s;
00324 
00325     ALPM_LOG_FUNC;
00326 
00327     /* Sanity checks */
00328     ASSERT(handle != NULL, return(NULL));
00329     ASSERT(db != NULL, return(NULL));
00330 
00331     s = (pmserver_t*)db->servers->data;
00332 
00333     snprintf(path, PATH_MAX, "%s://%s%s", s->s_url->scheme, s->s_url->host, s->s_url->doc);
00334     return strdup(path);
00335 }
00336 
00337 
00338 /** Get a package entry from a package database
00339  * @param db pointer to the package database to get the package from
00340  * @param name of the package
00341  * @return the package entry on success, NULL on error
00342  */
00343 pmpkg_t SYMEXPORT *alpm_db_get_pkg(pmdb_t *db, const char *name)
00344 {
00345     ALPM_LOG_FUNC;
00346 
00347     /* Sanity checks */
00348     ASSERT(handle != NULL, return(NULL));
00349     ASSERT(db != NULL, return(NULL));
00350     ASSERT(name != NULL && strlen(name) != 0, return(NULL));
00351 
00352     return(_alpm_db_get_pkgfromcache(db, name));
00353 }
00354 
00355 /** Get the package cache of a package database
00356  * @param db pointer to the package database to get the package from
00357  * @return the list of packages on success, NULL on error
00358  */
00359 alpm_list_t SYMEXPORT *alpm_db_getpkgcache(pmdb_t *db)
00360 {
00361     ALPM_LOG_FUNC;
00362 
00363     /* Sanity checks */
00364     ASSERT(handle != NULL, return(NULL));
00365     ASSERT(db != NULL, return(NULL));
00366 
00367     return(_alpm_db_get_pkgcache(db));
00368 }
00369 
00370 /** Get the list of packages that a package provides
00371  * @param db pointer to the package database to get the package from
00372  * @param name name of the package
00373  * @return the list of packages on success, NULL on error
00374  */
00375 alpm_list_t SYMEXPORT *alpm_db_whatprovides(pmdb_t *db, const char *name)
00376 {
00377     ALPM_LOG_FUNC;
00378 
00379     /* Sanity checks */
00380     ASSERT(handle != NULL, return(NULL));
00381     ASSERT(db != NULL, return(NULL));
00382     ASSERT(name != NULL && strlen(name) != 0, return(NULL));
00383 
00384     return(_alpm_db_whatprovides(db, name));
00385 }
00386 
00387 /** Get a group entry from a package database
00388  * @param db pointer to the package database to get the group from
00389  * @param name of the group
00390  * @return the groups entry on success, NULL on error
00391  */
00392 pmgrp_t SYMEXPORT *alpm_db_readgrp(pmdb_t *db, const char *name)
00393 {
00394     ALPM_LOG_FUNC;
00395 
00396     /* Sanity checks */
00397     ASSERT(handle != NULL, return(NULL));
00398     ASSERT(db != NULL, return(NULL));
00399     ASSERT(name != NULL && strlen(name) != 0, return(NULL));
00400 
00401     return(_alpm_db_get_grpfromcache(db, name));
00402 }
00403 
00404 /** Get the group cache of a package database
00405  * @param db pointer to the package database to get the group from
00406  * @return the list of groups on success, NULL on error
00407  */
00408 alpm_list_t SYMEXPORT *alpm_db_getgrpcache(pmdb_t *db)
00409 {
00410     ALPM_LOG_FUNC;
00411 
00412     /* Sanity checks */
00413     ASSERT(handle != NULL, return(NULL));
00414     ASSERT(db != NULL, return(NULL));
00415 
00416     return(_alpm_db_get_grpcache(db));
00417 }
00418 
00419 /** Searches a database
00420  * @param db pointer to the package database to search in
00421  * @param needles the list of strings to search for
00422  * @return the list of packages on success, NULL on error
00423  */
00424 alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, const alpm_list_t* needles)
00425 {
00426     ALPM_LOG_FUNC;
00427 
00428     /* Sanity checks */
00429     ASSERT(handle != NULL, return(NULL));
00430     ASSERT(db != NULL, return(NULL));
00431 
00432     return(_alpm_db_search(db, needles));
00433 }
00434 
00435 /** @} */
00436 
00437 pmdb_t *_alpm_db_new(const char *dbpath, const char *treename)
00438 {
00439     pmdb_t *db;
00440     const size_t pathsize = strlen(dbpath) + strlen(treename) + 2;
00441 
00442     ALPM_LOG_FUNC;
00443 
00444     CALLOC(db, 1, sizeof(pmdb_t), RET_ERR(PM_ERR_MEMORY, NULL));
00445     CALLOC(db->path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
00446 
00447     sprintf(db->path, "%s%s/", dbpath, treename);
00448 
00449     strncpy(db->treename, treename, PATH_MAX);
00450 
00451     return(db);
00452 }
00453 
00454 void _alpm_db_free(pmdb_t *db)
00455 {
00456     alpm_list_t *tmp;
00457 
00458     ALPM_LOG_FUNC;
00459 
00460     /* cleanup pkgcache */
00461     _alpm_db_free_pkgcache(db);
00462     /* cleanup server list */
00463     for(tmp = db->servers; tmp; tmp = alpm_list_next(tmp)) {
00464         _alpm_server_free(tmp->data);
00465     }
00466     alpm_list_free(db->servers);
00467     FREE(db->path);
00468     FREE(db);
00469 
00470     return;
00471 }
00472 
00473 int _alpm_db_cmp(const void *db1, const void *db2)
00474 {
00475     ALPM_LOG_FUNC;
00476     return(strcmp(((pmdb_t *)db1)->treename, ((pmdb_t *)db2)->treename));
00477 }
00478 
00479 alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
00480 {
00481     const alpm_list_t *i, *j, *k;
00482     alpm_list_t *ret = NULL;
00483 
00484     ALPM_LOG_FUNC;
00485 
00486     for(i = needles; i; i = i->next) {
00487         char *targ;
00488         regex_t reg;
00489 
00490         if(i->data == NULL) {
00491             continue;
00492         }
00493         targ = i->data;
00494         _alpm_log(PM_LOG_DEBUG, "searching for target '%s'\n", targ);
00495 
00496         if(regcomp(&reg, targ, REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE) != 0) {
00497             RET_ERR(PM_ERR_INVALID_REGEX, NULL);
00498         }
00499 
00500         for(j = _alpm_db_get_pkgcache(db); j; j = j->next) {
00501             pmpkg_t *pkg = j->data;
00502             const char *matched = NULL;
00503             const char *name = alpm_pkg_get_name(pkg);
00504             const char *desc = alpm_pkg_get_desc(pkg);
00505 
00506             /* check name as regex AND as plain text */
00507             if(name && (regexec(&reg, name, 0, 0, 0) == 0 || strstr(name, targ))) {
00508                 matched = name;
00509             }
00510             /* check desc */
00511             else if (desc && regexec(&reg, desc, 0, 0, 0) == 0) {
00512                 matched = desc;
00513             }
00514             /* check provides */
00515             /* TODO: should we be doing this, and should we print something
00516              * differently when we do match it since it isn't currently printed? */
00517             else {
00518                 for(k = alpm_pkg_get_provides(pkg); k; k = k->next) {
00519                     if (regexec(&reg, k->data, 0, 0, 0) == 0) {
00520                         matched = k->data;
00521                         break;
00522                     }
00523                 }
00524             }
00525 
00526             if(matched != NULL) {
00527                 _alpm_log(PM_LOG_DEBUG, "    search target '%s' matched '%s'\n",
00528                           targ, matched);
00529                 ret = alpm_list_add(ret, pkg);
00530             }
00531         }
00532 
00533         regfree(&reg);
00534     }
00535 
00536     return(ret);
00537 }
00538 
00539 pmdb_t *_alpm_db_register_local(void)
00540 {
00541     struct stat buf;
00542     pmdb_t *db;
00543     const char *dbpath;
00544     char path[PATH_MAX];
00545 
00546     ALPM_LOG_FUNC;
00547 
00548     if(handle->db_local != NULL) {
00549         _alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n"));
00550         RET_ERR(PM_ERR_DB_NOT_NULL, NULL);
00551     }
00552 
00553     _alpm_log(PM_LOG_DEBUG, "registering local database\n");
00554 
00555     /* make sure the database directory exists */
00556     dbpath = alpm_option_get_dbpath();
00557     if(!dbpath) {
00558         _alpm_log(PM_LOG_ERROR, _("database path is undefined\n"));
00559             RET_ERR(PM_ERR_DB_OPEN, NULL);
00560     }
00561     snprintf(path, PATH_MAX, "%slocal", dbpath);
00562     /* TODO this is rediculous, we try to do this even if we can't */
00563     if(stat(path, &buf) != 0 || !S_ISDIR(buf.st_mode)) {
00564         _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
00565                 path);
00566         if(_alpm_makepath(path) != 0) {
00567             RET_ERR(PM_ERR_SYSTEM, NULL);
00568         }
00569     }
00570 
00571     db = _alpm_db_new(dbpath, "local");
00572     if(db == NULL) {
00573         RET_ERR(PM_ERR_DB_CREATE, NULL);
00574     }
00575 
00576     _alpm_log(PM_LOG_DEBUG, "opening database '%s'\n", db->treename);
00577     if(_alpm_db_open(db) == -1) {
00578         _alpm_db_free(db);
00579         RET_ERR(PM_ERR_DB_OPEN, NULL);
00580     }
00581 
00582     handle->db_local = db;
00583     return(db);
00584 }
00585 
00586 pmdb_t *_alpm_db_register_sync(const char *treename)
00587 {
00588     struct stat buf;
00589     pmdb_t *db;
00590     const char *dbpath;
00591     char path[PATH_MAX];
00592     alpm_list_t *i;
00593 
00594     ALPM_LOG_FUNC;
00595 
00596     for(i = handle->dbs_sync; i; i = i->next) {
00597         pmdb_t *sdb = i->data;
00598         if(strcmp(treename, sdb->treename) == 0) {
00599             _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
00600             return sdb;
00601         }
00602     }
00603 
00604     _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
00605 
00606     /* make sure the database directory exists */
00607     dbpath = alpm_option_get_dbpath();
00608     if(!dbpath) {
00609         _alpm_log(PM_LOG_ERROR, _("database path is undefined\n"));
00610             RET_ERR(PM_ERR_DB_OPEN, NULL);
00611     }
00612     /* all sync DBs now reside in the sync/ subdir of the dbpath */
00613     snprintf(path, PATH_MAX, "%ssync/%s", dbpath, treename);
00614     /* TODO this is rediculous, we try to do this even if we can't */
00615     if(stat(path, &buf) != 0 || !S_ISDIR(buf.st_mode)) {
00616         _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
00617                 path);
00618         if(_alpm_makepath(path) != 0) {
00619             RET_ERR(PM_ERR_SYSTEM, NULL);
00620         }
00621     }
00622 
00623     /* Ensure the db gets the real path. */
00624     path[0] = '\0';
00625     snprintf(path, PATH_MAX, "%ssync/", dbpath);
00626 
00627     db = _alpm_db_new(path, treename);
00628     if(db == NULL) {
00629         RET_ERR(PM_ERR_DB_CREATE, NULL);
00630     }
00631 
00632     _alpm_log(PM_LOG_DEBUG, "opening database '%s'\n", db->treename);
00633     if(_alpm_db_open(db) == -1) {
00634         _alpm_db_free(db);
00635         RET_ERR(PM_ERR_DB_OPEN, NULL);
00636     }
00637 
00638     handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
00639     return(db);
00640 }
00641 
00642 /* helper function for alpm_list_find and _alpm_db_whatprovides
00643  *
00644  * @return "provision.name" == needle (as string)
00645  */
00646 int _alpm_prov_cmp(const void *provision, const void *needle)
00647 {
00648     char *tmpptr;
00649     char *provname = strdup(provision);
00650     int retval = 0;
00651     tmpptr = strchr(provname, '=');
00652 
00653     if(tmpptr != NULL) { /* provision-version */
00654         *tmpptr='\0';
00655     }
00656     retval = strcmp(provname, needle);
00657     free(provname);
00658     return(retval);
00659 }
00660 
00661 /* return a alpm_list_t of packages in "db" that provide "package"
00662  */
00663 alpm_list_t *_alpm_db_whatprovides(pmdb_t *db, const char *package)
00664 {
00665     alpm_list_t *pkgs = NULL;
00666     alpm_list_t *lp;
00667 
00668     ALPM_LOG_FUNC;
00669 
00670     if(db == NULL || package == NULL || strlen(package) == 0) {
00671         return(NULL);
00672     }
00673 
00674     for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
00675         pmpkg_t *info = lp->data;
00676 
00677         if(alpm_list_find(alpm_pkg_get_provides(info), (const void *)package, _alpm_prov_cmp)) {
00678             pkgs = alpm_list_add(pkgs, info);
00679         }
00680     }
00681 
00682     return(pkgs);
00683 }
00684 
00685 /* vim: set ts=2 sw=2 noet: */

Generated on Mon Jan 14 23:53:40 2008 for libalpm by  doxygen 1.5.4