diff mbox series

[OpenWrt-Devel] opkg: check for reverse conflicts on install

Message ID 20200303132844.103585-1-peter.stadler@student.uibk.ac.at
State New
Headers show
Series [OpenWrt-Devel] opkg: check for reverse conflicts on install | expand

Commit Message

Peter Stadler March 3, 2020, 1:28 p.m. UTC
Do not install a package if another package that is already installed
lists the new package (or one of its providees) as conflicting.
Without checking for reverse conflicts, the conflicting packages need
cyclic conflicts, which are not supported by `make menuconfig`.

Signed-off-by: Peter Stadler <peter.stadler@student.uibk.ac.at>
---
 libopkg/pkg_depends.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

Comments

Peter Stadler March 5, 2020, 12:05 p.m. UTC | #1
Additionally it would be good to ignore conflicting packages, when 
selecting a provider in `pkg_hash_fetch_best_installation_candidate`.

Please look at the extended patch:

Signed-off-by: Peter Stadler<peter.stadler@student.uibk.ac.at>
---
  libopkg/pkg.h         |  3 ++-
  libopkg/pkg_depends.c | 25 +++++++++++++++++--------
  libopkg/pkg_hash.c    |  5 +++++
  3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/libopkg/pkg.h b/libopkg/pkg.h
index 600fc9e..7d01549 100644
--- a/libopkg/pkg.h
+++ b/libopkg/pkg.h
@@ -59,6 +59,7 @@ enum pkg_state_flag {
  	SF_FILELIST_CHANGED = 128,	/* needs filelist written */
  	SF_USER = 256,
  	SF_NEED_DETAIL = 512,
+	SF_CONFLICT = 1024,
  	SF_LAST_STATE_FLAG
  };
  typedef enum pkg_state_flag pkg_state_flag_t;
@@ -162,7 +163,7 @@ struct pkg {
  	pkg_src_t *src;
  	pkg_dest_t *dest;
  	pkg_state_want_t state_want:3;
-	pkg_state_flag_t state_flag:11;
+	pkg_state_flag_t state_flag:12;
  	pkg_state_status_t state_status:4;
  
  	abstract_pkg_t *parent;
diff --git a/libopkg/pkg_depends.c b/libopkg/pkg_depends.c
index 3abdcd3..7ad0840 100644
--- a/libopkg/pkg_depends.c
+++ b/libopkg/pkg_depends.c
@@ -292,6 +292,8 @@ static int is_pkg_a_replaces(pkg_t * pkg_scout, pkg_t * pkg)
  
  pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
  {
+	pkg_vec_t * installed_pkgs;
+	pkg_t *installed_pkg;
  	pkg_vec_t *installed_conflicts, *test_vec;
  	compound_depend_t *conflicts, *conflict;
  	depend_t **possible_satisfiers;
@@ -312,17 +314,14 @@ pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
  	}
  
  	conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS);
-	if (!conflicts) {
-		return (pkg_vec_t *) NULL;
-	}
  	installed_conflicts = pkg_vec_alloc();
  
  	/* foreach conflict */
-	for (conflict = conflicts; conflict->type; conflict++ ) {
-		possible_satisfiers = conflicts->possibilities;
+	for (conflict = conflicts; conflict && conflict->type; conflict++ ) {
+		possible_satisfiers = conflict->possibilities;
  
  		/* foreach possible satisfier */
-		for (j = 0; j < conflicts->possibility_count; j++) {
+		for (j = 0; j < conflict->possibility_count; j++) {
  			possible_satisfier = possible_satisfiers[j];
  			if (!possible_satisfier)
  				opkg_msg(ERROR,
@@ -355,9 +354,19 @@ pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
  				}
  			}
  		}
-		conflicts++;
  	}
  
+	/* reverse conflicts */
+	installed_pkgs = pkg_vec_alloc();
+	pkg_hash_fetch_all_installed(installed_pkgs);
+	for (j = 0; j < installed_pkgs->len; j++) {
+		installed_pkg = installed_pkgs->pkgs[j];
+		if (pkg_conflicts(installed_pkg, pkg)) {
+			pkg_vec_insert(installed_conflicts, installed_pkg);
+		}
+	}
+	pkg_vec_free(installed_pkgs);
+
  	if (installed_conflicts->len)
  		return installed_conflicts;
  	pkg_vec_free(installed_conflicts);
@@ -558,7 +567,7 @@ static void flag_related_packages(pkg_t *pkg, int state_flags)
  			if ((deps[i].possibilities[j]->pkg->state_flag & state_flags) != state_flags) {
  				opkg_msg(DEBUG, "propagating pkg flag to conflicting abpkg %s\n",
  				         deps[i].possibilities[j]->pkg->name);
-				deps[i].possibilities[j]->pkg->state_flag |= state_flags;
+				deps[i].possibilities[j]->pkg->state_flag |= state_flags | SF_CONFLICT;
  			}
  		}
  }
