From ea1f09e2112cf5c98d45c973af0bcc34fb3f43f1 Mon Sep 17 00:00:00 2001 From: pixdamix@gmail.com Date: Thu, 22 Nov 2012 04:17:43 -0500 Subject: Fix dependency issues for preinst scripts There is a problem with dependency order when installing packages. The key problem revolves around the satisfy_dependencies_for() function which is called from opkg_install_pkg just before the installation (and preinst) happens. The satisfy_dependencies_for() function calls pkg_hash_fetch_unsatisfied_dependencies() which will only return packages which were previously not marked as *going* to be installed at some point. For the purposes of opkg_install_pkg() we really need to know which dependencies haven't been installed yet. This patch adds pkg_hash_fetch_satisfied_dependencies() which returns a list of package dependencies. We can then directly check the status of these and ensure any hard dependencies (not suggestions or recommendations) are installed before returning. Consider the situation (where -> means 'depends on'): X -> A,E A -> B,E E -> B B -> C Currently X would install A and E. When installing A the packages B, E and C would be marked as "to install". When the package B is considered the second time (as a dependency of E rather than A), it would install straight away even though C was not currently installed, just marked as needing to be installed. The patch changes the behaviour so B can't install until C really is installed. This change is required to run the postinst scripts in the correct order. Signed-off-by: Martin Jansa git-svn-id: http://opkg.googlecode.com/svn/trunk@638 e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 --- diff --git a/libopkg/opkg_install.c b/libopkg/opkg_install.c index 3925f58..6ed67d2 100644 --- a/libopkg/opkg_install.c +++ b/libopkg/opkg_install.c @@ -77,6 +77,27 @@ satisfy_dependencies_for(pkg_t *pkg) if (ndepends <= 0) { pkg_vec_free(depends); + depends = pkg_hash_fetch_satisfied_dependencies(pkg); + + for (i = 0; i < depends->len; i++) { + dep = depends->pkgs[i]; + /* The package was uninstalled when we started, but another + dep earlier in this loop may have depended on it and pulled + it in, so check first. */ + if ((dep->state_status != SS_INSTALLED) && (dep->state_status != SS_UNPACKED)) { + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(dep, 0); + /* mark this package as having been automatically installed to + * satisfy a dependency */ + dep->auto_installed = 1; + if (err) { + pkg_vec_free(depends); + return err; + } + } + } + + pkg_vec_free(depends); return 0; } diff --git a/libopkg/pkg_depends.c b/libopkg/pkg_depends.c index 1e14d1f..208b934 100644 --- a/libopkg/pkg_depends.c +++ b/libopkg/pkg_depends.c @@ -259,6 +259,88 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *unsatisfied, return unsatisfied->len; } + +pkg_vec_t * +pkg_hash_fetch_satisfied_dependencies(pkg_t * pkg) +{ + pkg_vec_t *satisfiers; + int i, j, k; + int count; + abstract_pkg_t * ab_pkg; + + satisfiers = pkg_vec_alloc(); + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if (!(ab_pkg = pkg->parent)) { + opkg_msg(ERROR, "Internal error, with pkg %s.\n", pkg->name); + return satisfiers; + } + + count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count; + if (!count) + return satisfiers; + + /* foreach dependency */ + for (i = 0; i < count; i++) { + compound_depend_t * compound_depend = &pkg->depends[i]; + depend_t ** possible_satisfiers = compound_depend->possibilities;; + + if (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST) + continue; + + if (compound_depend->type == GREEDY_DEPEND) { + /* foreach possible satisfier */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg; + abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by; + int nposs = ab_provider_vec->len; + abstract_pkg_t **ab_providers = ab_provider_vec->pkgs; + int l; + for (l = 0; l < nposs; l++) { + pkg_vec_t *test_vec = ab_providers[l]->pkgs; + /* if no depends on this one, try the first package that Provides this one */ + if (!test_vec){ /* no pkg_vec hooked up to the abstract_pkg! (need another feed?) */ + continue; + } + + /* cruise this possiblity's pkg_vec looking for an installed version */ + for (k = 0; k < test_vec->len; k++) { + pkg_t *pkg_scout = test_vec->pkgs[k]; + /* not installed, and not already known about? */ + if (pkg_scout->state_want == SW_INSTALL && pkg_scout != pkg) + pkg_vec_insert(satisfiers, pkg_scout); + } + } + } + + continue; + } + + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_installed_and_constraint_satisfied, + dependence_to_satisfy, 0); + /* Being that I can't test constraing in pkg_hash, I will test it here */ + if (satisfying_pkg != NULL && satisfying_pkg != pkg) { + if (pkg_constraint_satisfied(satisfying_pkg, dependence_to_satisfy) && (satisfying_pkg->state_want == SW_INSTALL || satisfying_pkg->state_want == SW_UNKNOWN)) + pkg_vec_insert(satisfiers, satisfying_pkg); + } + + } + } + return satisfiers; +} + + /*checking for conflicts !in replaces If a packages conflicts with another but is also replacing it, I should not consider it a really conflicts diff --git a/libopkg/pkg_depends.h b/libopkg/pkg_depends.h index 5d1f074..b8072e2 100644 --- a/libopkg/pkg_depends.h +++ b/libopkg/pkg_depends.h @@ -82,6 +82,7 @@ char *pkg_depend_str(pkg_t *pkg, int index); void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg); int version_constraints_satisfied(depend_t * depends, pkg_t * pkg); int pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *depends, char *** unresolved); +pkg_vec_t * pkg_hash_fetch_satisfied_dependencies(pkg_t * pkg); pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg); int pkg_dependence_satisfiable(depend_t *depend); int pkg_dependence_satisfied(depend_t *depend); -- cgit v0.9.1