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/>.
38 #include "alpm_list.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
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
)
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)
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
)
94 _alpm_log(PM_LOG_DEBUG
, "unregistering database '%s'\n", db
->treename
);
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)
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
;
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
) {
123 db
->ops
->unregister(db
);
126 FREELIST(handle
->dbs_sync
);
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
)
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
;
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.
155 handle
->dbs_sync
= alpm_list_remove(handle
->dbs_sync
,
156 db
, _alpm_db_cmp
, &data
);
163 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
166 db
->ops
->unregister(db
);
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
)
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) {
194 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
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
);
210 FREELIST(db
->servers
);
211 _alpm_log(PM_LOG_DEBUG
, "serverlist flushed for '%s'\n", db
->treename
);
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
)
226 ASSERT(handle
!= NULL
, return(NULL
));
227 ASSERT(db
!= NULL
, return(NULL
));
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
)
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
;
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
)
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
)
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
)
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
)
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
)
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
)
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
);
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
);
354 if(_alpm_db_read(db
, pkg
, INFRQ_DESC
)) {
357 if(pkg
->reason
== reason
) {
361 /* set reason (in pkgcache) */
362 pkg
->reason
= reason
;
364 if(_alpm_db_write(db
, pkg
, INFRQ_DESC
)) {
373 static pmdb_t
*_alpm_db_new(const char *treename
, int is_local
)
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
;
386 void _alpm_db_free(pmdb_t
*db
)
390 /* cleanup pkgcache */
391 _alpm_db_free_pkgcache(db
);
392 /* cleanup server list */
393 FREELIST(db
->servers
);
401 const char *_alpm_db_path(pmdb_t
*db
)
410 dbpath
= alpm_option_get_dbpath();
412 _alpm_log(PM_LOG_ERROR
, _("database path is undefined\n"));
413 RET_ERR(PM_ERR_DB_OPEN
, NULL
);
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
);
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
);
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
));
448 for(i
= needles
; i
; i
= i
->next
) {
452 if(i
->data
== NULL
) {
457 _alpm_log(PM_LOG_DEBUG
, "searching for target '%s'\n", targ
);
459 if(regcomp(®
, 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(®
, name
, 0, 0, 0) == 0 || strstr(name
, targ
))) {
474 else if (desc
&& regexec(®
, desc
, 0, 0, 0) == 0) {
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? */
481 for(k
= alpm_pkg_get_provides(pkg
); k
; k
= k
->next
) {
482 if (regexec(®
, k
->data
, 0, 0, 0) == 0) {
490 for(k
= alpm_pkg_get_groups(pkg
); k
; k
= k
->next
) {
491 if (regexec(®
, k
->data
, 0, 0, 0) == 0) {
498 if(matched
!= NULL
) {
499 _alpm_log(PM_LOG_DEBUG
, " search target '%s' matched '%s'\n",
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
);
515 pmdb_t
*_alpm_db_register_local(void)
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
;
531 RET_ERR(PM_ERR_DB_CREATE
, NULL
);
534 handle
->db_local
= db
;
538 pmdb_t
*_alpm_db_register_sync(const char *treename
)
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
);
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
;
558 RET_ERR(PM_ERR_DB_CREATE
, NULL
);
561 handle
->dbs_sync
= alpm_list_add(handle
->dbs_sync
, db
);
566 int splitname(const char *target
, pmpkg_t
*pkg
)
568 /* the format of a db entry is as follows:
569 * package-version-rel/
570 * package name can contain hyphens, so parse from the back- go back
571 * two hyphens and we have split the version from the name.
575 if(target
== NULL
|| pkg
== NULL
) {
578 STRDUP(tmp
, target
, RET_ERR(PM_ERR_MEMORY
, -1));
579 p
= tmp
+ strlen(tmp
);
581 /* do the magic parsing- find the beginning of the version string
582 * by doing two iterations of same loop to lop off two hyphens */
583 for(q
= --p
; *q
&& *q
!= '-'; q
--);
584 for(p
= --q
; *p
&& *p
!= '-'; p
--);
585 if(*p
!= '-' || p
== tmp
) {
589 /* copy into fields and return */
593 STRDUP(pkg
->version
, p
+1, RET_ERR(PM_ERR_MEMORY
, -1));
594 /* insert a terminator at the end of the name (on hyphen)- then copy it */
599 STRDUP(pkg
->name
, tmp
, RET_ERR(PM_ERR_MEMORY
, -1));
606 /* TODO: move these two functions to be_local once be_sync no longer uses them */
608 int checkdbdir(pmdb_t
*db
)
611 const char *path
= _alpm_db_path(db
);
613 if(stat(path
, &buf
) != 0) {
614 _alpm_log(PM_LOG_DEBUG
, "database dir '%s' does not exist, creating it\n",
616 if(_alpm_makepath(path
) != 0) {
617 RET_ERR(PM_ERR_SYSTEM
, -1);
619 } else if(!S_ISDIR(buf
.st_mode
)) {
620 _alpm_log(PM_LOG_WARNING
, _("removing invalid database: %s\n"), path
);
621 if(unlink(path
) != 0 || _alpm_makepath(path
) != 0) {
622 RET_ERR(PM_ERR_SYSTEM
, -1);
628 /* Note: the return value must be freed by the caller */
629 char *get_pkgpath(pmdb_t
*db
, pmpkg_t
*info
)
635 dbpath
= _alpm_db_path(db
);
636 len
= strlen(dbpath
) + strlen(info
->name
) + strlen(info
->version
) + 3;
637 MALLOC(pkgpath
, len
, RET_ERR(PM_ERR_MEMORY
, NULL
));
638 sprintf(pkgpath
, "%s%s-%s/", dbpath
, info
->name
, info
->version
);
642 /* vim: set ts=2 sw=2 noet: */