krh@248: /* krh@248: * Copyright (C) 2008 Kristian Høgsberg krh@248: * Copyright (C) 2008 Red Hat, Inc ali@446: * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow krh@248: * krh@248: * This program is free software; you can redistribute it and/or modify krh@248: * it under the terms of the GNU General Public License as published by krh@248: * the Free Software Foundation; either version 2 of the License, or krh@248: * (at your option) any later version. krh@248: * krh@248: * This program is distributed in the hope that it will be useful, krh@248: * but WITHOUT ANY WARRANTY; without even the implied warranty of krh@248: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the krh@248: * GNU General Public License for more details. krh@248: * krh@248: * You should have received a copy of the GNU General Public License along krh@248: * with this program; if not, write to the Free Software Foundation, Inc., krh@248: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. krh@248: */ krh@248: krh@248: #define _GNU_SOURCE krh@248: ali@438: #include "config.h" krh@248: #include krh@248: #include krh@248: #include krh@248: #include krh@248: #include krh@248: #include krh@248: #include richard@301: #include krh@248: krh@248: #include "razor-internal.h" krh@248: #include "razor.h" krh@248: krh@248: static int krh@248: provider_satisfies_requirement(struct razor_property *provider, krh@248: const char *provider_strings, krh@248: uint32_t flags, krh@248: const char *required) krh@248: { krh@248: int cmp, len; krh@248: const char *provided = &provider_strings[provider->version]; krh@248: krh@248: if (!*required) krh@248: return 1; krh@248: if (!*provided) { krh@248: if (flags & RAZOR_PROPERTY_LESS) krh@248: return 0; krh@248: else krh@248: return 1; krh@248: } krh@248: krh@248: cmp = razor_versioncmp(provided, required); krh@248: krh@248: switch (flags & RAZOR_PROPERTY_RELATION_MASK) { krh@248: case RAZOR_PROPERTY_LESS: krh@248: return cmp < 0; krh@248: krh@248: case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: krh@248: if (cmp <= 0) krh@248: return 1; krh@248: /* fall through: FIXME, make sure this is correct */ krh@248: krh@248: case RAZOR_PROPERTY_EQUAL: krh@248: if (cmp == 0) krh@248: return 1; krh@248: krh@248: /* "foo == 1.1" is satisfied by "foo 1.1-2" */ krh@248: len = strlen(required); krh@248: if (!strncmp(required, provided, len) && provided[len] == '-') krh@248: return 1; krh@248: return 0; krh@248: krh@248: case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: krh@248: return cmp >= 0; krh@248: krh@248: case RAZOR_PROPERTY_GREATER: krh@248: return cmp > 0; krh@248: } krh@248: krh@248: /* shouldn't happen */ krh@248: return 0; krh@248: } krh@248: krh@248: #define TRANS_PACKAGE_PRESENT 1 krh@248: #define TRANS_PACKAGE_UPDATE 2 krh@248: #define TRANS_PROPERTY_SATISFIED 0x80000000 krh@248: krh@248: struct transaction_set { krh@248: struct razor_set *set; krh@248: uint32_t *packages; krh@248: uint32_t *properties; krh@248: }; krh@248: krh@248: struct razor_transaction { krh@248: int package_count, errors; krh@248: struct transaction_set system, upstream; krh@248: int changes; ali@369: struct razor_merger *merger; krh@248: }; krh@248: krh@248: static void krh@248: transaction_set_init(struct transaction_set *ts, struct razor_set *set) krh@248: { krh@248: int count; krh@248: ali@403: ts->set = razor_set_ref(set); krh@248: count = set->packages.size / sizeof (struct razor_package); krh@248: ts->packages = zalloc(count * sizeof *ts->packages); krh@248: count = set->properties.size / sizeof (struct razor_property); krh@248: ts->properties = zalloc(count * sizeof *ts->properties); krh@248: } krh@248: krh@248: static void krh@248: transaction_set_release(struct transaction_set *ts) krh@248: { ali@403: razor_set_unref(ts->set); krh@248: free(ts->packages); krh@248: free(ts->properties); krh@248: } krh@248: krh@248: static void krh@248: transaction_set_install_package(struct transaction_set *ts, krh@248: struct razor_package *package) krh@248: { krh@248: struct razor_package *pkgs; krh@248: struct list *prop; krh@248: int i; krh@248: krh@248: pkgs = ts->set->packages.data; krh@248: i = package - pkgs; ali@432: if (ts->packages[i] & TRANS_PACKAGE_PRESENT) krh@248: return; krh@248: ali@432: ts->packages[i] |= TRANS_PACKAGE_PRESENT; krh@248: krh@248: prop = list_first(&package->properties, &ts->set->property_pool); krh@248: while (prop) { krh@248: ts->properties[prop->data]++; krh@248: prop = list_next(prop); krh@248: } krh@248: } krh@248: krh@248: static void krh@248: transaction_set_remove_package(struct transaction_set *ts, krh@248: struct razor_package *package) krh@248: { krh@248: struct razor_package *pkgs; krh@248: struct list *prop; krh@248: int i; krh@248: krh@248: pkgs = ts->set->packages.data; krh@248: i = package - pkgs; ali@432: if (!(ts->packages[i] & TRANS_PACKAGE_PRESENT)) krh@248: return; krh@248: ali@432: ts->packages[i] &= ~TRANS_PACKAGE_PRESENT; krh@248: krh@248: prop = list_first(&package->properties, &ts->set->property_pool); krh@248: while (prop) { krh@248: ts->properties[prop->data]--; krh@248: prop = list_next(prop); krh@248: } krh@248: } krh@248: krh@269: RAZOR_EXPORT struct razor_transaction * krh@248: razor_transaction_create(struct razor_set *system, struct razor_set *upstream) krh@248: { krh@248: struct razor_transaction *trans; krh@248: struct razor_package *p, *spkgs, *pend; krh@248: krh@248: trans = zalloc(sizeof *trans); krh@248: transaction_set_init(&trans->system, system); krh@248: transaction_set_init(&trans->upstream, upstream); krh@248: krh@248: spkgs = trans->system.set->packages.data; krh@248: pend = trans->system.set->packages.data + krh@248: trans->system.set->packages.size; krh@248: for (p = spkgs; p < pend; p++) krh@248: transaction_set_install_package(&trans->system, p); krh@248: krh@248: return trans; krh@248: } krh@248: krh@269: RAZOR_EXPORT void krh@248: razor_transaction_install_package(struct razor_transaction *trans, krh@248: struct razor_package *package) krh@248: { richard@301: assert (trans != NULL); richard@301: assert (package != NULL); richard@301: krh@248: transaction_set_install_package(&trans->upstream, package); krh@248: trans->changes++; krh@248: } krh@248: krh@269: RAZOR_EXPORT void krh@248: razor_transaction_remove_package(struct razor_transaction *trans, krh@248: struct razor_package *package) krh@248: { richard@301: assert (trans != NULL); richard@301: assert (package != NULL); richard@301: krh@248: transaction_set_remove_package(&trans->system, package); krh@248: trans->changes++; krh@248: } krh@248: krh@269: RAZOR_EXPORT void krh@248: razor_transaction_update_package(struct razor_transaction *trans, krh@248: struct razor_package *package) krh@248: { krh@248: struct razor_package *spkgs, *upkgs, *end; krh@248: richard@301: assert (trans != NULL); richard@301: assert (package != NULL); richard@301: krh@248: spkgs = trans->system.set->packages.data; krh@248: upkgs = trans->upstream.set->packages.data; krh@248: end = trans->system.set->packages.data + krh@248: trans->system.set->packages.size; krh@248: if (spkgs <= package && package < end) krh@248: trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE; krh@248: else krh@248: trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE; krh@248: } krh@248: krh@248: struct prop_iter { krh@248: struct razor_property *p, *start, *end; krh@248: const char *pool; krh@248: uint32_t *present; krh@248: }; krh@248: krh@248: static void krh@248: prop_iter_init(struct prop_iter *pi, struct transaction_set *ts) krh@248: { krh@248: pi->p = ts->set->properties.data; krh@248: pi->start = ts->set->properties.data; krh@248: pi->end = ts->set->properties.data + ts->set->properties.size; krh@248: pi->pool = ts->set->string_pool.data; krh@248: pi->present = ts->properties; krh@248: } krh@248: krh@248: static int krh@248: prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p) krh@248: { krh@248: while (pi->p < pi->end) { krh@248: if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) && krh@248: (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) { krh@248: *p = pi->p++; krh@248: return 1; krh@248: } krh@248: pi->p++; krh@248: } krh@248: krh@248: return 0; krh@248: } krh@248: krh@248: static struct razor_property * krh@248: prop_iter_seek_to(struct prop_iter *pi, krh@248: uint32_t flags, const char *match) krh@248: { krh@248: uint32_t name; krh@248: krh@248: while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0) krh@248: pi->p++; krh@248: krh@248: if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0) krh@248: return NULL; krh@248: krh@248: name = pi->p->name; krh@248: while (pi->p < pi->end && krh@248: pi->p->name == name && krh@248: (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags) krh@248: pi->p++; krh@248: krh@248: if (pi->p == pi->end || pi->p->name != name) krh@248: return NULL; krh@248: krh@248: return pi->p; krh@248: } krh@248: krh@248: /* Remove packages from set that provide any of the matching (same krh@248: * name and type) providers from ppi onwards that match the krh@248: * requirement that rpi points to. */ krh@248: static void krh@248: remove_matching_providers(struct razor_transaction *trans, krh@248: struct prop_iter *ppi, krh@248: uint32_t flags, krh@248: const char *version) krh@248: { krh@248: struct razor_property *p; ali@442: struct razor_package *pkg; krh@248: struct razor_package_iterator pkg_iter; krh@248: struct razor_set *set; richard@302: const char *n, *v; krh@248: uint32_t type; krh@248: krh@248: if (ppi->present == trans->system.properties) krh@248: set = trans->system.set; krh@248: else krh@248: set = trans->upstream.set; krh@248: krh@248: type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; krh@248: for (p = ppi->p; krh@248: p < ppi->end && krh@248: p->name == ppi->p->name && krh@248: (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; krh@248: p++) { krh@248: if (!ppi->present[p - ppi->start]) krh@248: continue; krh@248: if (!provider_satisfies_requirement(p, ppi->pool, krh@248: flags, version)) krh@248: continue; krh@248: krh@248: razor_package_iterator_init_for_property(&pkg_iter, set, p); richard@302: while (razor_package_iterator_next(&pkg_iter, &pkg, richard@302: RAZOR_DETAIL_NAME, &n, richard@307: RAZOR_DETAIL_VERSION, &v, richard@307: RAZOR_DETAIL_LAST)) { ali@403: #if 0 krh@248: fprintf(stderr, "removing %s-%s\n", n, v); ali@403: #endif krh@248: razor_transaction_remove_package(trans, pkg); krh@248: } krh@248: } krh@248: } krh@248: krh@248: static void krh@248: flag_matching_providers(struct razor_transaction *trans, krh@248: struct prop_iter *ppi, krh@248: struct razor_property *r, krh@248: struct prop_iter *rpi, krh@248: unsigned int flag) krh@248: { krh@248: struct razor_property *p; krh@248: struct razor_package *pkg, *pkgs; krh@248: struct razor_package_iterator pkg_iter; krh@248: struct razor_set *set; richard@302: const char *name, *version; krh@248: uint32_t *flags, type; krh@248: krh@248: if (ppi->present == trans->system.properties) { krh@248: set = trans->system.set; krh@248: flags = trans->system.packages; krh@248: } else { krh@248: set = trans->upstream.set; krh@248: flags = trans->upstream.packages; krh@248: } krh@248: krh@248: pkgs = (struct razor_package *) set->packages.data; krh@248: type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; krh@248: for (p = ppi->p; krh@248: p < ppi->end && krh@248: p->name == ppi->p->name && krh@248: (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; krh@248: p++) { krh@248: if (!ppi->present[p - ppi->start]) krh@248: continue; krh@248: if (!provider_satisfies_requirement(p, ppi->pool, krh@248: r->flags, krh@248: &rpi->pool[r->version])) krh@248: continue; krh@248: krh@248: razor_package_iterator_init_for_property(&pkg_iter, set, p); krh@248: while (razor_package_iterator_next(&pkg_iter, &pkg, richard@302: RAZOR_DETAIL_NAME, &name, richard@307: RAZOR_DETAIL_VERSION, &version, richard@307: RAZOR_DETAIL_LAST)) { krh@248: ali@403: #if 0 krh@248: fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n", krh@248: name, version, krh@248: ppi->pool + p->name, krh@248: rpi->pool + r->name, krh@248: rpi->pool + r->version); ali@403: #endif krh@248: flags[pkg - pkgs] |= flag; krh@248: } krh@248: } krh@248: } krh@248: krh@248: static struct razor_package * krh@248: pick_matching_provider(struct razor_set *set, krh@248: struct prop_iter *ppi, krh@248: uint32_t flags, krh@248: const char *version) krh@248: { krh@248: struct razor_property *p; krh@248: struct razor_package *pkgs; krh@248: struct list *i; krh@248: uint32_t type; krh@248: krh@248: /* This is where we decide which pkgs to pull in to satisfy a krh@248: * requirement. There may be several different providers krh@248: * (different versions) and each version of a provider may krh@248: * come from a number of packages. We pick the first package krh@248: * from the first provider that matches. */ krh@248: krh@248: pkgs = set->packages.data; krh@248: type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; krh@248: for (p = ppi->p; krh@248: p < ppi->end && krh@248: p->name == ppi->p->name && krh@248: (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type && krh@248: ppi->present[p - ppi->start] == 0; krh@248: p++) { krh@248: if (!provider_satisfies_requirement(p, ppi->pool, krh@248: flags, version)) krh@248: continue; krh@248: krh@248: i = list_first(&p->packages, &set->package_pool); krh@248: krh@248: return &pkgs[i->data]; krh@248: } krh@248: krh@248: return NULL; krh@248: } krh@248: krh@248: static void krh@248: remove_obsoleted_packages(struct razor_transaction *trans) krh@248: { krh@248: struct razor_property *up; krh@248: struct prop_iter spi, upi; krh@248: krh@248: prop_iter_init(&spi, &trans->system); krh@248: prop_iter_init(&upi, &trans->upstream); krh@248: krh@248: while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) { krh@248: if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, krh@248: &upi.pool[up->name])) krh@248: continue; krh@248: remove_matching_providers(trans, &spi, up->flags, krh@248: &upi.pool[up->version]); krh@248: } krh@248: } krh@248: krh@248: static int krh@248: any_provider_satisfies_requirement(struct prop_iter *ppi, krh@248: uint32_t flags, krh@248: const char *version) krh@248: { krh@248: struct razor_property *p; krh@248: uint32_t type; krh@248: krh@248: type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK; krh@248: for (p = ppi->p; krh@248: p < ppi->end && krh@248: p->name == ppi->p->name && krh@248: (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type; krh@248: p++) { krh@248: if (ppi->present[p - ppi->start] > 0 && krh@248: provider_satisfies_requirement(p, ppi->pool, krh@248: flags, version)) krh@248: return 1; krh@248: } krh@248: krh@248: return 0; krh@248: } krh@248: krh@248: static void krh@248: clear_requires_flags(struct transaction_set *ts) krh@248: { krh@248: struct razor_property *p; krh@248: const char *pool; krh@248: int i, count; ali@368: char *sub; krh@248: krh@248: count = ts->set->properties.size / sizeof *p; krh@248: p = ts->set->properties.data; krh@248: pool = ts->set->string_pool.data; krh@248: for (i = 0; i < count; i++) { krh@248: ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED; ali@368: sub = strchr(&pool[p[i].name], '('); ali@368: if (sub && sub[strlen(sub) - 1] == ')') { ali@368: sub = strdup(sub + 1); ali@368: sub[strlen(sub) - 1] = '\0'; ali@368: if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0) ali@368: ts->properties[i] |= TRANS_PROPERTY_SATISFIED; ali@368: if (strncmp(&pool[p[i].name], "lua(", 4) == 0 && ali@368: razor_get_lua_loader(sub) && ali@368: p[i].flags & RAZOR_PROPERTY_SCRIPT_MASK) ali@368: ts->properties[i] |= TRANS_PROPERTY_SATISFIED; ali@368: free(sub); ali@368: } krh@248: } krh@248: } krh@248: krh@248: static void krh@248: mark_satisfied_requires(struct razor_transaction *trans, krh@248: struct transaction_set *rts, krh@248: struct transaction_set *pts) krh@248: { krh@248: struct prop_iter rpi, ppi; krh@248: struct razor_property *rp; krh@248: krh@248: prop_iter_init(&rpi, rts); krh@248: prop_iter_init(&ppi, pts); krh@248: krh@248: while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { krh@248: if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, krh@248: &rpi.pool[rp->name])) krh@248: continue; krh@248: krh@248: if (any_provider_satisfies_requirement(&ppi, rp->flags, krh@248: &rpi.pool[rp->version])) krh@248: rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED; krh@248: } krh@248: } krh@248: krh@248: static void krh@248: mark_all_satisfied_requires(struct razor_transaction *trans) krh@248: { krh@248: clear_requires_flags(&trans->system); krh@248: clear_requires_flags(&trans->upstream); krh@248: mark_satisfied_requires(trans, &trans->system, &trans->system); krh@248: mark_satisfied_requires(trans, &trans->system, &trans->upstream); krh@248: mark_satisfied_requires(trans, &trans->upstream, &trans->system); krh@248: mark_satisfied_requires(trans, &trans->upstream, &trans->upstream); krh@248: } krh@248: krh@248: static void krh@248: update_unsatisfied_packages(struct razor_transaction *trans) krh@248: { krh@248: struct razor_package *spkgs, *pkg; krh@248: struct razor_property *sp; krh@248: struct prop_iter spi; krh@248: struct razor_package_iterator pkg_iter; richard@302: const char *name; krh@248: krh@248: spkgs = trans->system.set->packages.data; krh@248: prop_iter_init(&spi, &trans->system); krh@248: krh@248: while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) { krh@248: if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED) krh@248: continue; krh@248: krh@248: razor_package_iterator_init_for_property(&pkg_iter, krh@248: trans->system.set, krh@248: sp); krh@248: while (razor_package_iterator_next(&pkg_iter, &pkg, richard@307: RAZOR_DETAIL_NAME, &name, richard@307: RAZOR_DETAIL_LAST)) { ali@432: if (!(trans->system.packages[pkg - spkgs] & TRANS_PACKAGE_PRESENT)) ali@432: continue; ali@432: ali@403: #if 0 krh@248: fprintf(stderr, "updating %s because %s %s %s " krh@248: "isn't satisfied\n", krh@248: name, spi.pool + sp->name, krh@248: razor_property_relation_to_string(sp), krh@248: spi.pool + sp->version); ali@403: #endif krh@248: trans->system.packages[pkg - spkgs] |= krh@248: TRANS_PACKAGE_UPDATE; krh@248: } krh@248: } krh@248: } krh@248: krh@269: RAZOR_EXPORT void krh@248: razor_transaction_update_all(struct razor_transaction *trans) krh@248: { krh@248: struct razor_package *p; krh@248: int i, count; krh@248: richard@301: assert (trans != NULL); richard@301: krh@248: count = trans->system.set->packages.size / sizeof *p; krh@248: for (i = 0; i < count; i++) krh@248: trans->system.packages[i] |= TRANS_PACKAGE_UPDATE; krh@248: } krh@248: krh@248: static void krh@248: update_conflicted_packages(struct razor_transaction *trans) krh@248: { krh@248: struct razor_package *pkg, *spkgs; krh@248: struct razor_property *up, *sp; krh@248: struct prop_iter spi, upi; krh@248: struct razor_package_iterator pkg_iter; richard@302: const char *name, *version; krh@248: krh@248: spkgs = trans->system.set->packages.data; krh@248: prop_iter_init(&spi, &trans->system); krh@248: prop_iter_init(&upi, &trans->upstream); krh@248: krh@248: while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) { krh@248: if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES, krh@248: &spi.pool[sp->name])) krh@248: continue; krh@248: krh@248: if (!any_provider_satisfies_requirement(&upi, sp->flags, krh@248: &spi.pool[sp->version])) krh@248: continue; krh@248: krh@248: razor_package_iterator_init_for_property(&pkg_iter, krh@248: trans->system.set, krh@248: sp); krh@248: while (razor_package_iterator_next(&pkg_iter, &pkg, richard@302: RAZOR_DETAIL_NAME, &name, richard@307: RAZOR_DETAIL_VERSION, &version, richard@307: RAZOR_DETAIL_LAST)) { ali@403: #if 0 jbowes@286: fprintf(stderr, "updating %s %s because it " jbowes@286: "conflicts with %s\n", krh@248: name, version, spi.pool + sp->name); ali@403: #endif krh@248: trans->system.packages[pkg - spkgs] |= krh@248: TRANS_PACKAGE_UPDATE; krh@248: } krh@248: } krh@248: krh@248: prop_iter_init(&spi, &trans->system); krh@248: prop_iter_init(&upi, &trans->upstream); krh@248: krh@248: while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) { krh@248: sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, krh@248: &upi.pool[upi.p->name]); krh@248: krh@248: if (sp) krh@248: flag_matching_providers(trans, &spi, up, &upi, krh@248: TRANS_PACKAGE_UPDATE); krh@248: } krh@248: } krh@248: krh@248: static void krh@248: pull_in_requirements(struct razor_transaction *trans, krh@248: struct prop_iter *rpi, struct prop_iter *ppi) krh@248: { krh@248: struct razor_property *rp, *pp; krh@248: struct razor_package *pkg, *upkgs; krh@248: krh@248: upkgs = trans->upstream.set->packages.data; krh@248: while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { krh@248: if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED) krh@248: continue; krh@248: krh@248: pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES, krh@248: &rpi->pool[rp->name]); krh@248: if (pp == NULL) krh@248: continue; krh@248: pkg = pick_matching_provider(trans->upstream.set, krh@248: ppi, rp->flags, krh@248: &rpi->pool[rp->version]); krh@248: if (pkg == NULL) krh@248: continue; krh@248: krh@248: rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED; krh@248: ali@403: #if 0 krh@257: fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s " krh@248: "to satisfy %s %s %s\n", krh@248: ppi->pool + pkg->name, krh@257: ppi->pool + pkg->version, krh@257: ppi->pool + pkg->arch, krh@248: ppi->pool + pp->name, krh@248: razor_property_relation_to_string(pp), krh@248: ppi->pool + pp->version, krh@248: &rpi->pool[rp->name], krh@248: razor_property_relation_to_string(rp), krh@248: &rpi->pool[rp->version]); ali@403: #endif krh@248: krh@248: trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE; krh@248: } krh@248: } krh@248: krh@248: static void krh@248: pull_in_all_requirements(struct razor_transaction *trans) krh@248: { krh@248: struct prop_iter rpi, ppi; krh@248: krh@248: prop_iter_init(&rpi, &trans->system); krh@248: prop_iter_init(&ppi, &trans->upstream); krh@248: pull_in_requirements(trans, &rpi, &ppi); krh@248: krh@248: prop_iter_init(&rpi, &trans->upstream); krh@248: prop_iter_init(&ppi, &trans->upstream); krh@248: pull_in_requirements(trans, &rpi, &ppi); krh@248: } krh@248: krh@248: static void krh@248: flush_scheduled_system_updates(struct razor_transaction *trans) krh@248: { krh@248: struct razor_package_iterator *pi; krh@248: struct razor_package *p, *pkg, *spkgs; krh@248: struct prop_iter ppi; richard@302: const char *name, *version; krh@248: krh@248: spkgs = trans->system.set->packages.data; krh@248: pi = razor_package_iterator_create(trans->system.set); krh@248: prop_iter_init(&ppi, &trans->upstream); krh@248: richard@302: while (razor_package_iterator_next(pi, &p, richard@302: RAZOR_DETAIL_NAME, &name, richard@307: RAZOR_DETAIL_VERSION, &version, richard@307: RAZOR_DETAIL_LAST)) { krh@248: if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE)) krh@248: continue; ali@432: trans->system.packages[p - spkgs] &= ~TRANS_PACKAGE_UPDATE; krh@248: krh@248: if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name)) krh@248: continue; krh@248: ali@386: if (any_provider_satisfies_requirement(&ppi, ali@386: RAZOR_PROPERTY_GREATER, ali@386: version)) { ali@386: razor_transaction_remove_package(trans, p); ali@386: continue; ali@386: } ali@386: krh@248: pkg = pick_matching_provider(trans->upstream.set, &ppi, krh@248: RAZOR_PROPERTY_GREATER, version); krh@248: if (pkg == NULL) krh@248: continue; krh@248: krh@248: razor_transaction_remove_package(trans, p); krh@248: razor_transaction_install_package(trans, pkg); krh@248: } krh@248: krh@248: razor_package_iterator_destroy(pi); krh@248: } krh@248: krh@248: static void krh@248: flush_scheduled_upstream_updates(struct razor_transaction *trans) krh@248: { krh@248: struct razor_package_iterator *pi; krh@248: struct razor_package *p, *upkgs; krh@248: struct prop_iter spi; richard@302: const char *name, *version; krh@248: krh@248: upkgs = trans->upstream.set->packages.data; krh@248: pi = razor_package_iterator_create(trans->upstream.set); krh@248: prop_iter_init(&spi, &trans->system); krh@248: richard@302: while (razor_package_iterator_next(pi, &p, richard@302: RAZOR_DETAIL_NAME, &name, richard@307: RAZOR_DETAIL_VERSION, &version, richard@307: RAZOR_DETAIL_LAST)) { krh@248: if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE)) krh@248: continue; ali@432: trans->upstream.packages[p - upkgs] &= ~TRANS_PACKAGE_UPDATE; krh@248: krh@248: if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name)) krh@248: remove_matching_providers(trans, krh@248: &spi, krh@248: RAZOR_PROPERTY_LESS, krh@248: version); krh@248: razor_transaction_install_package(trans, p); ali@403: #if 0 krh@248: fprintf(stderr, "installing %s-%s\n", name, version); ali@403: #endif krh@248: } ali@458: ali@458: razor_package_iterator_destroy(pi); krh@248: } krh@248: krh@269: RAZOR_EXPORT int krh@248: razor_transaction_resolve(struct razor_transaction *trans) krh@248: { krh@248: int last = 0; krh@248: krh@248: flush_scheduled_system_updates(trans); krh@248: flush_scheduled_upstream_updates(trans); krh@248: krh@248: while (last < trans->changes) { krh@248: last = trans->changes; krh@248: remove_obsoleted_packages(trans); krh@248: mark_all_satisfied_requires(trans); krh@248: update_unsatisfied_packages(trans); krh@248: update_conflicted_packages(trans); krh@248: pull_in_all_requirements(trans); krh@248: flush_scheduled_system_updates(trans); krh@248: flush_scheduled_upstream_updates(trans); krh@248: } krh@248: krh@248: return trans->changes; krh@248: } krh@248: krh@248: static void ali@446: describe_unsatisfied(struct razor_set *set, struct razor_property *rp, ali@446: razor_unsatisfied_callback_t callback, void *data) krh@248: { krh@248: struct razor_package_iterator pi; krh@248: struct razor_package *pkg; krh@248: const char *name, *version, *arch, *pool; ali@446: const char *requirement; ali@446: char *s = NULL; krh@248: krh@248: pool = set->string_pool.data; ali@446: if (pool[rp->version] == '\0') ali@446: requirement = &pool[rp->name]; ali@446: else { ali@446: s = razor_concat(&pool[rp->name], " ", ali@446: razor_property_relation_to_string(rp), " ", ali@446: &pool[rp->version], NULL); ali@446: requirement = s; krh@248: } ali@446: ali@446: razor_package_iterator_init_for_property(&pi, set, rp); ali@446: while (razor_package_iterator_next(&pi, &pkg, ali@446: RAZOR_DETAIL_NAME, &name, ali@446: RAZOR_DETAIL_VERSION, &version, ali@446: RAZOR_DETAIL_ARCH, &arch, ali@446: RAZOR_DETAIL_LAST)) ali@446: callback(requirement, pkg, name, version, arch, data); ali@446: ali@446: if (s) ali@446: free(s); krh@248: } krh@248: krh@269: RAZOR_EXPORT int ali@446: razor_transaction_unsatisfied(struct razor_transaction *trans, ali@446: razor_unsatisfied_callback_t callback, void *data) krh@248: { krh@248: struct prop_iter rpi; krh@248: struct razor_property *rp; krh@248: int unsatisfied; krh@248: krh@248: flush_scheduled_system_updates(trans); krh@248: flush_scheduled_upstream_updates(trans); krh@248: mark_all_satisfied_requires(trans); krh@248: krh@248: unsatisfied = 0; krh@248: prop_iter_init(&rpi, &trans->system); krh@248: while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { krh@248: if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { ali@446: if (callback) ali@446: describe_unsatisfied(trans->system.set, rp, ali@446: callback, data); krh@248: unsatisfied++; krh@248: } krh@248: } krh@248: krh@248: prop_iter_init(&rpi, &trans->upstream); krh@248: while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) { krh@248: if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) { ali@446: if (callback) ali@446: describe_unsatisfied(trans->upstream.set, rp, ali@446: callback, data); krh@248: unsatisfied++; krh@248: } krh@248: } krh@248: krh@248: return unsatisfied; krh@248: } krh@248: ali@446: static void ali@446: describe_unsatisfied_callback(const char *requirement, ali@446: struct razor_package *package, const char *name, ali@446: const char *version, const char *arch, void *data) ali@446: { ali@446: FILE *fp = data; ali@446: ali@446: fprintf(fp, "%s is needed by %s-%s.%s\n", requirement, ali@446: name, version, arch); ali@446: } ali@446: ali@446: RAZOR_EXPORT int ali@446: razor_transaction_describe(struct razor_transaction *trans) ali@446: { ali@446: return razor_transaction_unsatisfied(trans, ali@446: describe_unsatisfied_callback, ali@446: stderr); ali@446: } ali@446: krh@269: RAZOR_EXPORT int krh@248: razor_transaction_unsatisfied_property(struct razor_transaction *trans, krh@248: const char *name, krh@248: uint32_t flags, krh@248: const char *version) krh@248: { krh@248: struct prop_iter pi; krh@248: struct razor_property *p; krh@248: krh@248: prop_iter_init(&pi, &trans->system); jbowes@284: while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) { krh@248: if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && krh@248: p->flags == flags && krh@248: strcmp(&pi.pool[p->name], name) == 0 && krh@248: strcmp(&pi.pool[p->version], version) == 0) krh@248: krh@248: return 1; krh@248: } krh@248: krh@248: prop_iter_init(&pi, &trans->upstream); jbowes@284: while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) { krh@248: if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) && krh@248: p->flags == flags && krh@248: strcmp(&pi.pool[p->name], name) == 0 && krh@248: strcmp(&pi.pool[p->version], version) == 0) krh@248: krh@248: return 1; krh@248: } krh@248: krh@248: return 0; krh@248: } krh@248: krh@269: RAZOR_EXPORT struct razor_set * ali@369: razor_transaction_commit(struct razor_transaction *trans) krh@248: { krh@248: struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs; krh@248: char *upool, *spool; krh@248: int cmp; krh@248: krh@248: s = trans->system.set->packages.data; krh@248: spkgs = trans->system.set->packages.data; krh@248: send = trans->system.set->packages.data + krh@248: trans->system.set->packages.size; krh@248: spool = trans->system.set->string_pool.data; krh@248: krh@248: u = trans->upstream.set->packages.data; krh@248: upkgs = trans->upstream.set->packages.data; krh@248: uend = trans->upstream.set->packages.data + krh@248: trans->upstream.set->packages.size; krh@248: upool = trans->upstream.set->string_pool.data; krh@248: ali@369: trans->merger = razor_merger_create(trans->system.set, ali@369: trans->upstream.set); krh@248: while (s < send || u < uend) { krh@248: if (s < send && u < uend) krh@248: cmp = strcmp(&spool[s->name], &upool[u->name]); krh@248: else if (s < send) krh@248: cmp = -1; krh@248: else krh@248: cmp = 1; krh@248: krh@248: if (cmp < 0) { krh@248: if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) ali@369: razor_merger_add_package(trans->merger, s); krh@248: s++; krh@248: } else if (cmp == 0) { krh@248: if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT) ali@369: razor_merger_add_package(trans->merger, s); krh@248: if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) ali@369: razor_merger_add_package(trans->merger, u); krh@248: krh@248: s++; krh@248: u++; krh@248: } else { krh@248: if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT) ali@369: razor_merger_add_package(trans->merger, u); krh@248: u++; krh@248: } krh@248: } krh@248: ali@369: return razor_merger_commit(trans->merger); ali@369: } krh@248: ali@369: RAZOR_EXPORT void ali@369: razor_transaction_fixup_package(struct razor_transaction *trans, ali@369: struct razor_package *package, ali@369: struct razor_rpm *rpm) ali@369: { ali@369: const char *preunprog, *preun, *postunprog, *postun; ali@369: ali@369: razor_rpm_get_details(rpm, ali@369: RAZOR_DETAIL_PREUNPROG, &preunprog, ali@369: RAZOR_DETAIL_PREUN, &preun, ali@369: RAZOR_DETAIL_POSTUNPROG, &postunprog, ali@369: RAZOR_DETAIL_POSTUN, &postun, ali@369: RAZOR_DETAIL_LAST); ali@369: ali@369: razor_merger_package_add_script(trans->merger, package, ali@369: RAZOR_PROPERTY_PREUN, ali@369: preunprog, preun); ali@369: razor_merger_package_add_script(trans->merger, package, ali@369: RAZOR_PROPERTY_POSTUN, ali@369: postunprog, postun); krh@248: } krh@248: krh@269: RAZOR_EXPORT void krh@248: razor_transaction_destroy(struct razor_transaction *trans) krh@248: { richard@301: assert (trans != NULL); richard@301: ali@369: if (trans->merger) ali@369: razor_merger_destroy(trans->merger); krh@248: transaction_set_release(&trans->system); krh@248: transaction_set_release(&trans->upstream); krh@248: free(trans); krh@248: }