]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Add support for blacklisted packages
authorMichael Schroeder <mls@suse.de>
Thu, 20 May 2021 09:38:22 +0000 (11:38 +0200)
committerMichael Schroeder <mls@suse.de>
Thu, 20 May 2021 09:38:22 +0000 (11:38 +0200)
This will be used in SUSE's ptf packages and also to retract
released updates. The idea is that it is not possible to pull in
a blacklisted package via a dependency, they can only be installed
by a job that directly addresses them (the SETEVR bit is set).

12 files changed:
ext/libsolvext.ver
ext/repo_updateinfoxml.c
ext/repo_updateinfoxml.h
ext/testcase.c
src/problems.c
src/problems.h
src/rules.c
src/rules.h
src/solver.c
src/solver.h
src/solverdebug.c
tools/repo2solv.c

index 4896e855ff854f946e8c1617a1c5f0dad96d5cbb..b3fe0f04c6b1c1891c2f4791db1544c1ebc9ed6c 100644 (file)
@@ -41,6 +41,7 @@ SOLV_1.0 {
                repo_add_zyppdb_products;
                repo_find_all_pubkeys;
                repo_find_pubkey;
+               repo_mark_retracted_packages;
                repo_verify_sigdata;
                rpm_byfp;
                rpm_byrpmdbid;
index dc54ffb258eb28b32aeb424a29a4d868c4fc50cb..ff08214d3a31c2df1e4656aeebbfa9628fb0d0f3 100644 (file)
@@ -461,3 +461,92 @@ repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
   return pd.ret;
 }
 
+#ifdef SUSE
+
+static int
+repo_mark_retracted_packages_cmp(const void *ap, const void *bp, void *dp)
+{
+  Id *a = (Id *)ap;
+  Id *b = (Id *)bp;
+  if (a[1] != b[1])
+    return a[1] - b[1];
+  if (a[2] != b[2])
+    return a[2] - b[2];
+  if (a[0] != b[0])
+    return a[0] - b[0];
+  return 0;
+}
+
+
+void
+repo_mark_retracted_packages(Repo *repo, Id retractedmarker)
+{
+  Pool *pool = repo->pool;
+  int i, p;
+  Solvable *s;
+  Id con, *conp;
+  Id retractedname, retractedevr;
+
+  Queue q;
+  queue_init(&q);
+  for (p = 1; p < pool->nsolvables; p++)
+    {
+      const char *status;
+      s = pool->solvables + p;
+      if (strncmp(pool_id2str(pool, s->name), "patch:", 6) != 0)
+       {
+         if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+           continue;
+         queue_push2(&q, p, s->name);
+         queue_push2(&q, s->evr, s->arch);
+         continue;
+       }
+      status = solvable_lookup_str(s, UPDATE_STATUS);
+      if (!status || strcmp(status, "retracted") != 0)
+       continue;
+      if (!s->conflicts)
+       continue;
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+       {
+         Reldep *rd;
+         Id name, evr, arch;
+         if (!ISRELDEP(con))
+           continue;
+         rd = GETRELDEP(pool, con);
+         if (rd->flags != REL_LT)
+           continue;
+         name = rd->name;
+         evr = rd->evr;
+         arch = 0;
+         if (ISRELDEP(name))
+           {
+             rd = GETRELDEP(pool, name);
+             name = rd->name;
+             if (rd->flags == REL_ARCH)
+               arch = rd->evr;
+           }
+         queue_push2(&q, 0, name);
+         queue_push2(&q, evr, arch);
+       }
+    }
+  if (q.count)
+    solv_sort(q.elements, q.count / 4, sizeof(Id) * 4, repo_mark_retracted_packages_cmp, repo->pool);
+  retractedname = retractedevr = 0;
+  for (i = 0; i < q.count; i += 4)
+    {
+      if (!q.elements[i])
+       {
+         retractedname = q.elements[i + 1];
+         retractedevr = q.elements[i + 2];
+       }
+      else if (q.elements[i + 1] == retractedname && q.elements[i + 2] == retractedevr)
+       {
+         s = pool->solvables + q.elements[i];
+         s->provides = repo_addid_dep(repo, s->provides, retractedmarker, 0);
+       }
+    }
+  queue_free(&q);
+}
+
+#endif
index bd0a61b6603a0ede08cdcd6aa53a887b93dfadbf..c3da0f67068be1d5f5ccf42b57cde4791ef08c6f 100644 (file)
@@ -6,3 +6,6 @@
  */
 
 extern int repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags);
