4 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
5 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
6 * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
7 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33 #include <sys/types.h>
38 #include <limits.h> /* PATH_MAX */
44 #include "alpm_list.h"
47 #include "versioncmp.h"
65 #define min(X, Y) ((X) < (Y) ? (X) : (Y))
68 pmhandle_t
*handle
= NULL
;
69 enum _pmerrno_t pm_errno SYMEXPORT
;
71 /** \addtogroup alpm_interface Interface Functions
72 * @brief Functions to initialize and release libalpm
76 /** Initializes the library. This must be called before any other
77 * functions are called.
78 * @return 0 on success, -1 on error (pm_errno is set accordingly)
80 int SYMEXPORT
alpm_initialize()
82 ASSERT(handle
== NULL
, RET_ERR(PM_ERR_HANDLE_NOT_NULL
, -1));
84 handle
= _alpm_handle_new();
86 RET_ERR(PM_ERR_MEMORY
, -1);
92 /** Release the library. This should be the last alpm call you make.
93 * @return 0 on success, -1 on error (pm_errno is set accordingly)
95 int SYMEXPORT
alpm_release()
101 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
103 /* free the transaction if there is any */
105 alpm_trans_release();
108 /* close local database */
109 if(handle
->db_local
) {
110 alpm_db_unregister(handle
->db_local
);
111 handle
->db_local
= NULL
;
113 /* and also sync ones */
114 while((dbs_left
= alpm_list_count(handle
->dbs_sync
)) > 0) {
115 pmdb_t
*db
= (pmdb_t
*)handle
->dbs_sync
->data
;
116 _alpm_log(PM_LOG_DEBUG
, _("removing DB %s, %d remaining..."), db
->treename
, dbs_left
);
117 alpm_db_unregister(db
);
128 /** \addtogroup alpm_databases Database Functions
129 * @brief Functions to query and manipulate the database of libalpm
133 /** Register a package database
134 * @param treename the name of the repository
135 * @return a pmdb_t* on success (the value), NULL on error
137 pmdb_t SYMEXPORT
*alpm_db_register(char *treename
)
142 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, NULL
));
143 ASSERT(treename
!= NULL
&& strlen(treename
) != 0, RET_ERR(PM_ERR_WRONG_ARGS
, NULL
));
144 /* Do not register a database if a transaction is on-going */
145 ASSERT(handle
->trans
== NULL
, RET_ERR(PM_ERR_TRANS_NOT_NULL
, NULL
));
147 return(_alpm_db_register(treename
, NULL
));
150 /** Unregister a package database
151 * @param db pointer to the package database to unregister
152 * @return 0 on success, -1 on error (pm_errno is set accordingly)
154 int alpm_db_unregister(pmdb_t
*db
)
161 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
162 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
163 /* Do not unregister a database if a transaction is on-going */
164 ASSERT(handle
->trans
== NULL
, RET_ERR(PM_ERR_TRANS_NOT_NULL
, -1));
166 if(db
== handle
->db_local
) {
167 handle
->db_local
= NULL
;
171 handle
->dbs_sync
= alpm_list_remove(handle
->dbs_sync
, db
, _alpm_db_cmp
, &data
);
178 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
181 _alpm_log(PM_LOG_DEBUG
, _("unregistering database '%s'"), db
->treename
);
184 _alpm_db_free_pkgcache(db
);
186 _alpm_log(PM_LOG_DEBUG
, _("closing database '%s'"), db
->treename
);
194 /** Set the serverlist of a database.
195 * @param db database pointer
196 * @param url url of the server
197 * @return 0 on success, -1 on error (pm_errno is set accordingly)
199 int alpm_db_setserver(pmdb_t
*db
, const char *url
)
206 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_DB_NULL
, -1));
208 if(strcmp(db
->treename
, "local") == 0) {
209 if(handle
->db_local
!= NULL
) {
214 for(i
= handle
->dbs_sync
; i
&& !found
; i
= i
->next
) {
215 pmdb_t
*sdb
= i
->data
;
216 if(strcmp(db
->treename
, sdb
->treename
) == 0) {
222 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
225 if(url
&& strlen(url
)) {
227 if((server
= _alpm_server_new(url
)) == NULL
) {
228 /* pm_errno is set by _alpm_server_new */
231 db
->servers
= alpm_list_add(db
->servers
, server
);
232 _alpm_log(PM_LOG_DEBUG
, _("adding new server to database '%s': protocol '%s', server '%s', path '%s'"),
233 db
->treename
, server
->s_url
->scheme
, server
->s_url
->host
, server
->s_url
->doc
);
235 FREELIST(db
->servers
);
236 _alpm_log(PM_LOG_DEBUG
, _("serverlist flushed for '%s'"), db
->treename
);
242 /** Update a package database
243 * @param force if true, then forces the update, otherwise update only in case
244 * the database isn't up to date
245 * @param db pointer to the package database to update
246 * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
249 int SYMEXPORT
alpm_db_update(int force
, pmdb_t
*db
)
253 alpm_list_t
*files
= NULL
;
254 char newmtime
[16] = "";
255 char lastupdate
[16] = "";
261 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
262 ASSERT(db
!= NULL
&& db
!= handle
->db_local
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
263 /* Verify we are in a transaction. This is done _mainly_ because we need a DB
264 * lock - if we update without a db lock, we may kludge some other pacman
265 * process that _has_ a lock.
267 ASSERT(handle
->trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
268 ASSERT(handle
->trans
->state
== STATE_INITIALIZED
, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED
, -1));
269 ASSERT(handle
->trans
->type
== PM_TRANS_TYPE_SYNC
, RET_ERR(PM_ERR_TRANS_TYPE
, -1));
271 if(!alpm_list_find(handle
->dbs_sync
, db
)) {
272 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
276 /* get the lastupdate time */
277 _alpm_db_getlastupdate(db
, lastupdate
);
278 if(strlen(lastupdate
) == 0) {
279 _alpm_log(PM_LOG_DEBUG
, _("failed to get lastupdate time for %s (no big deal)"), db
->treename
);
283 /* build a one-element list */
284 snprintf(path
, PATH_MAX
, "%s" PM_EXT_DB
, db
->treename
);
285 files
= alpm_list_add(files
, strdup(path
));
287 snprintf(path
, PATH_MAX
, "%s%s", handle
->root
, handle
->dbpath
);
289 ret
= _alpm_downloadfiles_forreal(db
->servers
, path
, files
, lastupdate
, newmtime
);
292 /* mtimes match, do nothing */
295 } else if(ret
== -1) {
296 /* we use downloadLastErrString and downloadLastErrCode here, error returns from
298 _alpm_log(PM_LOG_DEBUG
, _("failed to sync db: %s [%d]"), downloadLastErrString
, downloadLastErrCode
);
299 RET_ERR(PM_ERR_DB_SYNC
, -1);
301 if(strlen(newmtime
)) {
302 _alpm_log(PM_LOG_DEBUG
, _("sync: new mtime for %s: %s"), db
->treename
, newmtime
);
303 _alpm_db_setlastupdate(db
, newmtime
);
305 snprintf(path
, PATH_MAX
, "%s%s%s" PM_EXT_DB
, handle
->root
, handle
->dbpath
, db
->treename
);
307 /* remove the old dir */
308 _alpm_log(PM_LOG_DEBUG
, _("flushing database %s%s"), db
->path
);
309 for(lp
= _alpm_db_get_pkgcache(db
); lp
; lp
= lp
->next
) {
310 pmpkg_t
*pkg
= lp
->data
;
311 if(pkg
&& _alpm_db_remove(db
, pkg
) == -1) {
312 _alpm_log(PM_LOG_ERROR
, _("could not remove database entry %s%s"), db
->treename
,
313 alpm_pkg_get_name(pkg
));
314 RET_ERR(PM_ERR_DB_REMOVE
, -1);
318 /* Cache needs to be rebuild */
319 _alpm_db_free_pkgcache(db
);
321 /* uncompress the sync database */
322 if(_alpm_db_install(db
, path
) == -1) {
330 /** Get a package entry from a package database
331 * @param db pointer to the package database to get the package from
332 * @param name of the package
333 * @return the package entry on success, NULL on error
335 pmpkg_t SYMEXPORT
*alpm_db_get_pkg(pmdb_t
*db
, const char *name
)
340 ASSERT(handle
!= NULL
, return(NULL
));
341 ASSERT(db
!= NULL
, return(NULL
));
342 ASSERT(name
!= NULL
&& strlen(name
) != 0, return(NULL
));
344 return(_alpm_db_get_pkgfromcache(db
, name
));
347 /** Get the package cache of a package database
348 * @param db pointer to the package database to get the package from
349 * @return the list of packages on success, NULL on error
351 alpm_list_t SYMEXPORT
*alpm_db_getpkgcache(pmdb_t
*db
)
356 ASSERT(handle
!= NULL
, return(NULL
));
357 ASSERT(db
!= NULL
, return(NULL
));
359 return(_alpm_db_get_pkgcache(db
));
362 /** Get the list of packages that a package provides
363 * @param db pointer to the package database to get the package from
364 * @param name name of the package
365 * @return the list of packages on success, NULL on error
367 alpm_list_t SYMEXPORT
*alpm_db_whatprovides(pmdb_t
*db
, const char *name
)
372 ASSERT(handle
!= NULL
, return(NULL
));
373 ASSERT(db
!= NULL
, return(NULL
));
374 ASSERT(name
!= NULL
&& strlen(name
) != 0, return(NULL
));
376 return(_alpm_db_whatprovides(db
, name
));
379 /** Get a group entry from a package database
380 * @param db pointer to the package database to get the group from
381 * @param name of the group
382 * @return the groups entry on success, NULL on error
384 pmgrp_t SYMEXPORT
*alpm_db_readgrp(pmdb_t
*db
, const char *name
)
389 ASSERT(handle
!= NULL
, return(NULL
));
390 ASSERT(db
!= NULL
, return(NULL
));
391 ASSERT(name
!= NULL
&& strlen(name
) != 0, return(NULL
));
393 return(_alpm_db_get_grpfromcache(db
, name
));
396 /** Get the group cache of a package database
397 * @param db pointer to the package database to get the group from
398 * @return the list of groups on success, NULL on error
400 alpm_list_t SYMEXPORT
*alpm_db_getgrpcache(pmdb_t
*db
)
405 ASSERT(handle
!= NULL
, return(NULL
));
406 ASSERT(db
!= NULL
, return(NULL
));
408 return(_alpm_db_get_grpcache(db
));
413 /** \addtogroup alpm_packages Package Functions
414 * @brief Functions to manipulate libalpm packages
418 /** Create a package from a file.
419 * @param filename location of the package tarball
420 * @param pkg address of the package pointer
421 * @return 0 on success, -1 on error (pm_errno is set accordingly)
423 int SYMEXPORT
alpm_pkg_load(char *filename
, pmpkg_t
**pkg
)
425 _alpm_log(PM_LOG_FUNCTION
, "enter alpm_pkg_load");
428 ASSERT(filename
!= NULL
&& strlen(filename
) != 0, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
429 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
431 *pkg
= _alpm_pkg_load(filename
);
433 /* pm_errno is set by pkg_load */
441 * @param pkg package pointer to free
442 * @return 0 on success, -1 on error (pm_errno is set accordingly)
444 int SYMEXPORT
alpm_pkg_free(pmpkg_t
*pkg
)
446 _alpm_log(PM_LOG_FUNCTION
, "enter alpm_pkg_free");
448 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
450 /* Only free packages loaded in user space */
451 if(pkg
->origin
!= PKG_FROM_CACHE
) {
458 /** Check the integrity (with sha1) of a package from the sync cache.
459 * @param pkg package pointer
460 * @return 0 on success, -1 on error (pm_errno is set accordingly)
462 int alpm_pkg_checksha1sum(pmpkg_t
*pkg
)
465 char *sha1sum
= NULL
;
470 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
471 /* We only inspect packages from sync repositories */
472 ASSERT(pkg
->origin
== PKG_FROM_CACHE
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
473 ASSERT(pkg
->data
!= handle
->db_local
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
475 snprintf(path
, PATH_MAX
, "%s%s/%s-%s" PM_EXT_PKG
,
476 handle
->root
, handle
->cachedir
,
477 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
479 sha1sum
= _alpm_SHAFile(path
);
480 if(sha1sum
== NULL
) {
481 _alpm_log(PM_LOG_ERROR
, _("could not get sha1sum for package %s-%s"),
482 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
483 pm_errno
= PM_ERR_NOT_A_FILE
;
486 if(strcmp(sha1sum
, alpm_pkg_get_sha1sum(pkg
)) == 0) {
487 _alpm_log(PM_LOG_DEBUG
, _("sha1sums for package %s-%s match"),
488 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
490 _alpm_log(PM_LOG_ERROR
, _("sha1sums do not match for package %s-%s"),
491 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
492 pm_errno
= PM_ERR_PKG_INVALID
;
502 /** Check the integrity (with md5) of a package from the sync cache.
503 * @param pkg package pointer
504 * @return 0 on success, -1 on error (pm_errno is set accordingly)
506 int alpm_pkg_checkmd5sum(pmpkg_t
*pkg
)
514 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
515 /* We only inspect packages from sync repositories */
516 ASSERT(pkg
->origin
== PKG_FROM_CACHE
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
517 ASSERT(pkg
->data
!= handle
->db_local
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
519 snprintf(path
, PATH_MAX
, "%s%s/%s-%s" PM_EXT_PKG
,
520 handle
->root
, handle
->cachedir
,
521 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
523 md5sum
= _alpm_MDFile(path
);
525 _alpm_log(PM_LOG_ERROR
, _("could not get md5sum for package %s-%s"),
526 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
527 pm_errno
= PM_ERR_NOT_A_FILE
;
530 if(strcmp(md5sum
, alpm_pkg_get_md5sum(pkg
)) == 0) {
531 _alpm_log(PM_LOG_DEBUG
, _("md5sums for package %s-%s match"),
532 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
534 _alpm_log(PM_LOG_ERROR
, _("md5sums do not match for package %s-%s"),
535 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
536 pm_errno
= PM_ERR_PKG_INVALID
;
546 /** Compare versions.
547 * @param ver1 first version
548 * @param ver2 secont version
549 * @return postive, 0 or negative if ver1 is less, equal or more
550 * than ver2, respectively.
552 int SYMEXPORT
alpm_pkg_vercmp(const char *ver1
, const char *ver2
)
556 return(_alpm_versioncmp(ver1
, ver2
));
560 static char *_supported_archs
[] = {
567 char SYMEXPORT
*alpm_pkg_name_hasarch(char *pkgname
)
569 /* TODO remove this when we transfer everything over to -ARCH
571 * this parsing sucks... it's done to support
572 * two package formats for the time being:
573 * package-name-foo-1.0.0-1-i686
575 * package-name-bar-1.2.3-1
578 char *arch
, *cmp
, *p
;
582 if((p
= strrchr(pkgname
, '-'))) {
583 for(i
=0; i
< sizeof(_supported_archs
)/sizeof(char*); ++i
) {
585 arch
= _supported_archs
[i
];
587 /* whee, case insensitive compare */
588 while(*arch
&& *cmp
&& tolower(*arch
++) == tolower(*cmp
++)) ;
601 /** \addtogroup alpm_sync Sync Functions
602 * @brief Functions to get informations about libalpm syncs
606 /** Searches a database
607 * @param db pointer to the package database to search in
608 * @param needles the list of strings to search for
609 * @return the list of packages on success, NULL on error
611 alpm_list_t SYMEXPORT
*alpm_db_search(pmdb_t
*db
, alpm_list_t
* needles
)
616 ASSERT(handle
!= NULL
, return(NULL
));
617 ASSERT(db
!= NULL
, return(NULL
));
619 return(_alpm_db_search(db
, needles
));
624 /** \addtogroup alpm_trans Transaction Functions
625 * @brief Functions to manipulate libalpm transactions
629 /** Initialize the transaction.
630 * @param type type of the transaction
631 * @param flags flags of the transaction (like nodeps, etc)
632 * @param event event callback function pointer
633 * @param conv question callback function pointer
634 * @param progress progress callback function pointer
635 * @return 0 on success, -1 on error (pm_errno is set accordingly)
637 int SYMEXPORT
alpm_trans_init(pmtranstype_t type
, pmtransflag_t flags
,
638 alpm_trans_cb_event event
, alpm_trans_cb_conv conv
,
639 alpm_trans_cb_progress progress
)
646 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
648 ASSERT(handle
->trans
== NULL
, RET_ERR(PM_ERR_TRANS_NOT_NULL
, -1));
651 snprintf(path
, PATH_MAX
, "%s%s", handle
->root
, PM_LOCK
);
652 handle
->lckfd
= _alpm_lckmk(path
);
653 if(handle
->lckfd
== -1) {
654 RET_ERR(PM_ERR_HANDLE_LOCK
, -1);
657 handle
->trans
= _alpm_trans_new();
658 if(handle
->trans
== NULL
) {
659 RET_ERR(PM_ERR_MEMORY
, -1);
662 return(_alpm_trans_init(handle
->trans
, type
, flags
, event
, conv
, progress
));
665 /** Search for packages to upgrade and add them to the transaction.
666 * @return 0 on success, -1 on error (pm_errno is set accordingly)
668 int SYMEXPORT
alpm_trans_sysupgrade()
674 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
676 trans
= handle
->trans
;
677 ASSERT(trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
678 ASSERT(trans
->state
== STATE_INITIALIZED
, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED
, -1));
679 ASSERT(trans
->type
== PM_TRANS_TYPE_SYNC
, RET_ERR(PM_ERR_TRANS_TYPE
, -1));
681 return(_alpm_trans_sysupgrade(trans
));
684 /** Add a target to the transaction.
685 * @param target the name of the target to add
686 * @return 0 on success, -1 on error (pm_errno is set accordingly)
688 int SYMEXPORT
alpm_trans_addtarget(char *target
)
695 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
696 ASSERT(target
!= NULL
&& strlen(target
) != 0, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
698 trans
= handle
->trans
;
699 ASSERT(trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
700 ASSERT(trans
->state
== STATE_INITIALIZED
, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED
, -1));
702 return(_alpm_trans_addtarget(trans
, target
));
705 /** Prepare a transaction.
706 * @param data the address of a PM_LIST where detailed description
707 * of an error can be dumped (ie. list of conflicting files)
708 * @return 0 on success, -1 on error (pm_errno is set accordingly)
710 int SYMEXPORT
alpm_trans_prepare(alpm_list_t
**data
)
715 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
716 ASSERT(data
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
718 ASSERT(handle
->trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
719 ASSERT(handle
->trans
->state
== STATE_INITIALIZED
, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED
, -1));
721 return(_alpm_trans_prepare(handle
->trans
, data
));
724 /** Commit a transaction.
725 * @param data the address of a PM_LIST where detailed description
726 * of an error can be dumped (ie. list of conflicting files)
727 * @return 0 on success, -1 on error (pm_errno is set accordingly)
729 int SYMEXPORT
alpm_trans_commit(alpm_list_t
**data
)
734 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
736 ASSERT(handle
->trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
737 ASSERT(handle
->trans
->state
== STATE_PREPARED
, RET_ERR(PM_ERR_TRANS_NOT_PREPARED
, -1));
739 /* Check for database R/W permission */
740 if(!(handle
->trans
->flags
& PM_TRANS_FLAG_PRINTURIS
)) {
741 /* The print-uris operation is a bit odd. So we explicitly check for it */
742 ASSERT(handle
->access
== PM_ACCESS_RW
, RET_ERR(PM_ERR_BADPERMS
, -1));
745 return(_alpm_trans_commit(handle
->trans
, data
));
748 /** Release a transaction.
749 * @return 0 on success, -1 on error (pm_errno is set accordingly)
751 int SYMEXPORT
alpm_trans_release()
759 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
761 trans
= handle
->trans
;
762 ASSERT(trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
763 ASSERT(trans
->state
!= STATE_IDLE
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
765 /* during a commit do not interrupt inmediatelly, just after a target */
766 if(trans
->state
== STATE_COMMITING
|| trans
->state
== STATE_INTERRUPTED
) {
767 if(trans
->state
== STATE_COMMITING
) {
768 trans
->state
= STATE_INTERRUPTED
;
770 pm_errno
= PM_ERR_TRANS_COMMITING
;
774 FREETRANS(handle
->trans
);
777 if(handle
->lckfd
!= -1) {
778 close(handle
->lckfd
);
781 snprintf(path
, PATH_MAX
, "%s%s", handle
->root
, PM_LOCK
);
782 if(_alpm_lckrm(path
)) {
783 _alpm_log(PM_LOG_WARNING
, _("could not remove lock file %s"), path
);
784 alpm_logaction(_("warning: could not remove lock file %s"), path
);
792 /** \addtogroup alpm_log Logging Functions
793 * @brief Functions to log using libalpm
797 /** A printf-like function for logging.
798 * @param fmt output format
799 * @return 0 on success, -1 on error (pm_errno is set accordingly)
801 int SYMEXPORT
alpm_logaction(char *fmt
, ...)
803 char str
[LOG_STR_LEN
];
809 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
812 vsnprintf(str
, LOG_STR_LEN
, fmt
, args
);
815 /* TODO We should add a prefix to log strings depending on who called us.
816 * If logaction was called by the frontend:
817 * USER: <the frontend log>
818 * and if called internally:
819 * ALPM: <the library log>
820 * Moreover, the frontend should be able to choose its prefix
821 * (USER by default?):
824 * This would allow us to share the log file between several frontends
825 * and know who does what */
826 return(_alpm_logaction(handle
->usesyslog
, handle
->logfd
, str
));
830 /** \addtogroup alpm_misc Miscellaneous Functions
831 * @brief Various libalpm functions
835 /** Get the md5 sum of file.
836 * @param name name of the file
837 * @return the checksum on success, NULL on error
839 char SYMEXPORT
*alpm_get_md5sum(char *name
)
843 ASSERT(name
!= NULL
, return(NULL
));
845 return(_alpm_MDFile(name
));
848 /** Get the sha1 sum of file.
849 * @param name name of the file
850 * @return the checksum on success, NULL on error
852 char SYMEXPORT
*alpm_get_sha1sum(char *name
)
856 ASSERT(name
!= NULL
, return(NULL
));
858 return(_alpm_SHAFile(name
));
861 /** Fetch a remote pkg.
863 * @return the downloaded filename on success, NULL on error
865 char SYMEXPORT
*alpm_fetch_pkgurl(char *url
)
869 ASSERT(strstr(url
, "://"), return(NULL
));
871 return(_alpm_fetch_pkgurl(url
));
874 /** Parses a configuration file.
875 * @param file path to the config file.
876 * @param callback a function to be called upon new database creation
877 * @param this_section the config current section being parsed
878 * @return 0 on success, -1 on error (pm_errno is set accordingly)
880 int SYMEXPORT
alpm_parse_config(char *file
, alpm_cb_db_register callback
, const char *this_section
)
883 char line
[PATH_MAX
+1];
888 char section
[256] = "";
893 fp
= fopen(file
, "r");
898 if(this_section
!= NULL
&& strlen(this_section
) > 0) {
899 strncpy(section
, this_section
, min(255, strlen(this_section
)));
900 if(!strcmp(section
, "local")) {
901 RET_ERR(PM_ERR_CONF_LOCAL
, -1);
903 if(strcmp(section
, "options")) {
904 db
= _alpm_db_register(section
, callback
);
908 while(fgets(line
, PATH_MAX
, fp
)) {
911 if(strlen(line
) == 0 || line
[0] == '#') {
914 if(line
[0] == '[' && line
[strlen(line
)-1] == ']') {
915 /* new config section */
918 strncpy(section
, ptr
, min(255, strlen(ptr
)-1));
919 section
[min(255, strlen(ptr
)-1)] = '\0';
920 _alpm_log(PM_LOG_DEBUG
, _("config: new section '%s'"), section
);
921 if(!strlen(section
)) {
922 RET_ERR(PM_ERR_CONF_BAD_SECTION
, -1);
924 if(!strcmp(section
, "local")) {
925 RET_ERR(PM_ERR_CONF_LOCAL
, -1);
927 if(strcmp(section
, "options")) {
928 db
= _alpm_db_register(section
, callback
);
930 /* pm_errno is set by alpm_db_register */
937 key
= strsep(&ptr
, "=");
939 RET_ERR(PM_ERR_CONF_BAD_SYNTAX
, -1);
942 strncpy(origkey
, key
, min(255, strlen(key
)));
943 origkey
[min(255, strlen(key
))] = '\0';
944 key
= _alpm_strtoupper(key
);
945 if(!strlen(section
) && strcmp(key
, "INCLUDE")) {
946 RET_ERR(PM_ERR_CONF_DIRECTIVE_OUTSIDE_SECTION
, -1);
949 if(strcmp(origkey
, "NoPassiveFTP") == 0 || strcmp(key
, "NOPASSIVEFTP") == 0) {
950 alpm_option_set_nopassiveftp(1);
951 _alpm_log(PM_LOG_DEBUG
, _("config: nopassiveftp"));
952 } else if(strcmp(origkey
, "UseSyslog") == 0 || strcmp(key
, "USESYSLOG") == 0) {
953 alpm_option_set_usesyslog(1);
954 _alpm_log(PM_LOG_DEBUG
, _("config: usesyslog"));
955 } else if(strcmp(origkey
, "ILoveCandy") == 0 || strcmp(key
, "ILOVECANDY") == 0) {
956 alpm_option_set_chomp(1);
957 _alpm_log(PM_LOG_DEBUG
, _("config: chomp"));
958 } else if(strcmp(origkey
, "UseColor") == 0 || strcmp(key
, "USECOLOR") == 0) {
959 alpm_option_set_usecolor(1);
960 _alpm_log(PM_LOG_DEBUG
, _("config: usecolor"));
962 RET_ERR(PM_ERR_CONF_BAD_SYNTAX
, -1);
966 if(strcmp(origkey
, "Include") == 0 || strcmp(key
, "INCLUDE") == 0) {
968 strncpy(conf
, ptr
, PATH_MAX
);
969 _alpm_log(PM_LOG_DEBUG
, _("config: including %s"), conf
);
970 alpm_parse_config(conf
, callback
, section
);
971 } else if(strcmp(section
, "options") == 0) {
972 if(strcmp(origkey
, "NoUpgrade") == 0 || strcmp(key
, "NOUPGRADE") == 0) {
976 while((q
= strchr(p
, ' '))) {
978 alpm_option_add_noupgrade(p
);
979 _alpm_log(PM_LOG_DEBUG
, _("config: noupgrade: %s"), p
);
983 alpm_option_add_noupgrade(p
);
984 _alpm_log(PM_LOG_DEBUG
, _("config: noupgrade: %s"), p
);
985 } else if(strcmp(origkey
, "NoExtract") == 0 || strcmp(key
, "NOEXTRACT") == 0) {
989 while((q
= strchr(p
, ' '))) {
991 alpm_option_add_noextract(p
);
992 _alpm_log(PM_LOG_DEBUG
, _("config: noextract: %s"), p
);
996 alpm_option_add_noextract(p
);
997 _alpm_log(PM_LOG_DEBUG
, _("config: noextract: %s"), p
);
998 } else if(strcmp(origkey
, "IgnorePkg") == 0 || strcmp(key
, "IGNOREPKG") == 0) {
1002 while((q
= strchr(p
, ' '))) {
1004 alpm_option_add_ignorepkg(p
);
1005 _alpm_log(PM_LOG_DEBUG
, _("config: ignorepkg: %s"), p
);
1009 alpm_option_add_ignorepkg(p
);
1010 _alpm_log(PM_LOG_DEBUG
, _("config: ignorepkg: %s"), p
);
1011 } else if(strcmp(origkey
, "HoldPkg") == 0 || strcmp(key
, "HOLDPKG") == 0) {
1015 while((q
= strchr(p
, ' '))) {
1017 alpm_option_add_holdpkg(p
);
1018 _alpm_log(PM_LOG_DEBUG
, _("config: holdpkg: %s"), p
);
1022 alpm_option_add_holdpkg(p
);
1023 _alpm_log(PM_LOG_DEBUG
, _("config: holdpkg: %s"), p
);
1024 } else if(strcmp(origkey
, "DBPath") == 0 || strcmp(key
, "DBPATH") == 0) {
1025 /* shave off the leading slash, if there is one */
1029 alpm_option_set_dbpath(ptr
);
1030 _alpm_log(PM_LOG_DEBUG
, _("config: dbpath: %s"), ptr
);
1031 } else if(strcmp(origkey
, "CacheDir") == 0 || strcmp(key
, "CACHEDIR") == 0) {
1032 /* shave off the leading slash, if there is one */
1036 alpm_option_set_cachedir(ptr
);
1037 _alpm_log(PM_LOG_DEBUG
, _("config: cachedir: %s"), ptr
);
1038 } else if(strcmp(origkey
, "RootDir") == 0 || strcmp(key
, "ROOTDIR") == 0) {
1039 /* shave off the leading slash, if there is one */
1043 alpm_option_set_root(ptr
);
1044 _alpm_log(PM_LOG_DEBUG
, _("config: rootdir: %s"), ptr
);
1045 } else if (strcmp(origkey
, "LogFile") == 0 || strcmp(key
, "LOGFILE") == 0) {
1046 alpm_option_set_logfile(ptr
);
1047 _alpm_log(PM_LOG_DEBUG
, _("config: logfile: %s"), ptr
);
1048 } else if (strcmp(origkey
, "XferCommand") == 0 || strcmp(key
, "XFERCOMMAND") == 0) {
1049 alpm_option_set_xfercommand(ptr
);
1050 _alpm_log(PM_LOG_DEBUG
, _("config: xfercommand: %s"), ptr
);
1051 } else if (strcmp(origkey
, "UpgradeDelay") == 0 || strcmp(key
, "UPGRADEDELAY") == 0) {
1052 /* The config value is in days, we use seconds */
1053 time_t ud
= atol(ptr
) * 60 * 60 *24;
1054 alpm_option_set_upgradedelay(ud
);
1055 _alpm_log(PM_LOG_DEBUG
, _("config: upgradedelay: %d"), ud
);
1057 RET_ERR(PM_ERR_CONF_BAD_SYNTAX
, -1);
1060 if(strcmp(origkey
, "Server") == 0 || strcmp(key
, "SERVER") == 0) {
1061 /* add to the list */
1062 if(alpm_db_setserver(db
, ptr
) != 0) {
1063 /* pm_errno is set by alpm_db_setserver */
1067 RET_ERR(PM_ERR_CONF_BAD_SYNTAX
, -1);
1081 /* This function is mostly the same as sync.c find_replacements and sysupgrade
1082 * functions, and we should be able to combine them - this is an interim
1083 * solution made for -Qu operation */
1084 alpm_list_t SYMEXPORT
*alpm_get_upgrades()
1086 alpm_list_t
*syncpkgs
= NULL
;
1087 alpm_list_t
*i
, *j
, *k
, *m
;
1091 /* TODO holy nested loops, Batman! */
1092 /* check for "recommended" package replacements */
1093 _alpm_log(PM_LOG_DEBUG
, _("checking for package replacements"));
1094 for(i
= handle
->dbs_sync
; i
; i
= i
->next
) {
1095 for(j
= _alpm_db_get_pkgcache(i
->data
); j
; j
= j
->next
) {
1096 pmpkg_t
*spkg
= j
->data
;
1098 for(k
= alpm_pkg_get_replaces(spkg
); k
; k
= k
->next
) {
1100 for(m
= _alpm_db_get_pkgcache(handle
->db_local
); m
; m
= m
->next
) {
1101 pmpkg_t
*lpkg
= m
->data
;
1103 if(strcmp(k
->data
, alpm_pkg_get_name(lpkg
)) == 0) {
1104 _alpm_log(PM_LOG_DEBUG
, _("checking replacement '%s' for package '%s'"), k
->data
,
1105 alpm_pkg_get_name(spkg
));
1106 if(alpm_list_find_str(handle
->ignorepkg
, alpm_pkg_get_name(lpkg
))) {
1107 _alpm_log(PM_LOG_WARNING
, _("%s-%s: ignoring package upgrade (to be replaced by %s-%s)"),
1108 alpm_pkg_get_name(lpkg
), alpm_pkg_get_version(lpkg
),
1109 alpm_pkg_get_name(spkg
), alpm_pkg_get_version(spkg
));
1111 /* assume all replaces=() packages are accepted */
1112 pmsyncpkg_t
*sync
= NULL
;
1113 pmpkg_t
*dummy
= _alpm_pkg_new(alpm_pkg_get_name(lpkg
), NULL
);
1115 pm_errno
= PM_ERR_MEMORY
;
1118 dummy
->requiredby
= alpm_list_strdup(alpm_pkg_get_requiredby(lpkg
));
1120 pmsyncpkg_t
*syncpkg
;
1121 syncpkg
= _alpm_sync_find(syncpkgs
, alpm_pkg_get_name(spkg
));
1124 /* found it -- just append to the replaces list */
1125 sync
->data
= alpm_list_add(sync
->data
, dummy
);
1127 /* none found -- enter pkg into the final sync list */
1128 sync
= _alpm_sync_new(PM_SYNC_TYPE_REPLACE
, spkg
, NULL
);
1131 pm_errno
= PM_ERR_MEMORY
;
1134 sync
->data
= alpm_list_add(NULL
, dummy
);
1135 syncpkgs
= alpm_list_add(syncpkgs
, sync
);
1137 _alpm_log(PM_LOG_DEBUG
, _("%s-%s elected for upgrade (to be replaced by %s-%s)"),
1138 alpm_pkg_get_name(lpkg
), alpm_pkg_get_version(lpkg
),
1139 alpm_pkg_get_name(spkg
), alpm_pkg_get_version(spkg
));
1148 /* now do normal upgrades */
1149 for(i
= _alpm_db_get_pkgcache(handle
->db_local
); i
; i
= i
->next
) {
1151 pmpkg_t
*local
= i
->data
;
1152 pmpkg_t
*spkg
= NULL
;
1155 for(j
= handle
->dbs_sync
; !spkg
&& j
; j
= j
->next
) {
1156 spkg
= _alpm_db_get_pkgfromcache(j
->data
, alpm_pkg_get_name(local
));
1159 _alpm_log(PM_LOG_DEBUG
, _("'%s' not found in sync db -- skipping"), alpm_pkg_get_name(local
));
1163 /* we don't care about a to-be-replaced package's newer version */
1164 for(j
= syncpkgs
; j
&& !replace
; j
=j
->next
) {
1166 if(sync
->type
== PM_SYNC_TYPE_REPLACE
) {
1167 if(_alpm_pkg_find(alpm_pkg_get_name(spkg
), sync
->data
)) {
1173 _alpm_log(PM_LOG_DEBUG
, _("'%s' is already elected for removal -- skipping"),
1174 alpm_pkg_get_name(local
));
1178 if(alpm_pkg_compare_versions(local
, spkg
)) {
1179 _alpm_log(PM_LOG_DEBUG
, _("%s elected for upgrade (%s => %s)"),
1180 alpm_pkg_get_name(local
), alpm_pkg_get_version(local
),
1181 alpm_pkg_get_version(spkg
));
1183 pmsyncpkg_t
*syncpkg
;
1184 syncpkg
= _alpm_sync_find(syncpkgs
, alpm_pkg_get_name(local
));
1187 pmpkg_t
*dummy
= _alpm_pkg_new(alpm_pkg_get_name(local
),
1188 alpm_pkg_get_version(local
));
1192 sync
= _alpm_sync_new(PM_SYNC_TYPE_UPGRADE
, spkg
, dummy
);
1197 syncpkgs
= alpm_list_add(syncpkgs
, sync
);
1205 alpm_list_free_inner(syncpkgs
, _alpm_sync_free
);
1206 alpm_list_free(syncpkgs
);
1211 /* vim: set ts=2 sw=2 noet: */