Compare commits

..

5 Commits

Author SHA1 Message Date
morganamilo
c7cb6e486b libalpm: fix importing keys from keyserver
commit 95a7d416ce broke
key_search_keyserver() by removing the `ret = 1` at the end of the
function, causing the caller to allways think the funciton failed even
when it did not. Due to WKD being the primary method to import keys this
was unnoticed.
2025-08-01 09:42:02 +01:00
morganamilo
a0be6f0829 libalpm: reimport expired keys
If the user does not update for a while some of the keys in the keyring
may expire. Pacman does not import new versions of these keys because
they are already in the keying. This leads to users needing to first
update archlinux-keyring to get the new keys.
2025-08-01 09:41:59 +01:00
morganamilo
fff9296478 libalpm: improve error message for expired keys (cont)
Continuation of last commit.

Changes:

error: failed to commit transaction (invalid or corrupted package (PGP signature))

To:

error: failed to commit transaction (package signature has missing or invalid PGP key)
2025-08-01 09:41:56 +01:00
morganamilo
f42b93dd7f libalpm: improve error message for expired keys
If the user does not update their system for a while some of the package
keys may expire. Pacman gives this message:

error: simdjson: signature from "Bert Peters (packager key)
<bertptrs@archlinux.org>" is unknown trust

While this is technically true it masks the real issue of the key being
expired.

This commit changes that error message to:

error: simdjson: key  "Bert Peters (packager key) <bertptrs@archlinux.org>" (38100C24376CD5F6ED4FF4B46918400C2703040C)
2025-08-01 06:15:06 +01:00
morganamilo
beb6bd80cd libalpm: set errno when key is missing from keyring
There was no fitting error type for this so add ALPM_ERR_KEY_MISSING.
2025-08-01 04:09:26 +01:00
27 changed files with 680 additions and 662 deletions

View File

@@ -318,12 +318,12 @@ When to Check::
*Never*;;
All signature checking is suppressed, even if signatures are present.
*Optional*;;
*Optional* (default);;
Signatures are checked if present; absence of a signature is not an
error. An invalid signature is a fatal error, as is a signature from a
key not in the keyring.
*Required* (default);;
*Required*;;
Signatures are required; absence of a signature or an invalid signature
is a fatal error, as is a signature from a key not in the keyring.
@@ -349,7 +349,7 @@ level signatures for packages.
The built-in default is the following:
--------
SigLevel = Required TrustedOnly
SigLevel = Optional TrustedOnly
--------

View File

@@ -75,9 +75,6 @@ repo-add Options
Only add packages that are not already in the database. Warnings will be
printed upon detection of existing packages, but they will not be re-added.
*-p, \--prevent-downgrade*::
Do not add package to database if a newer version is already present
*\--include-sigs*::
Include package PGP signatures in the repository database (if available)

View File

@@ -242,6 +242,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_DB_INVALID,
/** Database has an invalid signature */
ALPM_ERR_DB_INVALID_SIG,
/** Database is signed by an invalid key */
ALPM_ERR_DB_INVALID_KEY,
/** The localdb is in a newer/older format than libalpm expects */
ALPM_ERR_DB_VERSION,
/** Failed to write to the database */
@@ -285,6 +287,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_PKG_INVALID_CHECKSUM,
/** Package has an invalid signature */
ALPM_ERR_PKG_INVALID_SIG,
/** Package is signed by an invalid key */
ALPM_ERR_PKG_INVALID_KEY,
/** Package does not have a signature */
ALPM_ERR_PKG_MISSING_SIG,
/** Cannot open the package file */
@@ -300,6 +304,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_SIG_MISSING,
/** Signatures are invalid */
ALPM_ERR_SIG_INVALID,
/** Keys are missing from keyring */
ALPM_ERR_KEY_MISSING,
/* Dependencies */
/** Dependencies could not be satisfied */
ALPM_ERR_UNSATISFIED_DEPS,
@@ -481,7 +487,7 @@ typedef struct _alpm_siglist_t {
* Check the PGP signature for the given package file.
* @param pkg the package to check
* @param siglist a pointer to storage for signature results
* @return 0 on success, -1 if an error occurred or signature is missing
* @return 0 if valid, -1 if an error occurred or signature is invalid
*/
int alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg, alpm_siglist_t *siglist);
@@ -489,7 +495,7 @@ int alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg, alpm_siglist_t *siglist);
* Check the PGP signature for the given database.
* @param db the database to check
* @param siglist a pointer to storage for signature results
* @return 0 on success, -1 if an error occurred or signature is missing
* @return 0 if valid, -1 if an error occurred or signature is invalid
*/
int alpm_db_check_pgp_signature(alpm_db_t *db, alpm_siglist_t *siglist);

View File