+
+extern void repo_mark_retracted_packages(Repo *repo, Id retractedmarker);
+
index 0bac26b65423dcdc94a04224fa5535f24dccc5cb..72743504a3c03c0fec2a47b697f39e6e47eabfe1 100644 (file)
@@ -49,6 +49,7 @@ static struct job2str {
   { SOLVER_ALLOWUNINSTALL, "allowuninstall" },
   { SOLVER_FAVOR,          "favor" },
   { SOLVER_DISFAVOR,       "disfavor" },
+  { SOLVER_BLACKLIST,      "blacklist" },
   { 0, 0 }
 };
 
@@ -1801,6 +1802,7 @@ static struct rclass2str {
   { SOLVER_RULE_LEARNT, "learnt" },
   { SOLVER_RULE_BEST, "best" },
   { SOLVER_RULE_YUMOBS, "yumobs" },
+  { SOLVER_RULE_BLACK, "black" },
   { 0, 0 }
 };
 
index 2b5cefda3ca00956ec7057eeebd1f73b51632bd4..aa3639458e261a4bde101afb7ffc6e741c95ab6d 100644 (file)
@@ -719,6 +719,12 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
        }
       return;
     }
+  if (why >= solv->blackrules && why < solv->blackrules_end)
+    {
+      queue_push(solutionq, SOLVER_SOLUTION_BLACK);
+      assert(solv->rules[why].p < 0);
+      queue_push(solutionq, -solv->rules[why].p);
+    }
 }
 
 /*
@@ -981,6 +987,8 @@ solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
  *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
  *    SOLVER_SOLUTION_BEST          pkgid
  *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_BLACK         pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
  *    SOLVER_SOLUTION_JOB           jobidx
  *    -> remove job (jobidx - 1, jobidx) from job queue
  *    SOLVER_SOLUTION_POOLJOB       jobidx
@@ -1331,6 +1339,8 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ
       s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and ");
       s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
       return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
+    case SOLVER_RULE_BLACK:
+      return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " can only be installed by a direct request");
     default:
       return "bad problem rule type";
     }
@@ -1385,6 +1395,11 @@ solver_solutionelement2str(Solver *solv, Id p, Id rp)
       else
         return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
     }
+  else if (p == SOLVER_SOLUTION_BLACK)
+    {
+      Solvable *s = pool->solvables + rp;
+      return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), 0);
+    }
   else if (p > 0 && rp == 0)
     return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
   else if (p > 0 && rp > 0)
index 63319d6cbf09c686e2e7f03e0e9adaea184620bf..24f9119e3235eb24c4350328e429901b0cb43b4e 100644 (file)
@@ -22,11 +22,12 @@ extern "C" {
 
 struct _Solver;
 
-#define SOLVER_SOLUTION_JOB             (0)
-#define SOLVER_SOLUTION_DISTUPGRADE     (-1)
-#define SOLVER_SOLUTION_INFARCH         (-2)
-#define SOLVER_SOLUTION_BEST            (-3)
-#define SOLVER_SOLUTION_POOLJOB         (-4)
+#define SOLVER_SOLUTION_JOB            (0)
+#define SOLVER_SOLUTION_DISTUPGRADE    (-1)
+#define SOLVER_SOLUTION_INFARCH                (-2)
+#define SOLVER_SOLUTION_BEST           (-3)
+#define SOLVER_SOLUTION_POOLJOB                (-4)
+#define SOLVER_SOLUTION_BLACK          (-5)
 
 void solver_recordproblem(struct _Solver *solv, Id rid);
 void solver_fixproblem(struct _Solver *solv, Id rid);
index 59011457b60fd5cf1f0ceb4dba09d481ba958b55..87540be53b361a56a1a8c1b2d965a7971984e225 100644 (file)
@@ -2087,6 +2087,97 @@ reenableduprule(Solver *solv, Id name)
     }
 }
 
+/***********************************************************************
+ ***
+ ***  Black rule part
+ ***/
+
+static inline void
+disableblackrule(Solver *solv, Id p)
+{
+  Rule *r;
+  int i;
+  for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
+    if (r->p == -p)
+      solver_disablerule(solv, r);
+}
+
+static inline void
+reenableblackrule(Solver *solv, Id p)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
+    if (r->p == -p)
+      {
+       solver_enablerule(solv, r);
+       IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+         {
+           POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+           solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+         }
+      }
+}
+
+void
+solver_addblackrules(Solver *solv)
+{
+  int i;
+  Id how, select, what, p, pp;
+  Queue *job = &solv->job;
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Map updatemap;
+
+  map_init(&updatemap, 0);
+  solv->blackrules = solv->nrules;
+  if (installed)
+    {
+      for (i = 0; i < job->count; i += 2)
+       {
+         how = job->elements[i];
+         select = job->elements[i] & SOLVER_SELECTMASK;
+         what = job->elements[i + 1];
+         switch (how & SOLVER_JOBMASK)
+           {
+           case SOLVER_BLACKLIST:
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->repo != installed)
+                   continue;
+                 if (!updatemap.size)
+                   map_grow(&updatemap, pool->ss.nstrings);
+                 if (s->name > 0 && s->name < pool->ss.nstrings)
+                   MAPSET(&updatemap, s->name);
+               }
+           }
+       }
+    }
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      select = job->elements[i] & SOLVER_SELECTMASK;
+      what = job->elements[i + 1];
+      switch (how & SOLVER_JOBMASK)
+       {
+       case SOLVER_BLACKLIST:
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             Solvable *s = pool->solvables + p;
+             if (s->repo == installed)
+               continue;
+             if (updatemap.size && s->name > 0 && s->name < pool->ss.nstrings && MAPTST(&updatemap, s->name))
+               continue;       /* installed package with same name is already blacklisted */
+             solver_addrule(solv, -p, 0, 0);
+           }
+         break;
+       }
+    }
+  map_free(&updatemap);
+  solv->blackrules_end = solv->nrules;
+}
 
 /***********************************************************************
  ***
@@ -2100,6 +2191,7 @@ reenableduprule(Solver *solv, Id name)
 #define DISABLE_UPDATE 1
 #define DISABLE_INFARCH        2
 #define DISABLE_DUP    3
+#define DISABLE_BLACK  4
 
 static void
 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
@@ -2189,6 +2281,16 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
                }
            }
        }
+      if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end)
+        {
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_BLACK, what);
+         else
+           {
+             FOR_JOB_SELECT(p, pp, select, what)
+               queue_push2(q, DISABLE_BLACK, p);
+           }
+        }
       if (!installed || installed->end == installed->start)
        return;
       /* now the hard part: disable some update rules */