diff --git a/libopkg/pkg_hash.c b/libopkg/pkg_hash.c
index 611f3b9..31bad9e 100644
--- a/libopkg/pkg_hash.c
+++ b/libopkg/pkg_hash.c
@@ -312,6 +312,11 @@ pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t * apkg,
  	/* accumulate all the providers */
  	for (i = 0; i < nprovides; i++) {
  		abstract_pkg_t *provider_apkg = provided_apkgs[i];
+		if (provider_apkg->state_flag & SF_CONFLICT) {
+			opkg_msg(DEBUG, "Ignore conflicting %s as provider.\n",
+				provider_apkg->name);
+			continue;
+		}
  		opkg_msg(DEBUG, "Adding %s to providers.\n",
  			 provider_apkg->name);
  		abstract_pkg_vec_insert(providers, provider_apkg);
-- 2.24.1
Peter Stadler March 5, 2020, 12:45 p.m. UTC | #2
The latter is not working for reverse conflicts, too.
So, add a preference for depended packages.
Maybe this alone is enough?

The following patch includes all three:
* check for reverse conflicts on install
* ignore conflicting packages for selection of best candidate
* prefer depended packages on selection of best candidate

Signed-off-by: Peter Stadler<peter.stadler@student.uibk.ac.at>
---
  libopkg/pkg.h         |  4 +++-
  libopkg/pkg_depends.c | 27 ++++++++++++++++++---------
  libopkg/pkg_hash.c    |  8 ++++++++
  3 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/libopkg/pkg.h b/libopkg/pkg.h
index 600fc9e..5abc736 100644
--- a/libopkg/pkg.h
+++ b/libopkg/pkg.h
@@ -59,6 +59,8 @@ enum pkg_state_flag {
  	SF_FILELIST_CHANGED = 128,	/* needs filelist written */
  	SF_USER = 256,
  	SF_NEED_DETAIL = 512,
+	SF_CONFLICT = 1024,
+	SF_DEPENDED = 2048,
  	SF_LAST_STATE_FLAG
  };
  typedef enum pkg_state_flag pkg_state_flag_t;
@@ -162,7 +164,7 @@ struct pkg {
  	pkg_src_t *src;
  	pkg_dest_t *dest;
  	pkg_state_want_t state_want:3;
-	pkg_state_flag_t state_flag:11;
+	pkg_state_flag_t state_flag:13;
  	pkg_state_status_t state_status:4;
  
  	abstract_pkg_t *parent;
diff --git a/libopkg/pkg_depends.c b/libopkg/pkg_depends.c
index 3abdcd3..97e0f97 100644
--- a/libopkg/pkg_depends.c
+++ b/libopkg/pkg_depends.c
@@ -292,6 +292,8 @@ static int is_pkg_a_replaces(pkg_t * pkg_scout, pkg_t * pkg)
  
  pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
  {
+	pkg_vec_t * installed_pkgs;
+	pkg_t *installed_pkg;
  	pkg_vec_t *installed_conflicts, *test_vec;
  	compound_depend_t *conflicts, *conflict;
  	depend_t **possible_satisfiers;
@@ -312,17 +314,14 @@ pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
  	}
  
  	conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS);
-	if (!conflicts) {
-		return (pkg_vec_t *) NULL;
-	}
  	installed_conflicts = pkg_vec_alloc();
  
  	/* foreach conflict */
-	for (conflict = conflicts; conflict->type; conflict++ ) {
-		possible_satisfiers = conflicts->possibilities;
+	for (conflict = conflicts; conflict && conflict->type; conflict++ ) {
+		possible_satisfiers = conflict->possibilities;
  
  		/* foreach possible satisfier */
-		for (j = 0; j < conflicts->possibility_count; j++) {
+		for (j = 0; j < conflict->possibility_count; j++) {
  			possible_satisfier = possible_satisfiers[j];
  			if (!possible_satisfier)
  				opkg_msg(ERROR,
@@ -355,9 +354,19 @@ pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
  				}
  			}
  		}
-		conflicts++;
  	}
  
+	/* reverse conflicts */
+	installed_pkgs = pkg_vec_alloc();
+	pkg_hash_fetch_all_installed(installed_pkgs);
+	for (j = 0; j < installed_pkgs->len; j++) {
+		installed_pkg = installed_pkgs->pkgs[j];
+		if (pkg_conflicts(installed_pkg, pkg)) {
+			pkg_vec_insert(installed_conflicts, installed_pkg);
+		}
+	}
+	pkg_vec_free(installed_pkgs);
+
  	if (installed_conflicts->len)
  		return installed_conflicts;
  	pkg_vec_free(installed_conflicts);
@@ -549,7 +558,7 @@ static void flag_related_packages(pkg_t *pkg, int state_flags)
  			if ((deps[i].possibilities[j]->pkg->state_flag & state_flags) != state_flags) {
  				opkg_msg(DEBUG, "propagating pkg flag to dependent abpkg %s\n",
  				         deps[i].possibilities[j]->pkg->name);
-				deps[i].possibilities[j]->pkg->state_flag |= state_flags;
+				deps[i].possibilities[j]->pkg->state_flag |= state_flags | SF_DEPENDED;
  			}
  		}
  
@@ -558,7 +567,7 @@ static void flag_related_packages(pkg_t *pkg, int state_flags)
  			if ((deps[i].possibilities[j]->pkg->state_flag & state_flags) != state_flags) {
  				opkg_msg(DEBUG, "propagating pkg flag to conflicting abpkg %s\n",
  				         deps[i].possibilities[j]->pkg->name);
-				deps[i].possibilities[j]->pkg->state_flag |= state_flags;
+				deps[i].possibilities[j]->pkg->state_flag |= state_flags | SF_CONFLICT;
  			}
  		}
  }
