summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libalpm/alpm.h29
-rw-r--r--lib/libalpm/be_sync.c132
-rw-r--r--lib/libalpm/dload.c12
-rw-r--r--lib/libalpm/dload.h5
4 files changed, 178 insertions, 0 deletions
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 5d559db1..2cf20343 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -1049,6 +1049,35 @@ int alpm_db_remove_server(alpm_db_t *db, const char *url);
*/
int alpm_db_update(int force, alpm_db_t *db);
+/** Update package databases
+ *
+ * An update of the package databases in the list \a dbs will be attempted.
+ * Unless \a force is true, the update will only be performed if the remote
+ * databases were modified since the last update.
+ *
+ * This operation requires a database lock, and will return an applicable error
+ * if the lock could not be obtained.
+ *
+ * Example:
+ * @code
+ * alpm_list_t *dbs = alpm_get_syncdbs();
+ * ret = alpm_dbs_update(config->handle, dbs, force);
+ * if(ret < 0) {
+ * pm_printf(ALPM_LOG_ERROR, _("failed to synchronize all databases (%s)\n"),
+ * alpm_strerror(alpm_errno(config->handle)));
+ * }
+ * @endcode
+ *
+ * @note After a successful update, the \link alpm_db_get_pkgcache()
+ * package cache \endlink will be invalidated
+ * @param handle the context handle
+ * @param dbs list of package databases to update
+ * @param force if true, then forces the update, otherwise update only in case
+ * the databases aren't up to date
+ * @return 0 on success, -1 on error (pm_errno is set accordingly)
+ */
+int alpm_dbs_update(alpm_handle_t *handle, alpm_list_t *dbs, int force);
+
/** Get a package entry from a package database.
* @param db pointer to the package database to get the package from
* @param name of the package
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index 2cee97e0..b4a94315 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -301,6 +301,138 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
return ret;
}
+int SYMEXPORT alpm_dbs_update(alpm_handle_t *handle, alpm_list_t *dbs, int force) {
+ char *syncpath;
+ const char *dbext = handle->dbext;
+ alpm_list_t *i;
+ int ret = -1;
+ mode_t oldmask;
+ alpm_list_t *payloads = NULL;
+
+ /* Sanity checks */
+ CHECK_HANDLE(handle, return -1);
+ ASSERT(dbs != NULL, return -1);
+ handle->pm_errno = ALPM_ERR_OK;
+
+ syncpath = get_sync_dir(handle);
+ ASSERT(syncpath != NULL, return -1);
+
+ /* make sure we have a sane umask */
+ oldmask = umask(0022);
+
+ /* attempt to grab a lock */
+ if(_alpm_handle_lock(handle)) {
+ GOTO_ERR(handle, ALPM_ERR_HANDLE_LOCK, cleanup);
+ }
+
+ for(i = dbs; i; i = i->next) {
+ alpm_db_t *db = i->data;
+ int dbforce = force;
+ struct dload_payload *payload = NULL;
+ size_t len;
+ int siglevel;
+
+ if(!(db->usage & ALPM_DB_USAGE_SYNC)) {
+ continue;
+ }
+
+ ASSERT(db != handle->db_local, GOTO_ERR(handle, ALPM_ERR_WRONG_ARGS, cleanup));
+ ASSERT(db->servers != NULL, GOTO_ERR(handle, ALPM_ERR_SERVER_NONE, cleanup));
+
+ /* force update of invalid databases to fix potential mismatched database/signature */
+ if(db->status & DB_STATUS_INVALID) {
+ dbforce = 1;
+ }
+
+ CALLOC(payload, 1, sizeof(*payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
+
+ /* set hard upper limit of 128 MiB */
+ payload->max_size = 128 * 1024 * 1024;
+ payload->servers = db->servers;
+
+ /* print server + filename into a buffer */
+ len = strlen(db->treename) + strlen(dbext) + 1;
+ MALLOC(payload->filepath, len,
+ FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
+ snprintf(payload->filepath, len, "%s%s", db->treename, dbext);
+ payload->handle = handle;
+ payload->force = dbforce;
+ payload->unlink_on_fail = 1;
+
+ payloads = alpm_list_add(payloads, payload);
+
+ siglevel = alpm_db_get_siglevel(db);
+ if(siglevel & ALPM_SIG_DATABASE) {
+ struct dload_payload *sig_payload;
+ CALLOC(sig_payload, 1, sizeof(*sig_payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
+
+ /* print filename into a buffer (leave space for separator and .sig) */
+ len = strlen(db->treename) + strlen(dbext) + 5;
+ MALLOC(sig_payload->filepath, len,
+ FREE(sig_payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
+ snprintf(sig_payload->filepath, len, "%s%s.sig", db->treename, dbext);
+
+ sig_payload->handle = handle;
+ sig_payload->force = dbforce;
+ sig_payload->errors_ok = (siglevel & ALPM_SIG_DATABASE_OPTIONAL);
+
+ /* set hard upper limit of 16 KiB */
+ sig_payload->max_size = 16 * 1024;
+ sig_payload->servers = db->servers;
+
+ payloads = alpm_list_add(payloads, sig_payload);
+ }
+ }
+
+ ret = _alpm_multi_download(handle, payloads, syncpath);
+ if(ret < 0) {
+ goto cleanup;
+ }
+
+ for(i = dbs; i; i = i->next) {
+ alpm_db_t *db = i->data;
+ if(!(db->usage & ALPM_DB_USAGE_SYNC)) {
+ continue;
+ }
+
+ /* Cache needs to be rebuilt */
+ _alpm_db_free_pkgcache(db);
+
+ /* clear all status flags regarding validity/existence */
+ db->status &= ~DB_STATUS_VALID;
+ db->status &= ~DB_STATUS_INVALID;
+ db->status &= ~DB_STATUS_EXISTS;
+ db->status &= ~DB_STATUS_MISSING;
+
+ /* if the download failed skip validation to preserve the download error */
+ if(sync_db_validate(db) != 0) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "failed to validate db: %s\n",
+ db->treename);
+ /* pm_errno should be set */
+ ret = -1;
+ }
+ }
+
+cleanup:
+ _alpm_handle_unlock(handle);
+
+ if(ret == -1) {
+ /* pm_errno was set by the download code */
+ _alpm_log(handle, ALPM_LOG_DEBUG, "failed to sync dbs: %s\n",
+ alpm_strerror(handle->pm_errno));
+ } else {
+ handle->pm_errno = ALPM_ERR_OK;
+ }
+
+ if(payloads) {
+ alpm_list_free_inner(payloads, (alpm_list_fn_free)_alpm_dload_payload_reset);
+ FREELIST(payloads);
+ }
+ free(syncpath);
+ umask(oldmask);
+ return ret;
+}
+
/* Forward decl so I don't reorganize the whole file right now */
static int sync_db_read(alpm_db_t *db, struct archive *archive,
struct archive_entry *entry, alpm_pkg_t **likely_pkg);
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index 57232a53..8dc259f2 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -634,6 +634,16 @@ int _alpm_download(struct dload_payload *payload, const char *localpath,
}
}
+int _alpm_multi_download(alpm_handle_t *handle,
+ alpm_list_t *payloads /* struct dload_payload */,
+ const char *localpath)
+{
+ (void)handle;
+ (void)payloads;
+ (void)localpath;
+ return 0;
+}
+
static char *filecache_find_url(alpm_handle_t *handle, const char *url)
{
const char *filebase = strrchr(url, '/');
@@ -736,6 +746,7 @@ void _alpm_dload_payload_reset(struct dload_payload *payload)
FREE(payload->destfile_name);
FREE(payload->content_disp_name);
FREE(payload->fileurl);
+ FREE(payload->filepath);
*payload = (struct dload_payload){0};
}
@@ -744,6 +755,7 @@ void _alpm_dload_payload_reset_for_retry(struct dload_payload *payload)
ASSERT(payload, return);
FREE(payload->fileurl);
+ FREE(payload->filepath);
payload->initial_size += payload->prevprogress;
payload->prevprogress = 0;
payload->unlink_on_fail = 0;
diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h
index 1e8f75f3..3eb7fbe1 100644
--- a/lib/libalpm/dload.h
+++ b/lib/libalpm/dload.h
@@ -31,6 +31,7 @@ struct dload_payload {
char *destfile_name;
char *content_disp_name;
char *fileurl;
+ char *filepath; /* download URL path */
alpm_list_t *servers;
long respcode;
off_t initial_size;
@@ -53,4 +54,8 @@ void _alpm_dload_payload_reset_for_retry(struct dload_payload *payload);
int _alpm_download(struct dload_payload *payload, const char *localpath,
char **final_file, const char **final_url);
+int _alpm_multi_download(alpm_handle_t *handle,
+ alpm_list_t *payloads /* struct dload_payload */,
+ const char *localpath);
+
#endif /* ALPM_DLOAD_H */