@@ -2334,6 +2436,9 @@ solver_disablepolicyrules(Solver *solv)
        case DISABLE_DUP:
          disableduprule(solv, arg);
          break;
+       case DISABLE_BLACK:
+         disableblackrule(solv, arg);
+         break;
        default:
          break;
        }
@@ -2437,6 +2542,9 @@ solver_reenablepolicyrules(Solver *solv, int jobidx)
        case DISABLE_DUP:
          reenableduprule(solv, arg);
          break;
+       case DISABLE_BLACK:
+         reenableblackrule(solv, arg);
+         break;
        }
     }
   queue_free(&q);
@@ -2763,6 +2871,12 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *depp = solv->yumobsrules_info[rid - solv->yumobsrules];
       return SOLVER_RULE_YUMOBS;
     }
+  if (rid >= solv->blackrules && rid < solv->blackrules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      return SOLVER_RULE_BLACK;
+    }
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     {
       return SOLVER_RULE_CHOICE;
@@ -2795,8 +2909,12 @@ solver_ruleclass(Solver *solv, Id rid)
     return SOLVER_RULE_BEST;
   if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
     return SOLVER_RULE_YUMOBS;
+  if (rid >= solv->blackrules && rid < solv->blackrules_end)
+    return SOLVER_RULE_BLACK;
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     return SOLVER_RULE_CHOICE;
+  if (rid >= solv->blackrules && rid < solv->blackrules_end)
+    return SOLVER_RULE_BLACK;
   if (rid >= solv->learntrules && rid < solv->nrules)
     return SOLVER_RULE_LEARNT;
   return SOLVER_RULE_UNKNOWN;
index db52199c67a0dcad716620e48ccfde55bfe7ed55..4e3b9d359356f182c43222263ec4094c3bb7c589 100644 (file)
@@ -71,7 +71,8 @@ typedef enum {
   SOLVER_RULE_CHOICE = 0x700,
   SOLVER_RULE_LEARNT = 0x800,
   SOLVER_RULE_BEST = 0x900,
-  SOLVER_RULE_YUMOBS = 0xa00
+  SOLVER_RULE_YUMOBS = 0xa00,
+  SOLVER_RULE_BLACK = 0xb00,
 } SolverRuleinfo;
 
 #define SOLVER_RULE_TYPEMASK    0xff00
@@ -133,6 +134,9 @@ extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs);
 /* yumobs rules */
 extern void solver_addyumobsrules(struct _Solver *solv);
 
