2 * Copyright (c) 2016, SUSE LLC.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
8 /* weird SUSE stuff. better not use it for your projects. */
16 #include "solver_private.h"
19 #include "poolvendor.h"
23 repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
25 Pool *pool = repo->pool;
27 char buf[1024], *p, *dep;
32 for (i = provides; repo->idarraydata[i]; i++)
34 id = repo->idarraydata[i];
37 dep = (char *)pool_id2str(pool, id);
38 if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
43 if ((p = strchr(dep, ':')) != 0 && p != dep)
46 idp = pool_str2id(pool, dep, 1);
50 while ((p = strchr(dep, ';')) != 0)
58 idl = pool_str2id(pool, dep, 1);
59 idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
61 id = pool_rel2id(pool, id, idl, REL_OR, 1);
68 for (p = dep; *p && *p != ')'; p++)
71 idl = pool_str2id(pool, dep, 1);
72 idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
74 id = pool_rel2id(pool, id, idl, REL_OR, 1);
79 id = pool_rel2id(pool, idp, id, REL_AND, 1);
81 supplements = repo_addid_dep(repo, supplements, id, 0);
83 else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
88 idp = pool_str2id(pool, buf, 1);
89 /* strip trailing slashes */
91 while (l > 1 && p[l - 1] == '/')
93 id = pool_str2id(pool, p, 1);
94 id = pool_rel2id(pool, idp, id, REL_WITH, 1);
95 id = pool_rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
96 supplements = repo_addid_dep(repo, supplements, id, 0);
102 for (i = supplements; repo->idarraydata[i]; i++)
104 id = repo->idarraydata[i];
107 dep = (char *)pool_id2str(pool, id);
108 if (!strncmp(dep, "system:modalias(", 16))
110 if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
113 p = strchr(buf + 9, ':');
114 if (p && p != buf + 9 && strchr(p + 1, ':'))
117 idp = pool_str2id(pool, buf + 9, 1);
118 p[strlen(p) - 1] = 0;
119 id = pool_str2id(pool, p, 1);
120 id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
121 id = pool_rel2id(pool, idp, id, REL_AND, 1);
126 p[strlen(p) - 1] = 0;
127 id = pool_str2id(pool, p, 1);
128 id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
131 repo->idarraydata[i] = id;
133 else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
138 while ((p = strchr(dep, ':')) != 0)
145 /* argh, allow pattern: prefix. sigh */
146 if (p - dep == 7 && !strncmp(dep, "pattern", 7))
148 p = strchr(p + 1, ':');
153 idp = pool_str2id(pool, dep, 1);
155 id = pool_rel2id(pool, id, idp, REL_AND, 1);
160 if (dep[0] && dep[1])
162 dep[strlen(dep) - 1] = 0;
163 idp = pool_str2id(pool, dep, 1);
165 id = pool_rel2id(pool, id, idp, REL_AND, 1);
170 repo->idarraydata[i] = id;
172 else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
174 strcpy(buf, dep + 11);
175 if ((p = strrchr(buf, ')')) != 0)
177 id = pool_str2id(pool, buf, 1);
178 id = pool_rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
179 repo->idarraydata[i] = id;
183 if (freshens && repo->idarraydata[freshens])
185 Id idsupp = 0, idfresh = 0;
186 if (!supplements || !repo->idarraydata[supplements])
188 for (i = supplements; repo->idarraydata[i]; i++)
191 idsupp = repo->idarraydata[i];
193 idsupp = pool_rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
195 for (i = freshens; repo->idarraydata[i]; i++)
198 idfresh = repo->idarraydata[i];
200 idfresh = pool_rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
205 idsupp = pool_rel2id(pool, idsupp, idfresh, REL_AND, 1);
206 supplements = repo_addid_dep(repo, 0, idsupp, 0);
212 repo_fix_conflicts(Repo *repo, Offset conflicts)
214 char buf[1024], *p, *dep;
215 Pool *pool = repo->pool;
221 for (i = conflicts; repo->idarraydata[i]; i++)
223 id = repo->idarraydata[i];
226 dep = (char *)pool_id2str(pool, id);
227 if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2)
229 strcpy(buf, dep + 15);
230 if ((p = strchr(buf, ')')) != 0)
232 id = pool_str2id(pool, buf, 1);
233 id = pool_rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
234 repo->idarraydata[i] = id;
241 repo_rewrite_suse_deps(Solvable *s, Offset freshens)
243 s->supplements = repo_fix_supplements(s->repo, s->provides, s->supplements, freshens);
245 s->conflicts = repo_fix_conflicts(s->repo, s->conflicts);
248 /**********************************************************************************/
251 dep2name(Pool *pool, Id dep)
253 while (ISRELDEP(dep))
255 Reldep *rd = GETRELDEP(pool, dep);
262 providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con)
265 Solvable *sn = pool->solvables + n;
267 FOR_PROVIDES(p, pp, sn->name)
269 Solvable *s = pool->solvables + p;
270 if (s->name != sn->name || s->arch != sn->arch)
272 if (!MAPTST(installed, p))
274 if (pool_match_nevr(pool, pool->solvables + p, con))
276 return 1; /* found installed package that doesn't conflict */
282 providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *multiversionmap)
285 FOR_PROVIDES(p, pp, dep)
287 if (p == SYSTEMSOLVABLE)
289 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
291 if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
292 if (providedbyinstalled_multiversion(pool, installed, p, dep))
294 if (MAPTST(installed, p))
302 * 2: conflicts with installed
303 * 8: interesting (only true if installed)
308 providedbyinstalled_multiversion_xmap(Pool *pool, unsigned char *map, Id n, Id con)
311 Solvable *sn = pool->solvables + n;
313 FOR_PROVIDES(p, pp, sn->name)
315 Solvable *s = pool->solvables + p;
316 if (s->name != sn->name || s->arch != sn->arch)
318 if ((map[p] & 9) != 9)
320 if (pool_match_nevr(pool, pool->solvables + p, con))
322 return 1; /* found installed package that doesn't conflict */
329 providedbyinstalled_xmap(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap)
333 FOR_PROVIDES(p, pp, dep)
335 if (p == SYSTEMSOLVABLE)
336 return 1; /* always boring, as never constraining */
337 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
339 if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
340 if (providedbyinstalled_multiversion_xmap(pool, map, p, dep))
342 if ((map[p] & 9) == 9)
349 /* FIXME: this mirrors policy_illegal_vendorchange */
351 pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
354 Id vendormask1, vendormask2;
356 if (pool->custom_vendorcheck)
357 return pool->custom_vendorcheck(pool, s1, s2);
358 /* treat a missing vendor as empty string */
359 v1 = s1->vendor ? s1->vendor : ID_EMPTY;
360 v2 = s2->vendor ? s2->vendor : ID_EMPTY;
363 vendormask1 = pool_vendor2mask(pool, v1);
365 return 1; /* can't match */
366 vendormask2 = pool_vendor2mask(pool, v2);
367 if ((vendormask1 & vendormask2) != 0)
369 return 1; /* no class matches */
372 /* check if this patch is relevant according to the vendor. To bad that patches
373 * don't have a vendor, so we need to do some careful repo testing. */
375 solvable_is_irrelevant_patch(Solvable *s, Map *installedmap)
377 Pool *pool = s->repo->pool;
379 int hadpatchpackage = 0;
383 conp = s->repo->idarraydata + s->conflicts;
384 while ((con = *conp++) != 0)
390 rd = GETRELDEP(pool, con);
391 if (rd->flags != REL_LT)
393 FOR_PROVIDES(p, pp, con)
396 if (!MAPTST(installedmap, p))
398 si = pool->solvables + p;
399 if (!pool_match_nevr(pool, si, con))
401 FOR_PROVIDES(p2, pp2, rd->name)
403 Solvable *s2 = pool->solvables + p2;
404 if (!pool_match_nevr(pool, s2, rd->name))
406 if (pool_match_nevr(pool, s2, con))
407 continue; /* does not fulfill patch */
408 if (s2->repo == s->repo)
411 /* ok, we have a package from the patch repo that solves the conflict. check vendor */
412 if (si->vendor == s2->vendor)
414 if (!pool_illegal_vendorchange(pool, si, s2))
416 /* vendor change was illegal, ignore conflict */
421 /* if we didn't find a patchpackage don't claim that the patch is irrelevant */
422 if (!hadpatchpackage)
428 * solvable_trivial_installable_map - answers if a solvable is installable
429 * without any other installs/deinstalls.
430 * The packages considered to be installed are provided via the
431 * installedmap bitmap. A additional "conflictsmap" bitmap providing
432 * information about the conflicts of the installed packages can be
433 * used for extra speed up. Provide a NULL pointer if you do not
434 * have this information.
435 * Both maps can be created with pool_create_state_maps() or
436 * solver_create_state_maps().
439 * 1: solvable is installable without any other package changes
440 * 0: solvable is not installable
441 * -1: solvable is installable, but doesn't constrain any installed packages
444 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap)
446 Pool *pool = s->repo->pool;
451 int r, interesting = 0;
453 if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
457 reqp = s->repo->idarraydata + s->requires;
458 while ((req = *reqp++) != 0)
460 if (req == SOLVABLE_PREREQMARKER)
462 r = providedbyinstalled(pool, installedmap, req, 0, 0);
473 if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
475 conp = s->repo->idarraydata + s->conflicts;
476 while ((con = *conp++) != 0)
478 if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
480 if (ispatch && solvable_is_irrelevant_patch(s, installedmap))
484 if (!interesting && ISRELDEP(con))
486 con = dep2name(pool, con);
487 if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
491 if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap))
498 p = s - pool->solvables;
499 for (i = 1; i < pool->nsolvables; i++)
501 if (!MAPTST(installedmap, i))
503 s2 = pool->solvables + i;
506 conp = s2->repo->idarraydata + s2->conflicts;
507 while ((con = *conp++) != 0)
509 dp = pool_whatprovides_ptr(pool, con);
516 return interesting ? 1 : -1;
520 * different interface for solvable_trivial_installable_map, where
521 * the information about the installed packages is provided
525 solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap)
527 Pool *pool = s->repo->pool;
533 map_init(&installedmap, pool->nsolvables);
534 for (i = 0; i < installed->count; i++)
536 p = installed->elements[i];
537 if (p > 0) /* makes it work with decisionq */
538 MAPSET(&installedmap, p);
540 r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
541 map_free(&installedmap);
546 * different interface for solvable_trivial_installable_map, where
547 * the information about the installed packages is provided
548 * by a repo containing the installed solvables.
551 solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *multiversionmap)
553 Pool *pool = s->repo->pool;
559 map_init(&installedmap, pool->nsolvables);
560 FOR_REPO_SOLVABLES(installed, p, s2)
561 MAPSET(&installedmap, p);
562 r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
563 map_free(&installedmap);
568 * pool_trivial_installable - calculate if a set of solvables is
569 * trivial installable without any other installs/deinstalls of
570 * packages not belonging to the set.
572 * the state is returned in the result queue:
573 * 1: solvable is installable without any other package changes
574 * 0: solvable is not installable
575 * -1: solvable is installable, but doesn't constrain any installed packages
579 pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap)
582 Id p, *dp, con, *conp, req, *reqp;
586 map = solv_calloc(pool->nsolvables, 1);
587 for (p = 1; p < pool->nsolvables; p++)
589 if (!MAPTST(installedmap, p))
592 s = pool->solvables + p;
595 conp = s->repo->idarraydata + s->conflicts;
596 while ((con = *conp++) != 0)
598 dp = pool_whatprovides_ptr(pool, con);
600 map[p] |= 2; /* XXX: self conflict ? */
603 for (i = 0; i < pkgs->count; i++)
604 map[pkgs->elements[i]] = 16;
606 for (i = 0, did = 0; did < pkgs->count; i++, did++)
608 if (i == pkgs->count)
610 p = pkgs->elements[i];
611 if ((map[p] & 16) == 0)
613 if ((map[p] & 2) != 0)
618 s = pool->solvables + p;
622 reqp = s->repo->idarraydata + s->requires;
623 while ((req = *reqp++) != 0)
625 if (req == SOLVABLE_PREREQMARKER)
627 r = providedbyinstalled_xmap(pool, map, req, 0, 0);
630 /* decided and miss */
636 break; /* undecided */
637 m |= r; /* 1 | 9 | 17 */
646 int ispatch = 0; /* see solver.c patch handling */
648 if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
650 conp = s->repo->idarraydata + s->conflicts;
651 while ((con = *conp++) != 0)
653 if ((providedbyinstalled_xmap(pool, map, con, ispatch, multiversionmap) & 1) != 0)
659 if ((m == 1 || m == 17) && ISRELDEP(con))
661 con = dep2name(pool, con);
662 if ((providedbyinstalled_xmap(pool, map, con, ispatch, multiversionmap) & 1) != 0)
667 continue; /* found a conflict */
676 queue_init_clone(res, pkgs);
677 for (i = 0; i < pkgs->count; i++)
679 m = map[pkgs->elements[i]];
686 res->elements[i] = r;
692 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
694 pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0);
698 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
700 Pool *pool = solv->pool;
703 pool_create_state_maps(pool, &solv->decisionq, &installedmap, 0);
704 pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0);
705 for (i = 0; i < res->count; i++)
706 if (res->elements[i] != -1)
708 Solvable *s = pool->solvables + pkgs->elements[i];
709 if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap))
710 res->elements[i] = -1;
712 map_free(&installedmap);
716 solver_printtrivial(Solver *solv)
718 Pool *pool = solv->pool;
726 for (p = 1, s = pool->solvables + p; p < solv->pool->nsolvables; p++, s++)
728 n = pool_id2str(pool, s->name);
729 if (strncmp(n, "patch:", 6) != 0 && strncmp(n, "pattern:", 8) != 0)
739 solver_trivial_installable(solv, &in, &out);
740 POOL_DEBUG(SOLV_DEBUG_RESULT, "trivial installable status:\n");
741 for (i = 0; i < in.count; i++)
742 POOL_DEBUG(SOLV_DEBUG_RESULT, " %s: %d\n", pool_solvid2str(pool, in.elements[i]), out.elements[i]);
743 POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");