4 * Copyright (c) 2006-2011 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/>.
37 #include "alpm_list.h"
45 /** \addtogroup alpm_databases Database Functions
46 * @brief Functions to query and manipulate the database of libalpm
50 /** Register a sync database of packages. */
51 pmdb_t SYMEXPORT
*alpm_db_register_sync(const char *treename
)
56 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, NULL
));
57 ASSERT(treename
!= NULL
&& strlen(treename
) != 0, RET_ERR(PM_ERR_WRONG_ARGS
, NULL
));
58 /* Do not register a database if a transaction is on-going */
59 ASSERT(handle
->trans
== NULL
, RET_ERR(PM_ERR_TRANS_NOT_NULL
, NULL
));
61 return _alpm_db_register_sync(treename
);
64 /* Helper function for alpm_db_unregister{_all} */
65 void _alpm_db_unregister(pmdb_t
*db
)
71 _alpm_log(PM_LOG_DEBUG
, "unregistering database '%s'\n", db
->treename
);
75 /** Unregister all package databases. */
76 int SYMEXPORT
alpm_db_unregister_all(void)
84 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
85 /* Do not unregister a database if a transaction is on-going */
86 ASSERT(handle
->trans
== NULL
, RET_ERR(PM_ERR_TRANS_NOT_NULL
, -1));
88 /* unregister all sync dbs */
89 for(i
= handle
->dbs_sync
; i
; i
= i
->next
) {
91 db
->ops
->unregister(db
);
94 FREELIST(handle
->dbs_sync
);
98 /** Unregister a package database. */
99 int SYMEXPORT
alpm_db_unregister(pmdb_t
*db
)
106 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
107 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
108 /* Do not unregister a database if a transaction is on-going */
109 ASSERT(handle
->trans
== NULL
, RET_ERR(PM_ERR_TRANS_NOT_NULL
, -1));
111 if(db
== handle
->db_local
) {
112 handle
->db_local
= NULL
;
115 /* Warning : this function shouldn't be used to unregister all sync
116 * databases by walking through the list returned by
117 * alpm_option_get_syncdbs, because the db is removed from that list here.
120 handle
->dbs_sync
= alpm_list_remove(handle
->dbs_sync
,
121 db
, _alpm_db_cmp
, &data
);
128 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
131 db
->ops
->unregister(db
);
135 /** Set the serverlist of a database. */
136 int SYMEXPORT
alpm_db_setserver(pmdb_t
*db
, const char *url
)
144 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_DB_NULL
, -1));
150 newurl
= strdup(url
);
151 /* strip the trailing slash if one exists */
152 if(newurl
[len
- 1] == '/') {
153 newurl
[len
- 1] = '\0';
155 db
->servers
= alpm_list_add(db
->servers
, newurl
);
156 _alpm_log(PM_LOG_DEBUG
, "adding new server URL to database '%s': %s\n",
157 db
->treename
, newurl
);
159 FREELIST(db
->servers
);
160 _alpm_log(PM_LOG_DEBUG
, "serverlist flushed for '%s'\n", db
->treename
);
165 /** Set the verify gpg signature option for a database.
166 * @param db database pointer
167 * @param verify enum pgp_verify_t
168 * @return 0 on success, -1 on error (pm_errno is set accordingly)
170 int SYMEXPORT
alpm_db_set_pgp_verify(pmdb_t
*db
, pgp_verify_t verify
)
175 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_DB_NULL
, -1));
177 db
->pgp_verify
= verify
;
178 _alpm_log(PM_LOG_DEBUG
, "adding VerifySig option to database '%s': %d\n",
179 db
->treename
, verify
);
184 /** Get the name of a package database. */
185 const char SYMEXPORT
*alpm_db_get_name(const pmdb_t
*db
)
190 ASSERT(handle
!= NULL
, return NULL
);
191 ASSERT(db
!= NULL
, return NULL
);
196 /** Get a download URL for the package database. */
197 const char SYMEXPORT
*alpm_db_get_url(const pmdb_t
*db
)
204 ASSERT(handle
!= NULL
, return NULL
);
205 ASSERT(db
!= NULL
, return NULL
);
206 ASSERT(db
->servers
!= NULL
, return NULL
);
208 url
= (char*)db
->servers
->data
;
214 /** Get a package entry from a package database. */
215 pmpkg_t SYMEXPORT
*alpm_db_get_pkg(pmdb_t
*db
, const char *name
)
220 ASSERT(handle
!= NULL
, return NULL
);
221 ASSERT(db
!= NULL
, return NULL
);
222 ASSERT(name
!= NULL
&& strlen(name
) != 0, return NULL
);
224 return _alpm_db_get_pkgfromcache(db
, name
);
227 /** Get the package cache of a package database. */
228 alpm_list_t SYMEXPORT
*alpm_db_get_pkgcache(pmdb_t
*db
)
233 ASSERT(handle
!= NULL
, return NULL
);
234 ASSERT(db
!= NULL
, return NULL
);
236 return _alpm_db_get_pkgcache(db
);
239 /** Get a group entry from a package database. */
240 pmgrp_t SYMEXPORT
*alpm_db_readgrp(pmdb_t
*db
, const char *name
)
245 ASSERT(handle
!= NULL
, return NULL
);
246 ASSERT(db
!= NULL
, return NULL
);
247 ASSERT(name
!= NULL
&& strlen(name
) != 0, return NULL
);
249 return _alpm_db_get_grpfromcache(db
, name
);
252 /** Get the group cache of a package database. */
253 alpm_list_t SYMEXPORT
*alpm_db_get_grpcache(pmdb_t
*db
)
258 ASSERT(handle
!= NULL
, return NULL
);
259 ASSERT(db
!= NULL
, return NULL
);
261 return _alpm_db_get_grpcache(db
);
264 /** Searches a database. */
265 alpm_list_t SYMEXPORT
*alpm_db_search(pmdb_t
*db
, const alpm_list_t
* needles
)
270 ASSERT(handle
!= NULL
, return NULL
);
271 ASSERT(db
!= NULL
, return NULL
);
273 return _alpm_db_search(db
, needles
);
276 /** Set install reason for a package in db. */
277 int SYMEXPORT
alpm_db_set_pkgreason(pmdb_t
*db
, const char *name
, pmpkgreason_t reason
)
282 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
283 ASSERT(db
!= NULL
&& name
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
285 pmpkg_t
*pkg
= _alpm_db_get_pkgfromcache(db
, name
);
287 RET_ERR(PM_ERR_PKG_NOT_FOUND
, -1);
290 _alpm_log(PM_LOG_DEBUG
, "setting install reason %u for %s/%s\n", reason
, db
->treename
, name
);
291 if(alpm_pkg_get_reason(pkg
) == reason
) {
295 /* set reason (in pkgcache) */
296 pkg
->reason
= reason
;
298 if(_alpm_local_db_write(db
, pkg
, INFRQ_DESC
)) {
299 RET_ERR(PM_ERR_DB_WRITE
, -1);
307 pmdb_t
*_alpm_db_new(const char *treename
, int is_local
)
313 CALLOC(db
, 1, sizeof(pmdb_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
314 STRDUP(db
->treename
, treename
, RET_ERR(PM_ERR_MEMORY
, NULL
));
315 db
->is_local
= is_local
;
320 const pmpgpsig_t
*_alpm_db_pgpsig(pmdb_t
*db
)
325 ASSERT(db
!= NULL
, return(NULL
));
327 if(db
->pgpsig
.rawdata
== NULL
) {
333 dbfile
= _alpm_db_path(db
);
334 len
= strlen(dbfile
) + 5;
335 MALLOC(sigfile
, len
, RET_ERR(PM_ERR_MEMORY
, NULL
));
336 sprintf(sigfile
, "%s.sig", dbfile
);
338 /* TODO: do something with ret value */
339 ret
= _alpm_load_signature(sigfile
, &(db
->pgpsig
));
345 return &(db
->pgpsig
);
348 void _alpm_db_free(pmdb_t
*db
)
352 /* cleanup pkgcache */
353 _alpm_db_free_pkgcache(db
);
354 /* cleanup server list */
355 FREELIST(db
->servers
);
356 /* only need to free rawdata */
357 FREE(db
->pgpsig
.rawdata
);
365 const char *_alpm_db_path(pmdb_t
*db
)
374 dbpath
= alpm_option_get_dbpath();
376 _alpm_log(PM_LOG_ERROR
, _("database path is undefined\n"));
377 RET_ERR(PM_ERR_DB_OPEN
, NULL
);
381 pathsize
= strlen(dbpath
) + strlen(db
->treename
) + 2;
382 CALLOC(db
->_path
, 1, pathsize
, RET_ERR(PM_ERR_MEMORY
, NULL
));
383 sprintf(db
->_path
, "%s%s/", dbpath
, db
->treename
);
385 pathsize
= strlen(dbpath
) + 5 + strlen(db
->treename
) + 4;
386 CALLOC(db
->_path
, 1, pathsize
, RET_ERR(PM_ERR_MEMORY
, NULL
));
387 /* all sync DBs now reside in the sync/ subdir of the dbpath */
388 sprintf(db
->_path
, "%ssync/%s.db", dbpath
, db
->treename
);
390 _alpm_log(PM_LOG_DEBUG
, "database path for tree %s set to %s\n",
391 db
->treename
, db
->_path
);
396 int _alpm_db_version(pmdb_t
*db
)
401 return db
->ops
->version(db
);
404 int _alpm_db_cmp(const void *d1
, const void *d2
)
406 pmdb_t
*db1
= (pmdb_t
*)d1
;
407 pmdb_t
*db2
= (pmdb_t
*)d2
;
408 return strcmp(db1
->treename
, db2
->treename
);
411 alpm_list_t
*_alpm_db_search(pmdb_t
*db
, const alpm_list_t
*needles
)
413 const alpm_list_t
*i
, *j
, *k
;
414 alpm_list_t
*ret
= NULL
;
415 /* copy the pkgcache- we will free the list var after each needle */
416 alpm_list_t
*list
= alpm_list_copy(_alpm_db_get_pkgcache(db
));
420 for(i
= needles
; i
; i
= i
->next
) {
424 if(i
->data
== NULL
) {
429 _alpm_log(PM_LOG_DEBUG
, "searching for target '%s'\n", targ
);
431 if(regcomp(®
, targ
, REG_EXTENDED
| REG_NOSUB
| REG_ICASE
| REG_NEWLINE
) != 0) {
432 RET_ERR(PM_ERR_INVALID_REGEX
, NULL
);
435 for(j
= list
; j
; j
= j
->next
) {
436 pmpkg_t
*pkg
= j
->data
;
437 const char *matched
= NULL
;
438 const char *name
= alpm_pkg_get_name(pkg
);
439 const char *desc
= alpm_pkg_get_desc(pkg
);
441 /* check name as regex AND as plain text */
442 if(name
&& (regexec(®
, name
, 0, 0, 0) == 0 || strstr(name
, targ
))) {
446 else if (desc
&& regexec(®
, desc
, 0, 0, 0) == 0) {
449 /* TODO: should we be doing this, and should we print something
450 * differently when we do match it since it isn't currently printed? */
453 for(k
= alpm_pkg_get_provides(pkg
); k
; k
= k
->next
) {
454 if (regexec(®
, k
->data
, 0, 0, 0) == 0) {
462 for(k
= alpm_pkg_get_groups(pkg
); k
; k
= k
->next
) {
463 if (regexec(®
, k
->data
, 0, 0, 0) == 0) {
470 if(matched
!= NULL
) {
471 _alpm_log(PM_LOG_DEBUG
, " search target '%s' matched '%s'\n",
473 ret
= alpm_list_add(ret
, pkg
);
477 /* Free the existing search list, and use the returned list for the
478 * next needle. This allows for AND-based package searching. */
479 alpm_list_free(list
);
487 /* Returns a new package cache from db.
488 * It frees the cache if it already exists.
490 int _alpm_db_load_pkgcache(pmdb_t
*db
)
497 _alpm_db_free_pkgcache(db
);
499 _alpm_log(PM_LOG_DEBUG
, "loading package cache for repository '%s'\n",
501 if(db
->ops
->populate(db
) == -1) {
502 _alpm_log(PM_LOG_DEBUG
,
503 "failed to load package cache for repository '%s'\n", db
->treename
);
507 db
->pkgcache_loaded
= 1;
511 void _alpm_db_free_pkgcache(pmdb_t
*db
)
515 if(db
== NULL
|| !db
->pkgcache_loaded
) {
519 _alpm_log(PM_LOG_DEBUG
, "freeing package cache for repository '%s'\n",
522 alpm_list_free_inner(_alpm_db_get_pkgcache(db
),
523 (alpm_list_fn_free
)_alpm_pkg_free
);
524 _alpm_pkghash_free(db
->pkgcache
);
525 db
->pkgcache_loaded
= 0;
527 _alpm_db_free_grpcache(db
);
530 pmpkghash_t
*_alpm_db_get_pkgcache_hash(pmdb_t
*db
)
538 if(!db
->pkgcache_loaded
) {
539 _alpm_db_load_pkgcache(db
);
542 /* hmmm, still NULL ?*/
544 _alpm_log(PM_LOG_DEBUG
, "warning: pkgcache is NULL for db '%s'\n", db
->treename
);
550 alpm_list_t
*_alpm_db_get_pkgcache(pmdb_t
*db
)
554 pmpkghash_t
*hash
= _alpm_db_get_pkgcache_hash(db
);
563 /* "duplicate" pkg then add it to pkgcache */
564 int _alpm_db_add_pkgincache(pmdb_t
*db
, pmpkg_t
*pkg
)
570 if(db
== NULL
|| !db
->pkgcache_loaded
|| pkg
== NULL
) {
574 newpkg
= _alpm_pkg_dup(pkg
);
579 _alpm_log(PM_LOG_DEBUG
, "adding entry '%s' in '%s' cache\n",
580 alpm_pkg_get_name(newpkg
), db
->treename
);
581 db
->pkgcache
= _alpm_pkghash_add_sorted(db
->pkgcache
, newpkg
);
583 _alpm_db_free_grpcache(db
);
588 int _alpm_db_remove_pkgfromcache(pmdb_t
*db
, pmpkg_t
*pkg
)
590 pmpkg_t
*data
= NULL
;
594 if(db
== NULL
|| !db
->pkgcache_loaded
|| pkg
== NULL
) {
598 _alpm_log(PM_LOG_DEBUG
, "removing entry '%s' from '%s' cache\n",
599 alpm_pkg_get_name(pkg
), db
->treename
);
601 db
->pkgcache
= _alpm_pkghash_remove(db
->pkgcache
, pkg
, &data
);
603 /* package not found */
604 _alpm_log(PM_LOG_DEBUG
, "cannot remove entry '%s' from '%s' cache: not found\n",
605 alpm_pkg_get_name(pkg
), db
->treename
);
609 _alpm_pkg_free(data
);
611 _alpm_db_free_grpcache(db
);
616 pmpkg_t
*_alpm_db_get_pkgfromcache(pmdb_t
*db
, const char *target
)
624 pmpkghash_t
*pkgcache
= _alpm_db_get_pkgcache_hash(db
);
626 _alpm_log(PM_LOG_DEBUG
, "warning: failed to get '%s' from NULL pkgcache\n",
631 return _alpm_pkghash_find(pkgcache
, target
);
634 /* Returns a new group cache from db.
636 int _alpm_db_load_grpcache(pmdb_t
*db
)
646 _alpm_log(PM_LOG_DEBUG
, "loading group cache for repository '%s'\n",
649 for(lp
= _alpm_db_get_pkgcache(db
); lp
; lp
= lp
->next
) {
650 const alpm_list_t
*i
;
651 pmpkg_t
*pkg
= lp
->data
;
653 for(i
= alpm_pkg_get_groups(pkg
); i
; i
= i
->next
) {
654 const char *grpname
= i
->data
;
659 /* first look through the group cache for a group with this name */
660 for(j
= db
->grpcache
; j
; j
= j
->next
) {
663 if(strcmp(grp
->name
, grpname
) == 0
664 && !alpm_list_find_ptr(grp
->packages
, pkg
)) {
665 grp
->packages
= alpm_list_add(grp
->packages
, pkg
);
673 /* we didn't find the group, so create a new one with this name */
674 grp
= _alpm_grp_new(grpname
);
675 grp
->packages
= alpm_list_add(grp
->packages
, pkg
);
676 db
->grpcache
= alpm_list_add(db
->grpcache
, grp
);
680 db
->grpcache_loaded
= 1;
684 void _alpm_db_free_grpcache(pmdb_t
*db
)
690 if(db
== NULL
|| !db
->grpcache_loaded
) {
694 _alpm_log(PM_LOG_DEBUG
, "freeing group cache for repository '%s'\n",
697 for(lg
= db
->grpcache
; lg
; lg
= lg
->next
) {
698 _alpm_grp_free(lg
->data
);
701 FREELIST(db
->grpcache
);
702 db
->grpcache_loaded
= 0;
705 alpm_list_t
*_alpm_db_get_grpcache(pmdb_t
*db
)
713 if(!db
->grpcache_loaded
) {
714 _alpm_db_load_grpcache(db
);
720 pmgrp_t
*_alpm_db_get_grpfromcache(pmdb_t
*db
, const char *target
)
726 if(db
== NULL
|| target
== NULL
|| strlen(target
) == 0) {
730 for(i
= _alpm_db_get_grpcache(db
); i
; i
= i
->next
) {
731 pmgrp_t
*info
= i
->data
;
733 if(strcmp(info
->name
, target
) == 0) {
741 /* vim: set ts=2 sw=2 noet: */