summaryrefslogtreecommitdiff
path: root/lib/libalpm/add.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm/add.c')
-rw-r--r--lib/libalpm/add.c200
1 files changed, 108 insertions, 92 deletions
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index f39a0ecf..702b12e9 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -1,7 +1,7 @@
/*
* add.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -40,7 +40,6 @@
#include "alpm_list.h"
#include "trans.h"
#include "util.h"
-#include "cache.h"
#include "log.h"
#include "backup.h"
#include "package.h"
@@ -50,64 +49,92 @@
#include "remove.h"
#include "handle.h"
-/** Add a file target to the transaction.
- * @param target the name of the file target to add
+/** Add a package to the transaction.
+ * @param pkg the package to add
* @return 0 on success, -1 on error (pm_errno is set accordingly)
*/
-int SYMEXPORT alpm_add_target(char *target)
+int SYMEXPORT alpm_add_pkg(pmpkg_t *pkg)
{
- pmpkg_t *pkg = NULL;
const char *pkgname, *pkgver;
- alpm_list_t *i;
pmtrans_t *trans;
+ pmdb_t *db_local;
+ pmpkg_t *local;
ALPM_LOG_FUNC;
/* Sanity checks */
- ASSERT(target != NULL && strlen(target) != 0, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+ ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
trans = handle->trans;
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
+ db_local = handle->db_local;
- _alpm_log(PM_LOG_DEBUG, "loading target '%s'\n", target);
-
- if(alpm_pkg_load(target, 1, &pkg) != 0) {
- goto error;
- }
pkgname = alpm_pkg_get_name(pkg);
pkgver = alpm_pkg_get_version(pkg);
- /* check if an older version of said package is already in transaction
- * packages. if so, replace it in the list */
- for(i = trans->add; i; i = i->next) {
- pmpkg_t *transpkg = i->data;
- if(strcmp(transpkg->name, pkgname) == 0) {
- if(alpm_pkg_vercmp(transpkg->version, pkgver) < 0) {
- _alpm_log(PM_LOG_WARNING,
- _("replacing older version %s-%s by %s in target list\n"),
- transpkg->name, transpkg->version, pkgver);
- _alpm_pkg_free(i->data);
- i->data = pkg;
+ _alpm_log(PM_LOG_DEBUG, "adding package '%s'\n", pkgname);
+
+ if(_alpm_pkg_find(trans->add, pkgname)) {
+ RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
+ }
+
+ local = _alpm_db_get_pkgfromcache(db_local, pkgname);
+ if(local) {
+ const char *localpkgname = alpm_pkg_get_name(local);
+ const char *localpkgver = alpm_pkg_get_version(local);
+ int cmp = _alpm_pkg_compare_versions(pkg, local);
+
+ if(cmp == 0) {
+ if(trans->flags & PM_TRANS_FLAG_NEEDED) {
+ /* with the NEEDED flag, packages up to date are not reinstalled */
+ _alpm_log(PM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"),
+ localpkgname, localpkgver);
+ return(0);
} else {
- _alpm_log(PM_LOG_WARNING,
- _("skipping %s-%s because newer version %s is in target list\n"),
- pkgname, pkgver, transpkg->version);
- _alpm_pkg_free(pkg);
+ _alpm_log(PM_LOG_WARNING, _("%s-%s is up to date -- reinstalling\n"),
+ localpkgname, localpkgver);
}
- return(0);
+ } else if(cmp < 0) {
+ /* local version is newer */
+ _alpm_log(PM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"),
+ localpkgname, localpkgver, pkgver);
}
}
/* add the package to the transaction */
+ pkg->reason = PM_PKG_REASON_EXPLICIT;
+ _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n",
+ pkgname, pkgver);
trans->add = alpm_list_add(trans->add, pkg);
return(0);
+}
+
+static int perform_extraction(struct archive *archive,
+ struct archive_entry *entry, const char *filename, const char *origname)
+{
+ int ret;
+ const int archive_flags = ARCHIVE_EXTRACT_OWNER |
+ ARCHIVE_EXTRACT_PERM |
+ ARCHIVE_EXTRACT_TIME;
-error:
- _alpm_pkg_free(pkg);
- return(-1);
+ archive_entry_set_pathname(entry, filename);
+
+ ret = archive_read_extract(archive, entry, archive_flags);
+ if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) {
+ /* operation succeeded but a "non-critical" error was encountered */
+ _alpm_log(PM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
+ origname, archive_error_string(archive));
+ } else if(ret != ARCHIVE_OK) {
+ _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
+ origname, archive_error_string(archive));
+ alpm_logaction("error: could not extract %s (%s)\n",
+ origname, archive_error_string(archive));
+ return(1);
+ }
+ return(0);
}
static int extract_single_file(struct archive *archive,
@@ -120,9 +147,6 @@ static int extract_single_file(struct archive *archive,
int needbackup = 0, notouch = 0;
char *hash_orig = NULL;
char *entryname_orig = NULL;
- const int archive_flags = ARCHIVE_EXTRACT_OWNER |
- ARCHIVE_EXTRACT_PERM |
- ARCHIVE_EXTRACT_TIME;
int errors = 0;
entryname = archive_entry_pathname(entry);
@@ -161,14 +185,6 @@ static int extract_single_file(struct archive *archive,
return(0);
}
- /* if a file is in the add skiplist we never extract it */
- if(alpm_list_find_str(trans->skip_add, filename)) {
- _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_add, skipping extraction\n",
- entryname);
- archive_read_data_skip(archive);
- return(0);
- }
-
/* Check for file existence. This is one of the more crucial parts
* to get 'right'. Here are the possibilities, with the filesystem
* on the left and the package on the top:
@@ -277,18 +293,10 @@ static int extract_single_file(struct archive *archive,
int ret;
snprintf(checkfile, PATH_MAX, "%s.paccheck", filename);
- archive_entry_set_pathname(entry, checkfile);
-
- ret = archive_read_extract(archive, entry, archive_flags);
- if(ret == ARCHIVE_WARN) {
- /* operation succeeded but a non-critical error was encountered */
- _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
- entryname_orig, archive_error_string(archive));
- } else if(ret != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
- entryname_orig, archive_error_string(archive));
- alpm_logaction("error: could not extract %s (%s)\n",
- entryname_orig, archive_error_string(archive));
+
+ ret = perform_extraction(archive, entry, checkfile, entryname_orig);
+ if(ret == 1) {
+ /* error */
FREE(hash_orig);
FREE(entryname_orig);
return(1);
@@ -430,18 +438,9 @@ static int extract_single_file(struct archive *archive,
unlink(filename);
}
- archive_entry_set_pathname(entry, filename);
-
- ret = archive_read_extract(archive, entry, archive_flags);
- if(ret == ARCHIVE_WARN) {
- /* operation succeeded but a non-critical error was encountered */
- _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
- entryname_orig, archive_error_string(archive));
- } else if(ret != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
- entryname_orig, archive_error_string(archive));
- alpm_logaction("error: could not extract %s (%s)\n",
- entryname_orig, archive_error_string(archive));
+ ret = perform_extraction(archive, entry, filename, entryname_orig);
+ if(ret == 1) {
+ /* error */
FREE(entryname_orig);
return(1);
}
@@ -473,8 +472,8 @@ static int extract_single_file(struct archive *archive,
return(errors);
}
-static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
- pmtrans_t *trans, pmdb_t *db)
+static int commit_single_pkg(pmpkg_t *newpkg, size_t pkg_current,
+ size_t pkg_count, pmtrans_t *trans, pmdb_t *db)
{
int i, ret = 0, errors = 0;
char scriptlet[PATH_MAX+1];
@@ -498,7 +497,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
oldpkg = _alpm_pkg_dup(local);
/* make sure all infos are loaded because the database entry
* will be removed soon */
- _alpm_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
+ _alpm_local_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
EVENT(trans, PM_TRANS_EVT_UPGRADE_START, newpkg, oldpkg);
_alpm_log(PM_LOG_DEBUG, "upgrading package %s-%s\n",
@@ -544,7 +543,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
/* prepare directory for database entries so permission are correct after
changelog/install script installation (FS#12263) */
- if(_alpm_db_prepare(db, newpkg)) {
+ if(_alpm_local_db_prepare(db, newpkg)) {
alpm_logaction("error: could not create database entry %s-%s\n",
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
pm_errno = PM_ERR_DB_WRITE;
@@ -556,6 +555,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
struct archive *archive;
struct archive_entry *entry;
char cwd[PATH_MAX] = "";
+ int restore_cwd = 0;
_alpm_log(PM_LOG_DEBUG, "extracting files\n");
@@ -579,11 +579,16 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
/* save the cwd so we can restore it later */
if(getcwd(cwd, PATH_MAX) == NULL) {
_alpm_log(PM_LOG_ERROR, _("could not get current working directory\n"));
- cwd[0] = 0;
+ } else {
+ restore_cwd = 1;
}
/* libarchive requires this for extracting hard links */
- chdir(handle->root);
+ if(chdir(handle->root) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
/* call PROGRESS once with 0 percent, as we sort-of skip that here */
if(is_upgrade) {
@@ -595,31 +600,31 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
}
for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
- double percent;
+ int percent;
if(newpkg->size != 0) {
/* Using compressed size for calculations here, as newpkg->isize is not
* exact when it comes to comparing to the ACTUAL uncompressed size
* (missing metadata sizes) */
int64_t pos = archive_position_compressed(archive);
- percent = (double)pos / (double)newpkg->size;
+ percent = (pos * 100) / newpkg->size;
_alpm_log(PM_LOG_DEBUG, "decompression progress: "
- "%f%% (%"PRId64" / %jd)\n",
- percent*100.0, pos, (intmax_t)newpkg->size);
- if(percent >= 1.0) {
- percent = 1.0;
+ "%d%% (%"PRId64" / %jd)\n",
+ percent, pos, (intmax_t)newpkg->size);
+ if(percent >= 100) {
+ percent = 100;
}
} else {
- percent = 0.0;
+ percent = 0;
}
if(is_upgrade) {
PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START,
- alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count,
+ alpm_pkg_get_name(newpkg), percent, pkg_count,
pkg_current);
} else {
PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START,
- alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count,
+ alpm_pkg_get_name(newpkg), percent, pkg_count,
pkg_current);
}
@@ -629,9 +634,9 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
}
archive_read_finish(archive);
- /* restore the old cwd is we have it */
- if(strlen(cwd)) {
- chdir(cwd);
+ /* restore the old cwd if we have it */
+ if(restore_cwd && chdir(cwd) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));
}
if(errors) {
@@ -656,7 +661,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
- if(_alpm_db_write(db, newpkg, INFRQ_ALL)) {
+ if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
_alpm_log(PM_LOG_ERROR, _("could not update database entry %s-%s\n"),
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
alpm_logaction("error: could not update database entry %s-%s\n",
@@ -705,7 +710,8 @@ cleanup:
int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)
{
- int pkg_count, pkg_current;
+ size_t pkg_count, pkg_current;
+ int skip_ldconfig = 0, ret = 0;
alpm_list_t *targ;
ALPM_LOG_FUNC;
@@ -723,18 +729,28 @@ int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)
/* loop through our package list adding/upgrading one at a time */
for(targ = trans->add; targ; targ = targ->next) {
if(handle->trans->state == STATE_INTERRUPTED) {
- return(0);
+ return(ret);
}
pmpkg_t *newpkg = (pmpkg_t *)targ->data;
- commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db);
+ if(commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db)) {
+ /* something screwed up on the commit, abort the trans */
+ trans->state = STATE_INTERRUPTED;
+ pm_errno = PM_ERR_TRANS_ABORT;
+ /* running ldconfig at this point could possibly screw system */
+ skip_ldconfig = 1;
+ ret = -1;
+ }
+
pkg_current++;
}
- /* run ldconfig if it exists */
- _alpm_ldconfig(handle->root);
+ if(!skip_ldconfig) {
+ /* run ldconfig if it exists */
+ _alpm_ldconfig(handle->root);
+ }
- return(0);
+ return(ret);
}
/* vim: set ts=2 sw=2 noet: */