From: Michael Schroeder Date: Thu, 20 May 2021 09:38:22 +0000 (+0200) Subject: Add support for blacklisted packages X-Git-Tag: 0.6.37~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d958ca728aa46e968e85b5d5ec222fcf035ec471;p=thirdparty%2Flibsolv.git Add support for blacklisted packages 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). --- diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver index 4896e855..b3fe0f04 100644 --- a/ext/libsolvext.ver +++ b/ext/libsolvext.ver @@ -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; diff --git a/ext/repo_updateinfoxml.c b/ext/repo_updateinfoxml.c index dc54ffb2..ff08214d 100644 --- a/ext/repo_updateinfoxml.c +++ b/ext/repo_updateinfoxml.c @@ -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 diff --git a/ext/repo_updateinfoxml.h b/ext/repo_updateinfoxml.h index bd0a61b6..c3da0f67 100644 --- a/ext/repo_updateinfoxml.h +++ b/ext/repo_updateinfoxml.h @@ -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); + diff --git a/ext/testcase.c b/ext/testcase.c index 0bac26b6..72743504 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -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 } }; diff --git a/src/problems.c b/src/problems.c index 2b5cefda..aa363945 100644 --- a/src/problems.c +++ b/src/problems.c @@ -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) diff --git a/src/problems.h b/src/problems.h index 63319d6c..24f9119e 100644 --- a/src/problems.h +++ b/src/problems.h @@ -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); diff --git a/src/rules.c b/src/rules.c index 59011457..87540be5 100644 --- a/src/rules.c +++ b/src/rules.c @@ -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; diff --git a/src/rules.h b/src/rules.h index db52199c..4e3b9d35 100644 --- a/src/rules.h +++ b/src/rules.h @@ -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); diff --git a/src/solver.c b/src/solver.c index 102d8141..6a1c30ff 100644 --- a/src/solver.c +++ b/src/solver.c @@ -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; diff --git a/src/solver.h b/src/solver.h index ebb2232b..6e5c1d04 100644 --- a/src/solver.h +++ b/src/solver.h @@ -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 diff --git a/src/solverdebug.c b/src/solverdebug.c index bb74ef61..8a7fb9ea 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -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); } diff --git a/tools/repo2solv.c b/tools/repo2solv.c index ece4225c..bc92aeff 100644 --- a/tools/repo2solv.c +++ b/tools/repo2solv.c @@ -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))