diff --git a/libopkg/pkg_hash.c b/libopkg/pkg_hash.c
index 611f3b9..c66d37d 100644
--- a/libopkg/pkg_hash.c
+++ b/libopkg/pkg_hash.c
@@ -312,6 +312,11 @@ pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t * apkg,
  	/* accumulate all the providers */
  	for (i = 0; i < nprovides; i++) {
  		abstract_pkg_t *provider_apkg = provided_apkgs[i];
+		if (provider_apkg->state_flag & SF_CONFLICT) {
+			opkg_msg(DEBUG, "Ignore conflicting %s as provider.\n",
+				provider_apkg->name);
+			continue;
+		}
  		opkg_msg(DEBUG, "Adding %s to providers.\n",
  			 provider_apkg->name);
  		abstract_pkg_vec_insert(providers, provider_apkg);
@@ -410,6 +415,9 @@ pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t * apkg,
  			/* It has been provided by hand, so it is what user want */
  			if (matching->provided_by_hand == 1)
  				break;
+			/* It is marked as depended, so it will be installed anyway */
+			if (matching->parent->state_flag & SF_DEPENDED)
+				break;
  		}
  	}
  
-- 2.24.1
diff mbox series

Patch

diff --git a/libopkg/pkg_depends.c b/libopkg/pkg_depends.c
index 3abdcd3..9f62faf 100644
--- a/libopkg/pkg_depends.c
+++ b/libopkg/pkg_depends.c
@@ -292,6 +292,8 @@  static int is_pkg_a_replaces(pkg_t * pkg_scout, pkg_t * pkg)
 
 pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
 {
+	pkg_vec_t * installed_pkgs;
+	pkg_t *installed_pkg;
 	pkg_vec_t *installed_conflicts, *test_vec;
 	compound_depend_t *conflicts, *conflict;
 	depend_t **possible_satisfiers;
@@ -312,17 +314,14 @@  pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
 	}
 
 	conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS);
-	if (!conflicts) {
-		return (pkg_vec_t *) NULL;
-	}
 	installed_conflicts = pkg_vec_alloc();
 
 	/* foreach conflict */
-	for (conflict = conflicts; conflict->type; conflict++ ) {
-		possible_satisfiers = conflicts->possibilities;
+	for (conflict = conflicts; conflict && conflict->type; conflict++ ) {
+		possible_satisfiers = conflict->possibilities;
 
 		/* foreach possible satisfier */
-		for (j = 0; j < conflicts->possibility_count; j++) {
+		for (j = 0; j < conflict->possibility_count; j++) {
 			possible_satisfier = possible_satisfiers[j];
 			if (!possible_satisfier)
 				opkg_msg(ERROR,
@@ -355,9 +354,19 @@  pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
 				}
 			}
 		}
-		conflicts++;
 	}
 
+	/* reverse conflicts */
+	installed_pkgs = pkg_vec_alloc();
+	pkg_hash_fetch_all_installed(installed_pkgs);
+	for (j = 0; j < installed_pkgs->len; j++) {
+		installed_pkg = installed_pkgs->pkgs[j];
+		if (pkg_conflicts(installed_pkg, pkg)) {
+			pkg_vec_insert(installed_conflicts, installed_pkg);
+		}
+	}
+	pkg_vec_free(installed_pkgs);
+
 	if (installed_conflicts->len)
 		return installed_conflicts;
 	pkg_vec_free(installed_conflicts);