+/* black rules */
+extern void solver_addblackrules(struct _Solver *solv);
+
 /* policy rule disabling/reenabling */
 extern void solver_disablepolicyrules(struct _Solver *solv);
 extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx);
index 102d81411b6f12f1246d4d8bb467038dbd051fa4..6a1c30ff7de51fd07c8ac4d8c901c2b8ffe6932a 100644 (file)
@@ -3301,6 +3301,7 @@ solver_solve(Solver *solv, Queue *job)
   int now, solve_start;
   int needduprules = 0;
   int hasbestinstalljob = 0;
+  int hasblacklistjob = 0;
 
   solve_start = solv_timems(0);
 
@@ -3919,6 +3920,10 @@ solver_solve(Solver *solv, Queue *job)
              queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? j : -j);
            }
          break;
+       case SOLVER_BLACKLIST:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: blacklist %s\n", solver_select2str(pool, select, what));
+         hasblacklistjob = 1;
+         break;
        default:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
          break;
@@ -3972,6 +3977,11 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
 
+  if (hasblacklistjob)
+    solver_addblackrules(solv);
+  else
+    solv->blackrules = solv->blackrules_end = solv->nrules;
+
   if (1)
     solver_addchoicerules(solv);
   else
@@ -4783,6 +4793,9 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
     case SOLVER_DISFAVOR:
       strstart = "disfavor ";
       break;
+    case SOLVER_BLACKLIST:
+      strstart = "blacklist ";
+      break;
     default:
       strstart = "unknown job ";
       break;
index ebb2232bb0a3e11aa415194e4616d7962494687a..6e5c1d048a1c314e22a56de57ff48bdc1fc804c2 100644 (file)
@@ -76,6 +76,9 @@ struct _Solver {
   Id yumobsrules_end;
   Id *yumobsrules_info;                        /* the dependency for each rule */
 
+  Id blackrules;                       /* rules from blacklisted packages */
+  Id blackrules_end;
+
   Id choicerules;                      /* choice rules (always weak) */
   Id choicerules_end;
   Id *choicerules_ref;
@@ -240,6 +243,7 @@ typedef struct _Solver Solver;
 #define SOLVER_ALLOWUNINSTALL          0x0b00
 #define SOLVER_FAVOR                   0x0c00
 #define SOLVER_DISFAVOR                        0x0d00
+#define SOLVER_BLACKLIST               0x0e00
 
 #define SOLVER_JOBMASK                 0xff00
 
index bb74ef613fef65c9a4aedb5b412e9746dcf0df74..8a7fb9ea8de1b67b70426b5bc3f56871244d50d2 100644 (file)
@@ -128,6 +128,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
     POOL_DEBUG(type, "FEATURE ");
   else if (p >= solv->yumobsrules && p < solv->yumobsrules_end)
     POOL_DEBUG(type, "YUMOBS ");
+  else if (p >= solv->blackrules && p < solv->blackrules_end)
+    POOL_DEBUG(type, "BLACK ");
   solver_printrule(solv, type, r);
 }
 
index ece4225ced8c3c128622d109285006aae461f2b7..bc92aeff8213597333d17691de9df2339d180efb 100644 (file)
@@ -827,6 +827,7 @@ main(int argc, char **argv)
 #ifdef SUSE
   if (add_auto)
     repo_add_autopattern(repo, 0);
+  repo_mark_retracted_packages(repo, pool_str2id(pool, "retracted-patch-package()", 1));
 #endif
   tool_write(repo, 0, 0);
   if (fflush(stdout))