@@ -341,15 +341,17 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle,
/* even if we don't have a sig, run the check code if level tells us to */
if(level & ALPM_SIG_PACKAGE) {
const char *sig = syncpkg ? syncpkg->base64_sig : NULL;
int ret;
_alpm_log(handle, ALPM_LOG_DEBUG, "sig data: %s\n", sig ? sig : "<from .sig>");
if(!has_sig && !(level & ALPM_SIG_PACKAGE_OPTIONAL)) {
handle->pm_errno = ALPM_ERR_PKG_MISSING_SIG;
return -1;
}
if(_alpm_check_pgp_helper(handle, pkgfile, sig,
ret = _alpm_check_pgp_helper(handle, pkgfile, sig,
level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_PACKAGE_MARGINAL_OK,
level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata)) {
handle->pm_errno = ALPM_ERR_PKG_INVALID_SIG;
level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata);
if(ret) {
handle->pm_errno = ret == -1 ? ALPM_ERR_PKG_INVALID_SIG : ALPM_ERR_PKG_INVALID_KEY;
return -1;
}
if(validation && has_sig) {
@@ -766,6 +768,7 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
if(fail) {
_alpm_log(handle, ALPM_LOG_ERROR, _("required key missing from keyring\n"));
handle->pm_errno = ALPM_ERR_KEY_MISSING;
free(sigpath);
return -1;
}

View File

@@ -126,6 +126,7 @@ static int sync_db_validate(alpm_db_t *db)
db->status &= ~DB_STATUS_VALID;
db->status |= DB_STATUS_INVALID;
db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
db->handle->pm_errno = ret == -1 ? ALPM_ERR_PKG_INVALID_SIG : ALPM_ERR_PKG_INVALID_KEY;
return 1;
}
}

View File

@@ -1322,7 +1322,7 @@ int SYMEXPORT alpm_fetch_pkgurl(alpm_handle_t *handle, const alpm_list_t *urls,
char *temporary_cachedir = NULL;
alpm_list_t *payloads = NULL;
const alpm_list_t *i;
alpm_event_t event;
alpm_event_t event = {0};
CHECK_HANDLE(handle, return -1);
ASSERT(*fetched == NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));

View File

@@ -72,6 +72,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("invalid or corrupted database");
case ALPM_ERR_DB_INVALID_SIG:
return _("invalid or corrupted database (PGP signature)");
case ALPM_ERR_DB_INVALID_KEY:
return _("database signature has missing or invalid PGP key");
case ALPM_ERR_DB_VERSION:
return _("database is incorrect version");
case ALPM_ERR_DB_WRITE:
@@ -115,6 +117,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("invalid or corrupted package (checksum)");
case ALPM_ERR_PKG_INVALID_SIG:
return _("invalid or corrupted package (PGP signature)");
case ALPM_ERR_PKG_INVALID_KEY:
return _("package signature has missing or invalid PGP key");
case ALPM_ERR_PKG_MISSING_SIG:
return _("package missing required signature");
case ALPM_ERR_PKG_OPEN:
@@ -130,6 +134,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("missing PGP signature");
case ALPM_ERR_SIG_INVALID:
return _("invalid PGP signature");
case ALPM_ERR_KEY_MISSING:
return _("PGP key missing from keyring");
/* Dependencies */
case ALPM_ERR_UNSATISFIED_DEPS:
return _("could not satisfy dependencies");

View File

@@ -233,9 +233,14 @@ int _alpm_key_in_keychain(alpm_handle_t *handle, const char *fpr)
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
ret = 0;
} else if(gpg_err_code(gpg_err) == GPG_ERR_NO_ERROR) {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, key exists\n");
handle->known_keys = alpm_list_add(handle->known_keys, strdup(fpr));
ret = 1;
if(key->expired) {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, but key is expired\n");
ret = 0;
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup success, key exists\n");
handle->known_keys = alpm_list_add(handle->known_keys, strdup(fpr));
ret = 1;
}
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(gpg_err));
}
@@ -268,7 +273,7 @@ static int key_import_wkd(alpm_handle_t *handle, const char *email, const char *
CHECK_ERR();
mode = gpgme_get_keylist_mode(ctx);
mode |= GPGME_KEYLIST_MODE_LOCATE;
mode |= GPGME_KEYLIST_MODE_LOCATE_EXTERNAL;
gpg_err = gpgme_set_keylist_mode(ctx, mode);
CHECK_ERR();
@@ -279,7 +284,7 @@ static int key_import_wkd(alpm_handle_t *handle, const char *email, const char *
if(fpr && _alpm_key_in_keychain(handle, fpr)) {
ret = 0;
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed: WKD imported wrong fingerprint\n");
_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed: WKD imported wrong fingerprint or key expired\n");
}
}
gpgme_key_unref(key);
@@ -371,6 +376,7 @@ static int key_search_keyserver(alpm_handle_t *handle, const char *fpr,
pgpkey->expires = key->subkeys->expires;
pgpkey->length = key->subkeys->length;
pgpkey->revoked = key->subkeys->revoked;
ret = 1;
gpg_error:
if(ret != 1) {
@@ -792,7 +798,7 @@ char *_alpm_sigpath(alpm_handle_t *handle, const char *path)
* @param marginal whether signatures with marginal trust are acceptable
* @param unknown whether signatures with unknown trust are acceptable
* @param sigdata a pointer to storage for signature results
* @return 0 on success, -1 on error (consult pm_errno or sigdata)
* @return 0 on success, -1 on error, -2 on key error (consult pm_errno or sigdata)
*/
int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
const char *base64_sig, int optional, int marginal, int unknown,
@@ -800,6 +806,7 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
{
alpm_siglist_t *siglist;
int ret;
int key_invalid = 0;
CALLOC(siglist, 1, sizeof(alpm_siglist_t),
RET_ERR(handle, ALPM_ERR_MEMORY, -1));
@@ -821,8 +828,11 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
size_t num;
for(num = 0; !ret && num < siglist->count; num++) {
switch(siglist->results[num].status) {
case ALPM_SIGSTATUS_VALID:
case ALPM_SIGSTATUS_KEY_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "key is expired\n");
key_invalid = 1;
__attribute__((fallthrough));
case ALPM_SIGSTATUS_VALID:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n");
switch(siglist->results[num].validity) {
case ALPM_SIGVALIDITY_FULL:
@@ -846,9 +856,12 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
break;
}
break;
case ALPM_SIGSTATUS_SIG_EXPIRED:
case ALPM_SIGSTATUS_KEY_UNKNOWN:
case ALPM_SIGSTATUS_KEY_DISABLED:
case ALPM_SIGSTATUS_SIG_EXPIRED:
_alpm_log(handle, ALPM_LOG_DEBUG, "key is not valid\n");
key_invalid = 1;
__attribute__((fallthrough));
case ALPM_SIGSTATUS_INVALID:
_alpm_log(handle, ALPM_LOG_DEBUG, "signature is not valid\n");
ret = -1;
@@ -864,7 +877,7 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
free(siglist);
}
return ret;
return key_invalid ? -2 : ret;
}
/**
@@ -897,7 +910,6 @@ int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
const char *name = result->key.uid ? result->key.uid : result->key.fingerprint;
switch(result->status) {
case ALPM_SIGSTATUS_VALID:
case ALPM_SIGSTATUS_KEY_EXPIRED:
switch(result->validity) {
case ALPM_SIGVALIDITY_FULL:
break;
@@ -923,6 +935,16 @@ int _alpm_process_siglist(alpm_handle_t *handle, const char *identifier,
identifier, name);
break;
}
break;
case ALPM_SIGSTATUS_KEY_EXPIRED:
_alpm_log(handle, ALPM_LOG_ERROR,
_("%s: key \"%s\" (%s) is expired\n"),
identifier, name, result->key.fingerprint);
if(_alpm_key_import(handle, result->key.uid, result->key.fingerprint) == 0) {
retry = 1;
}
break;
case ALPM_SIGSTATUS_KEY_UNKNOWN:
/* ensure this key is still actually unknown; we may have imported it

View File

@@ -776,7 +776,7 @@ static int download_files(alpm_handle_t *handle)
char * temporary_cachedir = NULL;
alpm_list_t *i, *files = NULL;
int ret = 0;
alpm_event_t event;
alpm_event_t event = {0};
alpm_list_t *payloads = NULL;
cachedir = _alpm_filecache_setup(handle);
@@ -975,6 +975,7 @@ static int check_keyring(alpm_handle_t *handle)
EVENT(handle, &event);
if(fail) {
_alpm_log(handle, ALPM_LOG_ERROR, _("required key missing from keyring\n"));
handle->pm_errno = ALPM_ERR_KEY_MISSING;
return -1;
}
}
@@ -1053,6 +1054,7 @@ static int check_validity(alpm_handle_t *handle,
_("%s: missing required signature\n"), v->pkg->name);
break;
case ALPM_ERR_PKG_INVALID_SIG:
case ALPM_ERR_PKG_INVALID_KEY:
_alpm_process_siglist(handle, v->pkg->name, v->siglist,
v->siglevel & ALPM_SIG_PACKAGE_OPTIONAL,
v->siglevel & ALPM_SIG_PACKAGE_MARGINAL_OK,

View File

@@ -1,57 +0,0 @@
#!/bin/bash
#
# buildenv.sh - Check that the BUILDENV and OPTIONS arrays are valid
#
# Copyright (c) 2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
[[ -n $LIBMAKEPKG_LINT_CONFIG_BUILDENV_SH ]] && return
LIBMAKEPKG_LINT_CONFIG_BUILDENV_SH=1
MAKEPKG_LIBRARY=${MAKEPKG_LIBRARY:-'@libmakepkgdir@'}
source "$MAKEPKG_LIBRARY/util/message.sh"
lint_config_functions+=('lint_buildenv')
lint_buildenv() {
local ret=0 kopt
local known_buildenv=(ccache check color distcc sign)
local known_option=(autodeps debug docs emptydirs libtool lto purge staticlibs strip zipman)
for i in "${BUILDENV[@]}"; do
for kopt in "${known_buildenv[@]}"; do
if [[ $i = "$kopt" || $i = "!$kopt" ]]; then
continue 2
fi
done
error "$(gettext "%s array contains unknown option '%s'")" "BUILDENV" "$i"
ret=1
done
for i in "${OPTIONS[@]}"; do
for kopt in "${known_option[@]}"; do
if [[ $i = "$kopt" || $i = "!$kopt" ]]; then
continue 2
fi
done
error "$(gettext "%s array contains unknown option '%s'")" "OPTIONS" "$i"
ret=1
done
}

View File

@@ -1,7 +1,6 @@
libmakepkg_module = 'lint_config'
sources = [
'buildenv.sh.in',
'ext.sh.in',
'nproc.sh.in',
'packager.sh.in',

View File

@@ -17,6 +17,7 @@ sources = [
'package_function.sh.in',
'package_function_variable.sh.in',
'pkgbase.sh.in',
'pkglist.sh.in',
'pkgname.sh.in',
'pkgrel.sh.in',
'pkgver.sh.in',

View File

@@ -0,0 +1,44 @@
#!/bin/bash
#
# pkglist.sh - Check the packages selected to build exist.
#
# Copyright (c) 2014-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
[[ -n "$LIBMAKEPKG_LINT_PKGBUILD_PKGLIST_SH" ]] && return
LIBMAKEPKG_LINT_PKGBUILD_PKGLIST_SH=1
MAKEPKG_LIBRARY=${MAKEPKG_LIBRARY:-'@libmakepkgdir@'}
source "$MAKEPKG_LIBRARY/util/message.sh"
source "$MAKEPKG_LIBRARY/util/util.sh"
lint_pkgbuild_functions+=('lint_pkglist')
lint_pkglist() {
local i ret=0
for i in "${PKGLIST[@]}"; do
if ! in_array "$i" "${pkgname[@]}"; then
error "$(gettext "Requested package %s is not provided in %s")" "$i" "$BUILDFILE"
ret=1
fi
done
return $ret
}

View File

@@ -68,7 +68,6 @@ Multiple packages to add can be specified on the command line.\n")"
printf -- "$(gettext "Options:\n")"
printf -- "$(gettext " -n, --new only add packages that are not already in the database\n")"
printf -- "$(gettext " -p, --prevent-downgrade do not add package to database if a newer version is already present\n")"
printf -- "$(gettext " --include-sigs Include package PGP signatures in the repository database (if available)")
elif [[ $cmd == "repo-remove" ]] ; then
printf -- "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename> ...\n")"
printf -- "\n"

View File

@@ -529,10 +529,17 @@ void cb_question(void *ctx, alpm_question_t *question)
case ALPM_QUESTION_CORRUPTED_PKG:
{
alpm_question_corrupted_t *q = &question->corrupted;
q->remove = yesno(_("File %s is corrupted (%s).\n"
"Do you want to delete it?"),
q->filepath,
alpm_strerror(q->reason));
if(q->reason == ALPM_ERR_PKG_INVALID_KEY || q->reason == ALPM_ERR_DB_INVALID_KEY) {
q->remove = yesno(_("Can't get PGP key for file %s (%s)\n"
"Do you want to delete it?"),
q->filepath,
alpm_strerror(q->reason));
} else {
q->remove = yesno(_("File %s is corrupted (%s).\n"
"Do you want to delete it?"),
q->filepath,
alpm_strerror(q->reason));
}
}
break;
case ALPM_QUESTION_IMPORT_KEY:

View File

@@ -105,11 +105,12 @@ config_t *config_new(void)
return NULL;
}
/* defaults which may get overridden later */
newconfig->op = PM_OP_NONE;
newconfig->op = PM_OP_MAIN;
newconfig->logmask = ALPM_LOG_ERROR | ALPM_LOG_WARNING;
newconfig->configfile = strdup(CONFFILE);
if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES) {
newconfig->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_DATABASE;
newconfig->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL;
newconfig->localfilesiglevel = ALPM_SIG_USE_DEFAULT;
newconfig->remotefilesiglevel = ALPM_SIG_USE_DEFAULT;
}
@@ -130,13 +131,6 @@ config_t *config_new(void)
return newconfig;
}
void targets_free(targets_t *targets) {
FREELIST(targets->targets);
FREELIST(targets->sync);
FREELIST(targets->upgrade);
FREELIST(targets->remove);
}
int config_free(config_t *oldconfig)
{
if(oldconfig == NULL) {

View File

@@ -44,14 +44,6 @@ typedef struct __config_repo_t {
int siglevel_mask;
} config_repo_t;
typedef struct __targets_t {
alpm_list_t *targets;
alpm_list_t *sync;
alpm_list_t *upgrade;
alpm_list_t *remove;
} targets_t;
typedef struct __config_t {
unsigned short op;
unsigned short quiet;
@@ -153,15 +145,14 @@ typedef struct __config_t {
/* Operations */
enum {
PM_OP_NONE = 0,
PM_OP_INVALID = (1 << 0),
PM_OP_REMOVE = (1 << 1),
PM_OP_UPGRADE = (1 << 2),
PM_OP_QUERY = (1 << 3),
PM_OP_SYNC = (1 << 4),
PM_OP_DEPTEST = (1 << 5),
PM_OP_DATABASE = (1 << 6),
PM_OP_FILES = (1 << 7)
PM_OP_MAIN = 1,
PM_OP_REMOVE,
PM_OP_UPGRADE,
PM_OP_QUERY,
PM_OP_SYNC,
PM_OP_DEPTEST,
PM_OP_DATABASE,
PM_OP_FILES
};
/* Long Operations */
@@ -248,9 +239,6 @@ enum {
/* global config variable */
extern config_t *config;
void targets_free(targets_t *targets);
void enable_colors(int colors);
config_t *config_new(void);
int config_free(config_t *oldconfig);

View File

@@ -10,7 +10,6 @@ pacman_sources = files('''
remove.c
sighandler.h sighandler.c
sync.c
trans.c
callback.h callback.c
upgrade.c
util.h util.c

View File

@@ -104,7 +104,7 @@ static void usage(int op, const char * const myname)
char const *const str_opr = _("operation");
/* please limit your strings to 80 characters in width */
if(op == PM_OP_NONE) {
if(op == PM_OP_MAIN) {
printf("%s: %s <%s> [...]\n", str_usg, myname, str_opr);
printf(_("operations:\n"));
printf(" %s {-h --help}\n", myname);
@@ -340,25 +340,25 @@ static int parsearg_op(int opt, int dryrun)
/* operations */
case 'D':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_DATABASE); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DATABASE); break;
case 'F':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_FILES); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_FILES); break;
case 'Q':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_QUERY); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break;
case 'R':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_REMOVE); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break;
case 'S':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_SYNC); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break;
case 'T':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_DEPTEST); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); break;
case 'U':
if(dryrun) break;
config->op = (config->op != PM_OP_NONE ? PM_OP_INVALID : PM_OP_UPGRADE); break;
config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); break;
case 'V':
if(dryrun) break;
config->version = 1; break;
@@ -996,7 +996,7 @@ static int parseargs(int argc, char *argv[])
parsearg_op(opt, 0);
}
if(config->op == PM_OP_INVALID) {
if(config->op == 0) {
pm_printf(ALPM_LOG_ERROR, _("only one operation may be used at a time\n"));
return 1;
}
@@ -1124,7 +1124,6 @@ int main(int argc, char *argv[])
{
int ret = 0;
uid_t myuid = getuid();
targets_t targets = {0};
console_cursor_hide();
install_segv_handler();
@@ -1277,27 +1276,24 @@ int main(int argc, char *argv[])
case PM_OP_DATABASE:
ret = pacman_database(pm_targets);
break;
case PM_OP_REMOVE:
ret = pacman_remove(pm_targets);
break;
case PM_OP_UPGRADE:
ret = pacman_upgrade(pm_targets);
break;
case PM_OP_QUERY:
ret = pacman_query(pm_targets);
break;
case PM_OP_SYNC:
ret = pacman_sync(pm_targets);
break;
case PM_OP_DEPTEST:
ret = pacman_deptest(pm_targets);
break;
case PM_OP_FILES:
ret = pacman_files(pm_targets);
break;
case PM_OP_SYNC:
targets.sync = pm_targets;
ret = do_transaction(&targets);
break;
case PM_OP_UPGRADE:
targets.upgrade = pm_targets;
ret = do_transaction(&targets);
break;
case PM_OP_REMOVE:
targets.remove = pm_targets;
ret = do_transaction(&targets);
break;
default:
pm_printf(ALPM_LOG_ERROR, _("no operation specified (use -h for help)\n"));
ret = EXIT_FAILURE;

View File

@@ -22,8 +22,6 @@
#include <alpm_list.h>
#include "conf.h"
#define PACMAN_CALLER_PREFIX "PACMAN"
/* database.c */
@@ -34,14 +32,12 @@ int pacman_deptest(alpm_list_t *targets);
int pacman_files(alpm_list_t *files);
/* query.c */
int pacman_query(alpm_list_t *targets);
/* remove.c */
int pacman_remove(alpm_list_t *targets);
/* sync.c */
int pacman_sync(alpm_list_t *targets);
/* remove.c */
int load_remove(alpm_list_t *targets);
int sync_prepare_execute(void);
/* upgrade.c */
int load_upgrade(alpm_list_t *targets);
/* trans.c */
int do_transaction(targets_t *targets);
int pacman_upgrade(alpm_list_t *targets);
#endif /* PM_PACMAN_H */

View File

@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fnmatch.h>
#include <stdlib.h>
#include <stdio.h>
@@ -29,6 +30,11 @@
#include "util.h"
#include "conf.h"
static int fnmatch_cmp(const void *pattern, const void *string)
{
return fnmatch(pattern, string, 0);
}
static int remove_target(const char *target)
{
alpm_pkg_t *pkg;
@@ -63,16 +69,28 @@ static int remove_target(const char *target)
return 0;
}
int load_remove(alpm_list_t *targets)
/**
* @brief Remove a specified list of packages.
*
* @param targets a list of packages (as strings) to remove from the system
*
* @return 0 on success, 1 on failure
*/
int pacman_remove(alpm_list_t *targets)
{
int retval = 0;
alpm_list_t *i;
alpm_list_t *i, *data = NULL;
if(targets == NULL) {
pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
return 1;
}
/* Step 0: create a new transaction */
if(trans_init(config->flags, 0) == -1) {
return 1;
}
/* Step 1: add targets to the created transaction */
for(i = targets; i; i = alpm_list_next(i)) {
char *target = i->data;
@@ -84,6 +102,81 @@ int load_remove(alpm_list_t *targets)
}
}
if(retval == 1) {
goto cleanup;
}
/* Step 2: prepare the transaction based on its type, targets and flags */
if(alpm_trans_prepare(config->handle, &data) == -1) {
alpm_errno_t err = alpm_errno(config->handle);
pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"),
alpm_strerror(err));
switch(err) {
case ALPM_ERR_UNSATISFIED_DEPS:
for(i = data; i; i = alpm_list_next(i)) {
alpm_depmissing_t *miss = i->data;
char *depstring = alpm_dep_compute_string(miss->depend);
colon_printf(_("removing %s breaks dependency '%s' required by %s\n"),
miss->causingpkg, depstring, miss->target);
free(depstring);
alpm_depmissing_free(miss);
}
break;
default:
break;
}
alpm_list_free(data);
retval = 1;
goto cleanup;
}
/* Search for holdpkg in target list */
int holdpkg = 0;
for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) {
alpm_pkg_t *pkg = i->data;
if(alpm_list_find(config->holdpkg, alpm_pkg_get_name(pkg), fnmatch_cmp)) {
pm_printf(ALPM_LOG_WARNING, _("%s is designated as a HoldPkg.\n"),
alpm_pkg_get_name(pkg));
holdpkg = 1;
}
}
if(holdpkg && (noyes(_("HoldPkg was found in target list. Do you want to continue?")) == 0)) {
retval = 1;
goto cleanup;
}
/* Step 3: actually perform the removal */
alpm_list_t *pkglist = alpm_trans_get_remove(config->handle);
if(pkglist == NULL) {
printf(_(" there is nothing to do\n"));
goto cleanup; /* we are done */
}
if(config->print) {
print_packages(pkglist);
goto cleanup;
}
/* print targets and ask user confirmation */
display_targets();
printf("\n");
if(yesno(_("Do you want to remove these packages?")) == 0) {
retval = 1;
goto cleanup;
}
if(alpm_trans_commit(config->handle, &data) == -1) {
pm_printf(ALPM_LOG_ERROR, _("failed to commit transaction (%s)\n"),
alpm_strerror(alpm_errno(config->handle)));
retval = 1;
}
FREELIST(data);
/* Step 4: release transaction resources */
cleanup:
if(trans_release() == -1) {
retval = 1;
}
return retval;
}

View File

@@ -35,6 +35,7 @@
#include "pacman.h"
#include "util.h"
#include "package.h"
#include "callback.h"
#include "conf.h"
static int unlink_verbose(const char *pathname, int ignore_missing)
@@ -83,7 +84,7 @@ static int sync_cleandb(const char *dbpath)
/* build the full path */
len = snprintf(path, PATH_MAX, "%s%s", dbpath, dname);
if(len >= PATH_MAX) {
if(len > PATH_MAX) {
pm_printf(ALPM_LOG_ERROR, _("could not remove %s%s: path exceeds PATH_MAX\n"),
dbpath, dname);
}
@@ -244,7 +245,7 @@ static int sync_cleancache(int level)
/* build the full filepath */
len=snprintf(path, PATH_MAX, "%s%s", cachedir, ent->d_name);
if(len >= PATH_MAX) {
if(len > PATH_MAX) {
pm_printf(ALPM_LOG_ERROR, _("skipping %s%s: path exceeds PATH_MAX\n"),
cachedir, ent->d_name);
continue;
@@ -363,8 +364,6 @@ static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets)
}
}
if(!found) {
pm_printf(ALPM_LOG_ERROR,
_("package group '%s' was not found\n"), grpname);
ret = 1;
}
}
@@ -521,6 +520,383 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)
return ret;
}
static alpm_db_t *get_db(const char *dbname)
{
alpm_list_t *i;
for(i = alpm_get_syncdbs(config->handle); i; i = i->next) {
alpm_db_t *db = i->data;
if(strcmp(alpm_db_get_name(db), dbname) == 0) {
return db;
}
}
return NULL;
}
static int process_pkg(alpm_pkg_t *pkg)
{
int ret = alpm_add_pkg(config->handle, pkg);
if(ret == -1) {
alpm_errno_t err = alpm_errno(config->handle);
pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", alpm_pkg_get_name(pkg), alpm_strerror(err));
return 1;
}
config->explicit_adds = alpm_list_add(config->explicit_adds, pkg);
return 0;
}
static int group_exists(alpm_list_t *dbs, const char *name)
{
alpm_list_t *i;
for(i = dbs; i; i = i->next) {
alpm_db_t *db = i->data;
if(alpm_db_get_group(db, name)) {
return 1;
}
}
return 0;
}
static int process_group(alpm_list_t *dbs, const char *group, int error)
{
int ret = 0;
alpm_list_t *i;
alpm_list_t *pkgs = alpm_find_group_pkgs(dbs, group);
int count = alpm_list_count(pkgs);
if(!count) {
if(group_exists(dbs, group)) {
return 0;
}
pm_printf(ALPM_LOG_ERROR, _("target not found: %s\n"), group);
return 1;
}
if(error) {
/* we already know another target errored. there is no reason to prompt the
* user here; we already validated the group name so just move on since we
* won't actually be installing anything anyway. */
goto cleanup;
}
if(config->print == 0) {
char *array = malloc(count);
int n = 0;
const colstr_t *colstr = &config->colstr;
colon_printf(_n("There is %d member in group %s%s%s:\n",
"There are %d members in group %s%s%s:\n", count),
count, colstr->groups, group, colstr->title);
select_display(pkgs);
if(!array) {
ret = 1;
goto cleanup;
}
if(multiselect_question(array, count)) {
ret = 1;
free(array);
goto cleanup;
}
for(i = pkgs, n = 0; i; i = alpm_list_next(i)) {
alpm_pkg_t *pkg = i->data;
if(array[n++] == 0) {
continue;
}
if(process_pkg(pkg) == 1) {
ret = 1;
free(array);
goto cleanup;
}
}
free(array);
} else {
for(i = pkgs; i; i = alpm_list_next(i)) {
alpm_pkg_t *pkg = i->data;
if(process_pkg(pkg) == 1) {
ret = 1;
goto cleanup;
}
}
}
cleanup:
alpm_list_free(pkgs);
return ret;
}
static int process_targname(alpm_list_t *dblist, const char *targname,
int error)
{
alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, targname);
/* skip ignored packages when user says no */
if(alpm_errno(config->handle) == ALPM_ERR_PKG_IGNORED) {
pm_printf(ALPM_LOG_WARNING, _("skipping target: %s\n"), targname);
return 0;
}
if(pkg) {
return process_pkg(pkg);
}
/* fallback on group */
return process_group(dblist, targname, error);
}
static int process_target(const char *target, int error)
{
/* process targets */
char *targstring = strdup(target);
char *targname = strchr(targstring, '/');
int ret = 0;
alpm_list_t *dblist;
if(targname && targname != targstring) {
alpm_db_t *db;
const char *dbname;
int usage;
*targname = '\0';
targname++;
dbname = targstring;
db = get_db(dbname);
if(!db) {
pm_printf(ALPM_LOG_ERROR, _("database not found: %s\n"),
dbname);
ret = 1;
goto cleanup;
}
/* explicitly mark this repo as valid for installs since
* a repo name was given with the target */
alpm_db_get_usage(db, &usage);
alpm_db_set_usage(db, usage|ALPM_DB_USAGE_INSTALL);
dblist = alpm_list_add(NULL, db);
ret = process_targname(dblist, targname, error);
alpm_list_free(dblist);
/* restore old usage so we don't possibly disturb later
* targets */
alpm_db_set_usage(db, usage);
} else {
targname = targstring;
dblist = alpm_get_syncdbs(config->handle);
ret = process_targname(dblist, targname, error);
}
cleanup:
free(targstring);
if(ret && access(target, R_OK) == 0) {
pm_printf(ALPM_LOG_WARNING,
_("'%s' is a file, did you mean %s instead of %s?\n"),
target, "-U/--upgrade", "-S/--sync");
}
return ret;
}
static int sync_trans(alpm_list_t *targets)
{
int retval = 0;
alpm_list_t *i;
/* Step 1: create a new transaction... */
if(trans_init(config->flags, 1) == -1) {
return 1;
}
/* process targets */
for(i = targets; i; i = alpm_list_next(i)) {
const char *targ = i->data;
if(process_target(targ, retval) == 1) {
retval = 1;
}
}
if(retval) {
trans_release();
return retval;
}
if(config->op_s_upgrade) {
if(!config->print) {
colon_printf(_("Starting full system upgrade...\n"));
alpm_logaction(config->handle, PACMAN_CALLER_PREFIX,
"starting full system upgrade\n");
}
if(alpm_sync_sysupgrade(config->handle, config->op_s_upgrade >= 2) == -1) {
pm_printf(ALPM_LOG_ERROR, "%s\n", alpm_strerror(alpm_errno(config->handle)));
trans_release();
return 1;
}
}
return sync_prepare_execute();
}
static void print_broken_dep(alpm_depmissing_t *miss)
{
char *depstring = alpm_dep_compute_string(miss->depend);
alpm_list_t *trans_add = alpm_trans_get_add(config->handle);
alpm_pkg_t *pkg;
if(miss->causingpkg == NULL) {
/* package being installed/upgraded has unresolved dependency */
colon_printf(_("unable to satisfy dependency '%s' required by %s\n"),
depstring, miss->target);
} else if((pkg = alpm_pkg_find(trans_add, miss->causingpkg))) {
/* upgrading a package breaks a local dependency */
colon_printf(_("installing %s (%s) breaks dependency '%s' required by %s\n"),
miss->causingpkg, alpm_pkg_get_version(pkg), depstring, miss->target);
} else {
/* removing a package breaks a local dependency */
colon_printf(_("removing %s breaks dependency '%s' required by %s\n"),
miss->causingpkg, depstring, miss->target);
}
free(depstring);
}
int sync_prepare_execute(void)
{
alpm_list_t *i, *packages, *data = NULL;
int retval = 0;
/* Step 2: "compute" the transaction based on targets and flags */
if(alpm_trans_prepare(config->handle, &data) == -1) {
alpm_errno_t err = alpm_errno(config->handle);
pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"),
alpm_strerror(err));
switch(err) {
case ALPM_ERR_PKG_INVALID_ARCH:
for(i = data; i; i = alpm_list_next(i)) {
char *pkg = i->data;
colon_printf(_("package %s does not have a valid architecture\n"), pkg);
free(pkg);
}
break;
case ALPM_ERR_UNSATISFIED_DEPS:
for(i = data; i; i = alpm_list_next(i)) {
print_broken_dep(i->data);
alpm_depmissing_free(i->data);
}
break;
case ALPM_ERR_CONFLICTING_DEPS:
for(i = data; i; i = alpm_list_next(i)) {
alpm_conflict_t *conflict = i->data;
/* only print reason if it contains new information */
if(conflict->reason->mod == ALPM_DEP_MOD_ANY) {
colon_printf(_("%s-%s and %s-%s are in conflict\n"),
alpm_pkg_get_name(conflict->package1),
alpm_pkg_get_version(conflict->package1),
alpm_pkg_get_name(conflict->package2),
alpm_pkg_get_version(conflict->package2));
} else {
char *reason = alpm_dep_compute_string(conflict->reason);
colon_printf(_("%s-%s and %s-%s are in conflict (%s)\n"),
alpm_pkg_get_name(conflict->package1),
alpm_pkg_get_version(conflict->package1),
alpm_pkg_get_name(conflict->package2),
alpm_pkg_get_version(conflict->package2),
reason);
free(reason);
}
alpm_conflict_free(conflict);
}
break;
default:
break;
}
retval = 1;
goto cleanup;
}
packages = alpm_trans_get_add(config->handle);
if(packages == NULL) {
/* nothing to do: just exit without complaining */
if(!config->print) {
printf(_(" there is nothing to do\n"));
}
goto cleanup;
}
/* Step 3: actually perform the operation */
if(config->print) {
print_packages(packages);
goto cleanup;
}
display_targets();
printf("\n");
int confirm;
if(config->op_s_downloadonly) {
confirm = yesno(_("Proceed with download?"));
} else {
confirm = yesno(_("Proceed with installation?"));
}
if(!confirm) {
retval = 1;
goto cleanup;
}
multibar_move_completed_up(true);
if(alpm_trans_commit(config->handle, &data) == -1) {
alpm_errno_t err = alpm_errno(config->handle);
pm_printf(ALPM_LOG_ERROR, _("failed to commit transaction (%s)\n"),
alpm_strerror(err));
switch(err) {
case ALPM_ERR_FILE_CONFLICTS:
for(i = data; i; i = alpm_list_next(i)) {
alpm_fileconflict_t *conflict = i->data;
switch(conflict->type) {
case ALPM_FILECONFLICT_TARGET:
fprintf(stderr, _("%s exists in both '%s' and '%s'\n"),
conflict->file, conflict->target, conflict->ctarget);
break;
case ALPM_FILECONFLICT_FILESYSTEM:
if(conflict->ctarget[0]) {
fprintf(stderr, _("%s: %s exists in filesystem (owned by %s)\n"),
conflict->target, conflict->file, conflict->ctarget);
} else {
fprintf(stderr, _("%s: %s exists in filesystem\n"),
conflict->target, conflict->file);
}
break;
}
alpm_fileconflict_free(conflict);
}
break;
case ALPM_ERR_PKG_INVALID:
case ALPM_ERR_PKG_INVALID_CHECKSUM:
case ALPM_ERR_PKG_INVALID_SIG:
for(i = data; i; i = alpm_list_next(i)) {
char *filename = i->data;
fprintf(stderr, _("%s is invalid or corrupted\n"), filename);
free(filename);
}
break;
default:
break;
}
/* TODO: stderr? */
printf(_("Errors occurred, no packages were upgraded.\n"));
retval = 1;
goto cleanup;
}
/* Step 4: release transaction resources */
cleanup:
alpm_list_free(data);
if(trans_release() == -1) {
retval = 1;
}
return retval;
}
int pacman_sync(alpm_list_t *targets)
{
alpm_list_t *sync_dbs = NULL;
@@ -543,8 +919,26 @@ int pacman_sync(alpm_list_t *targets)
return ret;
}
if(check_syncdbs(1, 0)) {
return 1;
}
sync_dbs = alpm_get_syncdbs(config->handle);
if(config->op_s_sync) {
/* grab a fresh package list */
colon_printf(_("Synchronizing package databases...\n"));
alpm_logaction(config->handle, PACMAN_CALLER_PREFIX,
"synchronizing package lists\n");
if(!sync_syncdbs(config->op_s_sync, sync_dbs)) {
return 1;
}
}
if(check_syncdbs(1, 1)) {
return 1;
}
/* search for a package */
if(config->op_s_search) {
return sync_search(sync_dbs, targets);
@@ -566,9 +960,17 @@ int pacman_sync(alpm_list_t *targets)
}
if(targets == NULL) {
pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
return 1;
if(config->op_s_upgrade) {
/* proceed */
} else if(config->op_s_sync) {
return 0;
} else {
/* don't proceed here unless we have an operation that doesn't require a
* target list */
pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
return 1;
}
}
return 0;
return sync_trans(targets);
}

View File

@@ -1,499 +0,0 @@
/*
* trans.c
*
* Copyright (c) 2006-2021 Pacman Development Team <pacman-dev(a)archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet(a)zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fnmatch.h>
#include <alpm.h>
#include <alpm_list.h>
/* pacman */
#include "pacman.h"
#include "callback.h"
#include "conf.h"
#include "util.h"
static int fnmatch_cmp(const void *pattern, const void *string)
{
return fnmatch(pattern, string, 0);
}
static void print_broken_dep(alpm_depmissing_t *miss)
{
char *depstring = alpm_dep_compute_string(miss->depend);
alpm_list_t *trans_add = alpm_trans_get_add(config->handle);
alpm_pkg_t *pkg;
if(miss->causingpkg == NULL) {
/* package being installed/upgraded has unresolved dependency */
colon_printf(_("unable to satisfy dependency '%s' required by %s\n"),
depstring, miss->target);
} else if((pkg = alpm_pkg_find(trans_add, miss->causingpkg))) {
/* upgrading a package breaks a local dependency */
colon_printf(_("installing %s (%s) breaks dependency '%s' required by %s\n"),
miss->causingpkg, alpm_pkg_get_version(pkg), depstring, miss->target);
} else {
/* removing a package breaks a local dependency */
colon_printf(_("removing %s breaks dependency '%s' required by %s\n"),
miss->causingpkg, depstring, miss->target);
}
free(depstring);
}
static void handle_trans_prepare_error(alpm_list_t *data)
{
alpm_errno_t err = alpm_errno(config->handle);
alpm_list_t *i;
pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"),
alpm_strerror(err));
switch(err) {
case ALPM_ERR_PKG_INVALID_ARCH:
for(i = data; i; i = alpm_list_next(i)) {
char *pkg = i->data;
colon_printf(_("package %s does not have a valid architecture\n"), pkg);
free(pkg);
}
break;
case ALPM_ERR_UNSATISFIED_DEPS:
for(i = data; i; i = alpm_list_next(i)) {
print_broken_dep(i->data);
alpm_depmissing_free(i->data);
}
break;
case ALPM_ERR_CONFLICTING_DEPS:
for(i = data; i; i = alpm_list_next(i)) {
alpm_conflict_t *conflict = i->data;
/* only print reason if it contains new information */
if(conflict->reason->mod == ALPM_DEP_MOD_ANY) {
colon_printf(_("%s-%s and %s-%s are in conflict\n"),
alpm_pkg_get_name(conflict->package1),
alpm_pkg_get_version(conflict->package1),
alpm_pkg_get_name(conflict->package2),
alpm_pkg_get_version(conflict->package2));
} else {
char *reason = alpm_dep_compute_string(conflict->reason);
colon_printf(_("%s-%s and %s-%s are in conflict (%s)\n"),
alpm_pkg_get_name(conflict->package1),
alpm_pkg_get_version(conflict->package1),
alpm_pkg_get_name(conflict->package2),
alpm_pkg_get_version(conflict->package2),
reason);
free(reason);
}
alpm_conflict_free(conflict);
}
break;
default:
break;
}
}
static void handle_trans_commit_error(alpm_list_t *data) {
alpm_errno_t err = alpm_errno(config->handle);
alpm_list_t *i;
pm_printf(ALPM_LOG_ERROR, _("failed to commit transaction (%s)\n"),
alpm_strerror(err));
switch(err) {
case ALPM_ERR_FILE_CONFLICTS:
for(i = data; i; i = alpm_list_next(i)) {
alpm_fileconflict_t *conflict = i->data;
switch(conflict->type) {
case ALPM_FILECONFLICT_TARGET:
fprintf(stderr, _("%s exists in both '%s' and '%s'\n"),
conflict->file, conflict->target, conflict->ctarget);
break;
case ALPM_FILECONFLICT_FILESYSTEM:
if(conflict->ctarget[0]) {
fprintf(stderr, _("%s: %s exists in filesystem (owned by %s)\n"),
conflict->target, conflict->file, conflict->ctarget);
} else {
fprintf(stderr, _("%s: %s exists in filesystem\n"),
conflict->target, conflict->file);
}
break;
}
alpm_fileconflict_free(conflict);
}
break;
case ALPM_ERR_PKG_INVALID:
case ALPM_ERR_PKG_INVALID_CHECKSUM:
case ALPM_ERR_PKG_INVALID_SIG:
for(i = data; i; i = alpm_list_next(i)) {
char *filename = i->data;
fprintf(stderr, _("%s is invalid or corrupted\n"), filename);
free(filename);
}
break;
default:
break;
}
/* TODO: stderr? */
printf(_("Errors occurred, no packages were upgraded.\n"));
}
static int trans_prepare_execute(void)
{
alpm_list_t *i, *packages, *remove_packages, *data = NULL;
int retval = 0;
/* Step 2: "compute" the transaction based on targets and flags */
if(alpm_trans_prepare(config->handle, &data) == -1) {
handle_trans_prepare_error(data);
retval = 1;
goto cleanup;
}
packages = alpm_trans_get_add(config->handle);
remove_packages = alpm_trans_get_remove(config->handle);
if(packages == NULL && remove_packages == NULL) {
/* nothing to do: just exit without complaining */
if(!config->print) {
printf(_(" there is nothing to do\n"));
}
goto cleanup;
}
/* Search for holdpkg in target list */
int holdpkg = 0;
for(i = remove_packages; i; i = alpm_list_next(i)) {
alpm_pkg_t *pkg = i->data;
if(alpm_list_find(config->holdpkg, alpm_pkg_get_name(pkg), fnmatch_cmp)) {
pm_printf(ALPM_LOG_WARNING, _("%s is designated as a HoldPkg.\n"),
alpm_pkg_get_name(pkg));
holdpkg = 1;
}
}
if(holdpkg && (noyes(_("HoldPkg was found in target list. Do you want to continue?")) == 0)) {
retval = 1;
goto cleanup;
}
/* Step 3: actually perform the operation */
if(config->print) {
print_packages(packages);
print_packages(remove_packages);
goto cleanup;
}
display_targets();
printf("\n");
int confirm;
if(config->op_s_downloadonly) {
confirm = yesno(_("Proceed with download?"));
} else {
confirm = yesno(_("Proceed with installation?"));
}
if(!confirm) {
retval = 1;
goto cleanup;
}
multibar_move_completed_up(true);
if(alpm_trans_commit(config->handle, &data) == -1) {
handle_trans_commit_error(data);
retval = 1;
goto cleanup;
}
/* Step 4: release transaction resources */
cleanup:
alpm_list_free(data);
if(trans_release() == -1) {
retval = 1;
}
return retval;
}
static int group_exists(alpm_list_t *dbs, const char *name)
{
alpm_list_t *i;
for(i = dbs; i; i = i->next) {
alpm_db_t *db = i->data;
if(alpm_db_get_group(db, name)) {
return 1;
}
}
return 0;
}
static alpm_db_t *get_db(const char *dbname)
{
alpm_list_t *i;
for(i = alpm_get_syncdbs(config->handle); i; i = i->next) {
alpm_db_t *db = i->data;
if(strcmp(alpm_db_get_name(db), dbname) == 0) {
return db;
}
}
return NULL;
}
static int process_pkg(alpm_pkg_t *pkg)
{
int ret = alpm_add_pkg(config->handle, pkg);
if(ret == -1) {
alpm_errno_t err = alpm_errno(config->handle);
pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", alpm_pkg_get_name(pkg), alpm_strerror(err));
return 1;
}
config->explicit_adds = alpm_list_add(config->explicit_adds, pkg);
return 0;
}
static int process_group(alpm_list_t *dbs, const char *group, int error)
{
int ret = 0;
alpm_list_t *i;
alpm_list_t *pkgs = alpm_find_group_pkgs(dbs, group);
int count = alpm_list_count(pkgs);
if(!count) {
if(group_exists(dbs, group)) {
return 0;
}
pm_printf(ALPM_LOG_ERROR, _("target not found: %s\n"), group);
return 1;
}
if(error) {
/* we already know another target errored. there is no reason to prompt the
* user here; we already validated the group name so just move on since we
* won't actually be installing anything anyway. */
goto cleanup;
}
if(config->print == 0) {
char *array = malloc(count);
int n = 0;
const colstr_t *colstr = &config->colstr;
colon_printf(_n("There is %d member in group %s%s%s:\n",
"There are %d members in group %s%s%s:\n", count),
count, colstr->groups, group, colstr->title);
select_display(pkgs);
if(!array) {
ret = 1;
goto cleanup;
}
if(multiselect_question(array, count)) {
ret = 1;
free(array);
goto cleanup;
}
for(i = pkgs, n = 0; i; i = alpm_list_next(i)) {
alpm_pkg_t *pkg = i->data;
if(array[n++] == 0) {
continue;
}
if(process_pkg(pkg) == 1) {
ret = 1;
free(array);
goto cleanup;
}
}
free(array);
} else {
for(i = pkgs; i; i = alpm_list_next(i)) {
alpm_pkg_t *pkg = i->data;
if(process_pkg(pkg) == 1) {
ret = 1;
goto cleanup;
}
}
}
cleanup:
alpm_list_free(pkgs);
return ret;
}
static int process_targname(alpm_list_t *dblist, const char *targname,
int error)
{
alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, targname);
/* skip ignored packages when user says no */
if(alpm_errno(config->handle) == ALPM_ERR_PKG_IGNORED) {
pm_printf(ALPM_LOG_WARNING, _("skipping target: %s\n"), targname);
return 0;
}
if(pkg) {
return process_pkg(pkg);
}
/* fallback on group */
return process_group(dblist, targname, error);
}
static int process_target(const char *target, int error)
{
/* process targets */
char *targstring = strdup(target);
char *targname = strchr(targstring, '/');
int ret = 0;
alpm_list_t *dblist;
if(targname && targname != targstring) {
alpm_db_t *db;
const char *dbname;
int usage;
*targname = '\0';
targname++;
dbname = targstring;
db = get_db(dbname);
if(!db) {
pm_printf(ALPM_LOG_ERROR, _("database not found: %s\n"),
dbname);
ret = 1;
goto cleanup;
}
/* explicitly mark this repo as valid for installs since
* a repo name was given with the target */
alpm_db_get_usage(db, &usage);
alpm_db_set_usage(db, usage|ALPM_DB_USAGE_INSTALL);
dblist = alpm_list_add(NULL, db);
ret = process_targname(dblist, targname, error);
alpm_list_free(dblist);
/* restore old usage so we don't possibly disturb later
* targets */
alpm_db_set_usage(db, usage);
} else {
targname = targstring;
dblist = alpm_get_syncdbs(config->handle);
ret = process_targname(dblist, targname, error);
}
cleanup:
free(targstring);
if(ret && access(target, R_OK) == 0) {
pm_printf(ALPM_LOG_WARNING,
_("'%s' is a file, did you mean %s instead of %s?\n"),
target, "-U/--upgrade", "-S/--sync");
}
return ret;
}
static int load_sync(alpm_list_t *targets)
{
int retval = 0;
alpm_list_t *i;
if(targets == NULL && !config->op_s_upgrade && !config->op_s_sync) {
pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
return 1;
}
/* process targets */
for(i = targets; i; i = alpm_list_next(i)) {
const char *targ = i->data;
if(process_target(targ, retval) == 1) {
retval = 1;
}
}
return retval;
}
int do_transaction(targets_t *targets) {
int need_repos = (config->op & PM_OP_SYNC);
alpm_list_t *sync_dbs;
if(targets->targets != NULL) {
pm_printf(ALPM_LOG_ERROR, _("targets must come after operation\n"));
return 1;
}
if(check_syncdbs(need_repos, 0)) {
return 1;
}
sync_dbs = alpm_get_syncdbs(config->handle);
if(config->op_s_sync) {
/* grab a fresh package list */
colon_printf(_("Synchronizing package databases...\n"));
alpm_logaction(config->handle, PACMAN_CALLER_PREFIX,
"synchronizing package lists\n");
if(!sync_syncdbs(config->op_s_sync, sync_dbs)) {
return 1;
}
}
if(check_syncdbs(need_repos, 1)) {
return 1;
}
if(config->op_s_clean || config->op_s_search || config->op_s_info
|| config->op_q_list || config->group) {
return pacman_sync(targets->sync);
}
/* Step 1: create a new transaction... */
if(trans_init(config->flags, 1) == -1) {
return 1;
}
if(config->op & PM_OP_SYNC && load_sync(targets->sync)) {
goto cleanup;
}
if(config->op & PM_OP_REMOVE && load_remove(targets->remove)) {
goto cleanup;
}
if(config->op & PM_OP_UPGRADE && load_upgrade(targets->upgrade)) {
goto cleanup;
}
if(config->op_s_upgrade) {
if(!config->print) {
colon_printf(_("Starting full system upgrade...\n"));
alpm_logaction(config->handle, PACMAN_CALLER_PREFIX,
"starting full system upgrade\n");
}
if(alpm_sync_sysupgrade(config->handle, config->op_s_upgrade >= 2) == -1) {
pm_printf(ALPM_LOG_ERROR, "%s\n", alpm_strerror(alpm_errno(config->handle)));
trans_release();
return 1;
}
}
return trans_prepare_execute();
cleanup:
trans_release();
return 1;
}

View File

@@ -65,7 +65,7 @@ static int load_packages(alpm_list_t *targets, int siglevel)
*
* @return 0 on success, 1 on failure
*/
int load_upgrade(alpm_list_t *targets)
int pacman_upgrade(alpm_list_t *targets)
{
int retval = 0;
alpm_list_t *remote_targets = NULL, *fetched_files = NULL;
@@ -88,6 +88,15 @@ int load_upgrade(alpm_list_t *targets)
if(remote_targets) {
retval = alpm_fetch_pkgurl(config->handle, remote_targets, &fetched_files);
if(retval) {
goto fail_free;
}
}
/* Step 1: create a new transaction */
if(trans_init(config->flags, 1) == -1) {
retval = 1;
goto fail_free;
}
if(!config->print) {
@@ -96,10 +105,23 @@ int load_upgrade(alpm_list_t *targets)
retval |= load_packages(local_targets, alpm_option_get_local_file_siglevel(config->handle));
retval |= load_packages(fetched_files, alpm_option_get_remote_file_siglevel(config->handle));
if(retval) {
goto fail_release;
}
alpm_list_free(remote_targets);
alpm_list_free(local_targets);
FREELIST(fetched_files);
/* now that targets are resolved, we can hand it all off to the sync code */
return sync_prepare_execute();
fail_release:
trans_release();
fail_free:
alpm_list_free(remote_targets);
alpm_list_free(local_targets);
FREELIST(fetched_files);
return retval;
}

View File

@@ -10,9 +10,9 @@ lp3 = pmpkg("pkg3")
lp3.depends = [ "pkg1" ]
self.addpkg2db("local", lp3)
self.args = "-R --unneeded pkg1 pkg2"
self.args = "-Ru pkg1 pkg2"
self.addrule("PACMAN_RETCODE=0")
self.addrule("PKG_EXIST=pkg1")
self.addrule("!PKG_EXIST=pkg2")
self.addrule("PKG_EXIST=pkg3")
self.addrule("PKG_EXIST=pkg3")

View File

@@ -1,7 +1,6 @@
self.description = 'download remote packages with -U with a URL filename'
self.require_capability("gpg")
self.require_capability("curl")
self.option['SigLevel'] = ['Required']
url = self.add_simple_http_server({
# simple

View File

@@ -115,8 +115,6 @@ def mkcfgfile(filename, root, option, db):
data = ["[options]"]
for key, value in option.items():
data.extend(["%s = %s" % (key, j) for j in value])
if "SigLevel" not in option:
data.append("SigLevel = Never\n")
# Repositories
# sort by repo name so tests can predict repo order, rather than be