libalpm: disallow partial upgrades

Detect if there's an upgrade avaliable, and if so disallow the upgrade.
This commit is contained in:
morganamilo 2024-03-16 03:54:31 +00:00
parent bae9594ac1
commit a84916d4bb
No known key found for this signature in database
GPG key ID: E48D0A8326DE47C5
6 changed files with 148 additions and 1 deletions

View file

@ -273,6 +273,8 @@ typedef enum _alpm_errno_t {
ALPM_ERR_TRANS_NOT_LOCKED, ALPM_ERR_TRANS_NOT_LOCKED,
/** A hook failed to run */ /** A hook failed to run */
ALPM_ERR_TRANS_HOOK_FAILED, ALPM_ERR_TRANS_HOOK_FAILED,
/* The transaction is a partial upgrade */
ALPM_ERR_TRANS_PARTIAL_UPGRADE,
/* Packages */ /* Packages */
/** Package not found */ /** Package not found */
ALPM_ERR_PKG_NOT_FOUND, ALPM_ERR_PKG_NOT_FOUND,
@ -1477,6 +1479,19 @@ int alpm_db_set_usage(alpm_db_t *db, int usage);
*/ */
int alpm_db_get_usage(alpm_db_t *db, int *usage); int alpm_db_get_usage(alpm_db_t *db, int *usage);
/** Set if a database may perform partial upgrades.
* @param db pointer to the package database
* @param partial 1 to allow, 0 to disallow
* @return 0 on success, or -1 on error
*/
int alpm_db_set_allow_partial_upgrades(alpm_db_t *db, int allow);
/** Set if a database allows partial upgrades.
* @param db pointer to the package database
* @return 1 if allowed, 0 if not, -1 on error
*/
int alpm_db_get_allow_partial_upgrades(alpm_db_t *db);
/* End of usage accessors */ /* End of usage accessors */
/** @} */ /** @} */
@ -2775,7 +2790,8 @@ typedef enum _alpm_transflag_t {
ALPM_TRANS_FLAG_NOSCRIPTLET = (1 << 10), ALPM_TRANS_FLAG_NOSCRIPTLET = (1 << 10),
/** Ignore dependency conflicts. */ /** Ignore dependency conflicts. */
ALPM_TRANS_FLAG_NOCONFLICTS = (1 << 11), ALPM_TRANS_FLAG_NOCONFLICTS = (1 << 11),
/* (1 << 12) flag can go here */ /** Allow partial upgrades */
ALPM_TRANS_FLAG_ALLOWPARTIAL = (1 << 12),
/** Do not install a package if it is already installed and up to date. */ /** Do not install a package if it is already installed and up to date. */
ALPM_TRANS_FLAG_NEEDED = (1 << 13), ALPM_TRANS_FLAG_NEEDED = (1 << 13),
/** Use ALPM_PKG_REASON_EXPLICIT when installing packages. */ /** Use ALPM_PKG_REASON_EXPLICIT when installing packages. */

View file

@ -368,6 +368,19 @@ int SYMEXPORT alpm_db_get_usage(alpm_db_t *db, int *usage)
return 0; return 0;
} }
int SYMEXPORT alpm_db_set_allow_partial_upgrades(alpm_db_t *db, int allow)
{
ASSERT(db != NULL, return -1);
db->allow_partial = allow ? 1 : 0;
return 0;
}
int SYMEXPORT alpm_db_get_allow_partial_upgrades(alpm_db_t *db)
{
ASSERT(db != NULL, return -1);
return db->allow_partial;
}
alpm_db_t *_alpm_db_new(const char *treename, int is_local) alpm_db_t *_alpm_db_new(const char *treename, int is_local)
{ {
alpm_db_t *db; alpm_db_t *db;

View file

@ -80,6 +80,8 @@ struct _alpm_db_t {
int siglevel; int siglevel;
/* alpm_db_usage_t */ /* alpm_db_usage_t */
int usage; int usage;
int allow_partial;
}; };

View file

@ -104,6 +104,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("transaction commit attempt when database is not locked"); return _("transaction commit attempt when database is not locked");
case ALPM_ERR_TRANS_HOOK_FAILED: case ALPM_ERR_TRANS_HOOK_FAILED:
return _("failed to run transaction hooks"); return _("failed to run transaction hooks");
case ALPM_ERR_TRANS_PARTIAL_UPGRADE:
return _("partial upgrade");
/* Packages */ /* Packages */
case ALPM_ERR_PKG_NOT_FOUND: case ALPM_ERR_PKG_NOT_FOUND:
return _("could not find or read package"); return _("could not find or read package");

View file

@ -249,6 +249,8 @@ int SYMEXPORT alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade)
} }
} }
trans->sysupgrade = enable_downgrade ? 2 : 1;
return 0; return 0;
} }
@ -362,6 +364,111 @@ finish:
return ret; return ret;
} }
static int has_replacment(alpm_db_t *sdb, alpm_pkg_t *lpkg)
{
alpm_list_t *j, *k;
alpm_handle_t *handle = lpkg->handle;
for(j = _alpm_db_get_pkgcache(sdb); j; j = j->next) {
alpm_pkg_t *spkg = j->data;
if(alpm_pkg_should_ignore(handle, spkg)) {
continue;
}
for(k = alpm_pkg_get_replaces(spkg); k; k = k->next) {
alpm_depend_t *replace = k->data;
/* we only want to consider literal matches at this point. */
if(_alpm_depcmp_literal(lpkg, replace)) {
_alpm_log(handle, ALPM_LOG_DEBUG, "partial upgrade due to %s haivng replacment\n", lpkg->name);
return 1;
}
}
}
return 0;
}
static int is_partial_upgrade(alpm_handle_t *handle)
{
alpm_list_t *i, *j;
alpm_trans_t *trans = handle->trans;
alpm_db_t *localdb = handle->db_local;
int from_sync = 0;
if(trans->sysupgrade == 2) {
return 0;
}
for(i = trans->add; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
if (pkg->origin == ALPM_PKG_FROM_SYNCDB){
alpm_db_t *db = alpm_pkg_get_db(pkg);
if(!db->allow_partial) {
alpm_pkg_t *lpkg = alpm_db_get_pkg(localdb, pkg->name);
/* let transaction pass if reinstall */
if(!lpkg || _alpm_pkg_compare_versions(pkg, lpkg) != 0) {
from_sync = 1;
break;
}
}
}
}
for(i = _alpm_db_get_pkgcache(localdb); i; i = i->next) {
alpm_pkg_t *lpkg = i->data;
if(alpm_pkg_find(trans->add, lpkg->name) || alpm_pkg_find(trans->remove, lpkg->name)
|| alpm_pkg_should_ignore(handle, lpkg)) {
continue;
}
/* Search for replacers then literal (if no replacer) in each sync database. */
for(j = handle->dbs_sync; j; j = j->next) {
alpm_db_t *sdb = j->data;
alpm_pkg_t *spkg;
if(!(sdb->usage & ALPM_DB_USAGE_UPGRADE)) {
/* jump to next db */
continue;
}
if(!sdb->allow_partial && !trans->sysupgrade && has_replacment(sdb, lpkg)) {
return 1;
}
if(!from_sync) {
/* jump to next local package */
break;
}
spkg = _alpm_db_get_pkgfromcache(sdb, lpkg->name);
if(!spkg || alpm_pkg_should_ignore(handle, spkg)) {
/* jump to next db */
continue;
}
if(sdb->allow_partial) {
/* jump to next local package */
break;
}
/* Check sdb */
if(_alpm_pkg_compare_versions(spkg, lpkg) != 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, "partial upgrade due to upgrade for %s\n", lpkg->name);
return 1;
}
/* jump to next local package */
break;
}
}
return 0;
}
int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)
{ {
alpm_list_t *i, *j; alpm_list_t *i, *j;
@ -680,6 +787,12 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)
} }
} }
if(!(trans->flags & ALPM_TRANS_FLAG_ALLOWPARTIAL) && !(trans->flags & ALPM_TRANS_FLAG_NODEPVERSION)
&& is_partial_upgrade(handle)) {
handle->pm_errno = ALPM_ERR_TRANS_PARTIAL_UPGRADE;
ret = -1;
}
cleanup: cleanup:
return ret; return ret;
} }

View file

@ -39,6 +39,7 @@ typedef enum _alpm_transstate_t {
typedef struct _alpm_trans_t { typedef struct _alpm_trans_t {
/* bitfield of alpm_transflag_t flags */ /* bitfield of alpm_transflag_t flags */
int flags; int flags;
int sysupgrade;
alpm_transstate_t state; alpm_transstate_t state;
alpm_list_t *unresolvable; /* list of (alpm_pkg_t *) */ alpm_list_t *unresolvable; /* list of (alpm_pkg_t *) */
alpm_list_t *add; /* list of (alpm_pkg_t *) */ alpm_list_t *add; /* list of (alpm_pkg_t *) */