Fix documentation syntax and typo
[pacman-ng.git] / lib / libalpm / db.c
blobb61631a537ee8904e2820334b2e4edbc15b0e489
1 /*
2 * db.c
4 * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
7 * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
8 * Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
9 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "config.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33 #include <regex.h>
34 #include <time.h>
36 /* libalpm */
37 #include "db.h"
38 #include "alpm_list.h"
39 #include "log.h"
40 #include "util.h"
41 #include "handle.h"
42 #include "alpm.h"
43 #include "package.h"
45 struct db_operations default_db_ops = {
46 .populate = _alpm_db_populate,
47 .unregister = _alpm_db_unregister,
50 /** \addtogroup alpm_databases Database Functions
51 * @brief Functions to query and manipulate the database of libalpm
52 * @{
55 /** Register a sync database of packages.
56 * @param treename the name of the sync repository
57 * @return a pmdb_t* on success (the value), NULL on error
59 pmdb_t SYMEXPORT *alpm_db_register_sync(const char *treename)
61 ALPM_LOG_FUNC;
63 /* Sanity checks */
64 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, NULL));
65 ASSERT(treename != NULL && strlen(treename) != 0, RET_ERR(PM_ERR_WRONG_ARGS, NULL));
66 /* Do not register a database if a transaction is on-going */
67 ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, NULL));
69 return(_alpm_db_register_sync(treename));
72 /** Register the local package database.
73 * @return a pmdb_t* representing the local database, or NULL on error
75 pmdb_t SYMEXPORT *alpm_db_register_local(void)
77 ALPM_LOG_FUNC;
79 /* Sanity checks */
80 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, NULL));
81 /* Do not register a database if a transaction is on-going */
82 ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, NULL));
84 return(_alpm_db_register_local());
87 /* Helper function for alpm_db_unregister{_all} */
88 void _alpm_db_unregister(pmdb_t *db)
90 if(db == NULL) {
91 return;
94 _alpm_log(PM_LOG_DEBUG, "unregistering database '%s'\n", db->treename);
95 _alpm_db_free(db);
98 /** Unregister all package databases
99 * @return 0 on success, -1 on error (pm_errno is set accordingly)
101 int SYMEXPORT alpm_db_unregister_all(void)
103 alpm_list_t *i;
104 pmdb_t *db;
106 ALPM_LOG_FUNC;
108 /* Sanity checks */
109 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
110 /* Do not unregister a database if a transaction is on-going */
111 ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
113 /* close local database */
114 db = handle->db_local;
115 if(db) {
116 db->ops->unregister(db);
117 handle->db_local = NULL;
120 /* and also sync ones */
121 for(i = handle->dbs_sync; i; i = i->next) {
122 db = i->data;
123 db->ops->unregister(db);
124 i->data = NULL;
126 FREELIST(handle->dbs_sync);
127 return(0);
130 /** Unregister a package database
131 * @param db pointer to the package database to unregister
132 * @return 0 on success, -1 on error (pm_errno is set accordingly)
134 int SYMEXPORT alpm_db_unregister(pmdb_t *db)
136 int found = 0;
138 ALPM_LOG_FUNC;
140 /* Sanity checks */
141 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
142 ASSERT(db != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
143 /* Do not unregister a database if a transaction is on-going */
144 ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
146 if(db == handle->db_local) {
147 handle->db_local = NULL;
148 found = 1;
149 } else {
150 /* Warning : this function shouldn't be used to unregister all sync
151 * databases by walking through the list returned by
152 * alpm_option_get_syncdbs, because the db is removed from that list here.
154 void *data;
155 handle->dbs_sync = alpm_list_remove(handle->dbs_sync,
156 db, _alpm_db_cmp, &data);
157 if(data) {
158 found = 1;
162 if(!found) {
163 RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
166 db->ops->unregister(db);
167 return(0);
170 /** Set the serverlist of a database.
171 * @param db database pointer
172 * @param url url of the server
173 * @return 0 on success, -1 on error (pm_errno is set accordingly)
175 int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url)
177 alpm_list_t *i;
178 int found = 0;
179 char *newurl;
180 int len = 0;
182 ALPM_LOG_FUNC;
184 /* Sanity checks */
185 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
187 for(i = handle->dbs_sync; i && !found; i = i->next) {
188 pmdb_t *sdb = i->data;
189 if(strcmp(db->treename, sdb->treename) == 0) {
190 found = 1;
193 if(!found) {
194 RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
197 if(url) {
198 len = strlen(url);
200 if(len) {
201 newurl = strdup(url);
202 /* strip the trailing slash if one exists */
203 if(newurl[len - 1] == '/') {
204 newurl[len - 1] = '\0';
206 db->servers = alpm_list_add(db->servers, newurl);
207 _alpm_log(PM_LOG_DEBUG, "adding new server URL to database '%s': %s\n",
208 db->treename, newurl);
209 } else {
210 FREELIST(db->servers);
211 _alpm_log(PM_LOG_DEBUG, "serverlist flushed for '%s'\n", db->treename);
214 return(0);
217 /** Get the name of a package database
218 * @param db pointer to the package database
219 * @return the name of the package database, NULL on error
221 const char SYMEXPORT *alpm_db_get_name(const pmdb_t *db)
223 ALPM_LOG_FUNC;
225 /* Sanity checks */
226 ASSERT(handle != NULL, return(NULL));
227 ASSERT(db != NULL, return(NULL));
229 return db->treename;
232 /** Get a download URL for the package database
233 * @param db pointer to the package database
234 * @return a fully-specified download URL, NULL on error
236 const char SYMEXPORT *alpm_db_get_url(const pmdb_t *db)
238 char *url;
240 ALPM_LOG_FUNC;
242 /* Sanity checks */
243 ASSERT(handle != NULL, return(NULL));
244 ASSERT(db != NULL, return(NULL));
245 ASSERT(db->servers != NULL, return(NULL));
247 url = (char*)db->servers->data;
249 return(url);
253 /** Get a package entry from a package database
254 * @param db pointer to the package database to get the package from
255 * @param name of the package
256 * @return the package entry on success, NULL on error
258 pmpkg_t SYMEXPORT *alpm_db_get_pkg(pmdb_t *db, const char *name)
260 ALPM_LOG_FUNC;
262 /* Sanity checks */
263 ASSERT(handle != NULL, return(NULL));
264 ASSERT(db != NULL, return(NULL));
265 ASSERT(name != NULL && strlen(name) != 0, return(NULL));
267 return(_alpm_db_get_pkgfromcache(db, name));
270 /** Get the package cache of a package database
271 * @param db pointer to the package database to get the package from
272 * @return the list of packages on success, NULL on error
274 alpm_list_t SYMEXPORT *alpm_db_get_pkgcache(pmdb_t *db)
276 ALPM_LOG_FUNC;
278 /* Sanity checks */
279 ASSERT(handle != NULL, return(NULL));
280 ASSERT(db != NULL, return(NULL));
282 return(_alpm_db_get_pkgcache(db));
285 /** Get a group entry from a package database
286 * @param db pointer to the package database to get the group from
287 * @param name of the group
288 * @return the groups entry on success, NULL on error
290 pmgrp_t SYMEXPORT *alpm_db_readgrp(pmdb_t *db, const char *name)
292 ALPM_LOG_FUNC;
294 /* Sanity checks */
295 ASSERT(handle != NULL, return(NULL));
296 ASSERT(db != NULL, return(NULL));
297 ASSERT(name != NULL && strlen(name) != 0, return(NULL));
299 return(_alpm_db_get_grpfromcache(db, name));
302 /** Get the group cache of a package database
303 * @param db pointer to the package database to get the group from
304 * @return the list of groups on success, NULL on error
306 alpm_list_t SYMEXPORT *alpm_db_get_grpcache(pmdb_t *db)
308 ALPM_LOG_FUNC;
310 /* Sanity checks */
311 ASSERT(handle != NULL, return(NULL));
312 ASSERT(db != NULL, return(NULL));
314 return(_alpm_db_get_grpcache(db));
317 /** Searches a database
318 * @param db pointer to the package database to search in
319 * @param needles the list of strings to search for
320 * @return the list of packages on success, NULL on error
322 alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, const alpm_list_t* needles)
324 ALPM_LOG_FUNC;
326 /* Sanity checks */
327 ASSERT(handle != NULL, return(NULL));
328 ASSERT(db != NULL, return(NULL));
330 return(_alpm_db_search(db, needles));
333 /** Set install reason for a package in db
334 * @param db pointer to the package database
335 * @param name the name of the package
336 * @param reason the new install reason
337 * @return 0 on success, -1 on error (pm_errno is set accordingly)
339 int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t reason)
341 ALPM_LOG_FUNC;
343 /* Sanity checks */
344 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
345 ASSERT(db != NULL && name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
347 pmpkg_t *pkg = _alpm_db_get_pkgfromcache(db, name);
348 if(pkg == NULL) {
349 RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
352 _alpm_log(PM_LOG_DEBUG, "setting install reason %u for %s/%s\n", reason, db->treename, name);
353 /* read DESC */
354 if(_alpm_db_read(db, pkg, INFRQ_DESC)) {
355 return(-1);
357 if(pkg->reason == reason) {
358 /* we are done */
359 return(0);
361 /* set reason (in pkgcache) */
362 pkg->reason = reason;
363 /* write DESC */
364 if(_alpm_db_write(db, pkg, INFRQ_DESC)) {
365 return(-1);
368 return(0);
371 /** @} */
373 static pmdb_t *_alpm_db_new(const char *treename, int is_local)
375 pmdb_t *db;
377 ALPM_LOG_FUNC;
379 CALLOC(db, 1, sizeof(pmdb_t), RET_ERR(PM_ERR_MEMORY, NULL));
380 STRDUP(db->treename, treename, RET_ERR(PM_ERR_MEMORY, NULL));
381 db->is_local = is_local;
383 return(db);
386 void _alpm_db_free(pmdb_t *db)
388 ALPM_LOG_FUNC;
390 /* cleanup pkgcache */
391 _alpm_db_free_pkgcache(db);
392 /* cleanup server list */
393 FREELIST(db->servers);
394 FREE(db->_path);
395 FREE(db->treename);
396 FREE(db);
398 return;
401 const char *_alpm_db_path(pmdb_t *db)
403 if(!db) {
404 return(NULL);
406 if(!db->_path) {
407 const char *dbpath;
408 size_t pathsize;
410 dbpath = alpm_option_get_dbpath();
411 if(!dbpath) {
412 _alpm_log(PM_LOG_ERROR, _("database path is undefined\n"));
413 RET_ERR(PM_ERR_DB_OPEN, NULL);
416 if(db->is_local) {
417 pathsize = strlen(dbpath) + strlen(db->treename) + 2;
418 CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
419 sprintf(db->_path, "%s%s/", dbpath, db->treename);
420 } else {
421 pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 2;
422 CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
423 /* all sync DBs now reside in the sync/ subdir of the dbpath */
424 sprintf(db->_path, "%ssync/%s/", dbpath, db->treename);
426 _alpm_log(PM_LOG_DEBUG, "database path for tree %s set to %s\n",
427 db->treename, db->_path);
429 return(db->_path);
432 int _alpm_db_cmp(const void *d1, const void *d2)
434 pmdb_t *db1 = (pmdb_t *)d1;
435 pmdb_t *db2 = (pmdb_t *)d2;
436 return(strcmp(db1->treename, db2->treename));
439 alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
441 const alpm_list_t *i, *j, *k;
442 alpm_list_t *ret = NULL;
443 /* copy the pkgcache- we will free the list var after each needle */
444 alpm_list_t *list = alpm_list_copy(_alpm_db_get_pkgcache(db));
446 ALPM_LOG_FUNC;
448 for(i = needles; i; i = i->next) {
449 char *targ;
450 regex_t reg;
452 if(i->data == NULL) {
453 continue;
455 ret = NULL;
456 targ = i->data;
457 _alpm_log(PM_LOG_DEBUG, "searching for target '%s'\n", targ);
459 if(regcomp(&reg, targ, REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE) != 0) {
460 RET_ERR(PM_ERR_INVALID_REGEX, NULL);
463 for(j = list; j; j = j->next) {
464 pmpkg_t *pkg = j->data;
465 const char *matched = NULL;
466 const char *name = alpm_pkg_get_name(pkg);
467 const char *desc = alpm_pkg_get_desc(pkg);
469 /* check name as regex AND as plain text */
470 if(name && (regexec(&reg, name, 0, 0, 0) == 0 || strstr(name, targ))) {
471 matched = name;
473 /* check desc */
474 else if (desc && regexec(&reg, desc, 0, 0, 0) == 0) {
475 matched = desc;
477 /* TODO: should we be doing this, and should we print something
478 * differently when we do match it since it isn't currently printed? */
479 if(!matched) {
480 /* check provides */
481 for(k = alpm_pkg_get_provides(pkg); k; k = k->next) {
482 if (regexec(&reg, k->data, 0, 0, 0) == 0) {
483 matched = k->data;
484 break;
488 if(!matched) {
489 /* check groups */
490 for(k = alpm_pkg_get_groups(pkg); k; k = k->next) {
491 if (regexec(&reg, k->data, 0, 0, 0) == 0) {
492 matched = k->data;
493 break;
498 if(matched != NULL) {
499 _alpm_log(PM_LOG_DEBUG, " search target '%s' matched '%s'\n",
500 targ, matched);
501 ret = alpm_list_add(ret, pkg);
505 /* Free the existing search list, and use the returned list for the
506 * next needle. This allows for AND-based package searching. */
507 alpm_list_free(list);
508 list = ret;
509 regfree(&reg);
512 return(ret);
515 pmdb_t *_alpm_db_register_local(void)
517 pmdb_t *db;
519 ALPM_LOG_FUNC;
521 if(handle->db_local != NULL) {
522 _alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n"));
523 RET_ERR(PM_ERR_DB_NOT_NULL, NULL);
526 _alpm_log(PM_LOG_DEBUG, "registering local database\n");
528 db = _alpm_db_new("local", 1);
529 db->ops = &default_db_ops;
530 if(db == NULL) {
531 RET_ERR(PM_ERR_DB_CREATE, NULL);
534 handle->db_local = db;
535 return(db);
538 pmdb_t *_alpm_db_register_sync(const char *treename)
540 pmdb_t *db;
541 alpm_list_t *i;
543 ALPM_LOG_FUNC;
545 for(i = handle->dbs_sync; i; i = i->next) {
546 pmdb_t *sdb = i->data;
547 if(strcmp(treename, sdb->treename) == 0) {
548 _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
549 return sdb;
553 _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
555 db = _alpm_db_new(treename, 0);
556 db->ops = &default_db_ops;
557 if(db == NULL) {
558 RET_ERR(PM_ERR_DB_CREATE, NULL);
561 handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
562 return(db);
565 /* vim: set ts=2 sw=2 noet: */