[Rpm-maint] [PATCH 08/18] Remove duplicates when preparing the policy set

Steve Lawrence slawrence at tresys.com
Wed Dec 23 20:57:28 UTC 2009


There are cases where duplicates are expected, and we must be able to
removed the older version of a duplicate. Unfortunately, policies are not
versioned, so we must use the install time of a policy to determine which
which is newer. Policies that have not yet been installed get a time of
UINT_MAX so they are seen as the newest when compared to already installed
policies. In the case of two policies having the same install time, we
don't know which one to choose, so we error out.

Policies are only considered duplicates if they have the same name and
their types overlay. For example, this would not be considered
duplicates because their types do not overlap and could be installed at
the same time (in different types) without a problem:

	%policy package1
	%module modules/foo-targeted.pp
		Name: foo
		Types: targeted

	%policy package2
	%module modules/foo-mls.pp
		Name: foo
		Types: mls

Whereas this would be considered a duplicate:

	%policy package1
	%module modules/foo.pp
		Name: foo
		Types: targeted mls

	%policy package2
	%module modules/foo-mls.pp
		Name: foo
		Types: mls

Note: If 'targeted mls' were changed to 'default', that would still be
considered a duplicate, because 'mls' is in the set of 'default'.
---
 lib/rpmpol.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/rpmpol.h |    8 ++++++++
 2 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/lib/rpmpol.c b/lib/rpmpol.c
index bd09689..893f487 100644
--- a/lib/rpmpol.c
+++ b/lib/rpmpol.c
@@ -29,6 +29,8 @@ struct rpmpol_s {
 	ARGV_t * obsoletes;    /*!< policy obsoletes */
 	rpmpolFlags * flags;   /*!< policy flags */
 	rpmpolAction * actions; /*!< install, upgrade, remove, ignore */
+	rpm_time_t time;       /*!< installation time of this policy, in seconds since the epoch */
+	rpmds requires;        /*!< PolicyRequires: dependencies */
 	int count;             /*!< number of policies */
 	int nrefs;             /*!< reference counting */
 	int index;             /*!< index for iterator */
@@ -205,6 +207,10 @@ rpmpol rpmpolNew(Header h)
 	for (i = 0; i < pol->count; i++) {
 		pol->actions[i] = RPMPOL_ACTION_IGNORE;
 	}
+	pol->time = (rpm_time_t)headerGetNumber(h, RPMTAG_INSTALLTIME);
+	if (pol->time == 0) { /* hasn't been installed yet */
+		pol->time = UINT_MAX; /* rpm_time_t is typedef to uint32_t */
+	}
 
 	pol = rpmpolLink(pol);
 
@@ -331,6 +337,11 @@ void rpmpolSetAction(rpmpol pol, rpmpolAction action)
 	}
 }
 
+rpm_time_t rpmpolGetTime(const rpmpol pol)
+{
+	return pol ? pol->time : 0;
+}
+
 int rpmpolHasType(const rpmpol pol, const char * type)
 {
 	ARGV_const_t types;
@@ -874,7 +885,8 @@ rpmRC rpmpolsPrepare(rpmpols ps, rpmdb db)
 	ARGV_t obs;
 	ARGV_t cur;
 	int changes = 0;
-	unsigned int i;
+	unsigned int i, j;
+	rpm_time_t timea, timeb;
 	rpmRC rc = RPMRC_FAIL;
 
 	if (!ps || !db) {
@@ -885,6 +897,45 @@ rpmRC rpmpolsPrepare(rpmpols ps, rpmdb db)
 		return RPMRC_NOTFOUND;
 	}
 
+	/* remove duplicates of to be installed policies, keeping those with the newest times.
+	 * if two policies have the same name, the same install time, and have overlapping types
+	 * then either policy could be the correct one. since we don't know which one to keep,
+	 * we just error out */
+	for (i = 0; i < ps->count - 1; i++) {
+		rpmpol pola = ps->pols[i];
+		for (j = i + 1; j < ps->count; j++) {
+			rpmpol polb = ps->pols[j];
+
+			rpmpolInitIterator(pola);
+			while (rpmpolNext(pola) >= 0) {
+				rpmpolInitIterator(polb);
+				while (rpmpolNext(polb) >= 0) {
+					if (!rstreq(rpmpolGetName(pola), rpmpolGetName(polb))) {
+						continue;
+					}
+
+					timea = rpmpolGetTime(pola);
+					timeb = rpmpolGetTime(polb);
+
+					if (timea == timeb) {
+						ARGV_const_t av;
+						for (av = rpmpolGetTypes(pola); av && *av; av++) {
+							if (rstreq(*av, RPMPOL_TYPE_DEFAULT) || rpmpolHasType(polb, *av)) {
+								rpmlog(RPMLOG_ERR, _("Duplicate policy modules with overlapping types found: %s\n"), rpmpolGetName(pola));
+								goto exit;
+							}
+						}
+					} else if (timea > timeb) {
+						rpmpolRemove(polb);
+					} else {
+						rpmpolRemove(pola);
+						break;
+					}
+				}
+			}
+		}
+	}
+
 	/* generate list of policies obsoleted by the to-be-installed policies */
 	for (i = 0; i < ps->count; i++) {
 		pol = ps->pols[i];
diff --git a/lib/rpmpol.h b/lib/rpmpol.h
index 6c5d5c5..144a99f 100644
--- a/lib/rpmpol.h
+++ b/lib/rpmpol.h
@@ -140,6 +140,14 @@ RPM_GNUC_INTERNAL
 void rpmpolSetAction(rpmpol pol, rpmpolAction action);
 
 /** \ingroup rpmpol
+ * Get the time the policy was installed
+ * @param pol	policy set
+ * @return		installation time of poilicy set
+ */
+RPM_GNUC_INTERNAL
+rpm_time_t rpmpolGetTime(const rpmpol pol);
+
+/** \ingroup rpmpol
  * Determine if a policy has a type
  * @param pol		policy set
  * @param type		policy type
-- 
1.6.0.6



More information about the Rpm-maint mailing list