/* vim: sw=2 et cino=>4,n-2,{1s */ /* * Copyright (c) 2009-2015, SUSE LLC * * This program is licensed under the BSD license, read LICENSE.BSD * for further information */ #define _GNU_SOURCE #include #include #include #include #include "pool.h" #include "poolarch.h" #include "repo_solv.h" #ifdef ENABLE_SUSEREPO #include "repo_susetags.h" #endif #ifdef ENABLE_RPMMD #include "repo_rpmmd.h" #endif #ifdef ENABLE_DEBIAN #include "repo_deb.h" #endif #ifdef ENABLE_ARCHREPO #include "repo_arch.h" #endif #include "solver.h" #include "solv_xfopen.h" #ifdef _WIN32 #include "strfncs.h" #endif void usage(char** argv) { printf("Usage:\n%s: [options..] repo [--nocheck repo]...\n" "\t--exclude \twhitespace-separated list of (sub-)" "packagenames to ignore\n" "\t--withobsoletes\t\tCheck for obsoletes on packages contained in repos\n" "\t--nocheck\t\tDo not warn about all following repos (only use them to fulfill dependencies)\n" "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n" , argv[0]); exit(1); } #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO) static int strlen_comp(const char *str) { size_t l = strlen(str); if (l > 3 && !strcmp(str + l - 3, ".gz")) return l - 3; if (l > 3 && !strcmp(str + l - 3, ".xz")) return l - 3; if (l > 4 && !strcmp(str + l - 4, ".bz2")) return l - 4; if (l > 5 && !strcmp(str + l - 4, ".lzma")) return l - 5; return l; } #endif int main(int argc, char **argv) { Pool *pool; Solver *solv; Repo *repo; Queue job; Queue rids; Queue cand; char *arch, *exclude_pat; int i, j; Id p; Id archid, noarchid; Id rpmrel; #ifndef DEBIAN Id rpmid; #endif int status = 0; int nocheck = 0; int withsrc = 0; int obsoletepkgcheck = 0; exclude_pat = 0; if (argc < 3) usage(argv); arch = argv[1]; pool = pool_create(); pool_setarch(pool, arch); noarchid = pool->solvables[SYSTEMSOLVABLE].arch; for (i = 2; i < argc; i++) { FILE *fp; int r; #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO) int l; #endif if (!strcmp(argv[i], "--withsrc")) { withsrc++; continue; } if (!strcmp(argv[i], "--withobsoletes")) { obsoletepkgcheck++; continue; } if (!strcmp(argv[i], "--nocheck")) { if (!nocheck) nocheck = pool->nsolvables; continue; } if (!strcmp(argv[i], "--exclude")) { if (i + 1 >= argc) { printf("--exclude needs a whitespace separated list of substrings as parameter\n"); exit(1); } exclude_pat = argv[i + 1]; ++i; continue; } #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO) l = strlen_comp(argv[i]); #endif if (!strcmp(argv[i], "-")) fp = stdin; else if ((fp = solv_xfopen(argv[i], 0)) == 0) { perror(argv[i]); exit(1); } repo = repo_create(pool, argv[i]); r = 0; if (0) { } #ifdef ENABLE_SUSEREPO else if (l >= 8 && !strncmp(argv[i] + l - 8, "packages", 8)) { r = repo_add_susetags(repo, fp, 0, 0, 0); } #endif #ifdef ENABLE_RPMMD else if (l >= 11 && !strncmp(argv[i] + l - 11, "primary.xml", 11)) { r = repo_add_rpmmd(repo, fp, 0, 0); if (!r && i + 1 < argc) { l = strlen_comp(argv[i + 1]); if (l >= 13 && !strncmp(argv[i + 1] + l - 13, "filelists.xml", 13)) { i++; fclose(fp); if ((fp = solv_xfopen(argv[i], 0)) == 0) { perror(argv[i]); exit(1); } r = repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL); } } } #endif #ifdef ENABLE_DEBIAN else if (l >= 8 && !strncmp(argv[i] + l - 8, "Packages", 8)) { r = repo_add_debpackages(repo, fp, 0); } #endif #ifdef ENABLE_ARCHREPO else if (l >= 7 && (!strncmp(argv[i] + l - 7, ".db.tar", 7))) { r = repo_add_arch_repo(repo, fp, 0); } #endif else r = repo_add_solv(repo, fp, 0); if (r) { fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool)); exit(1); } if (fp != stdin) fclose(fp); } pool_addfileprovides(pool); pool_createwhatprovides(pool); archid = pool_str2id(pool, arch, 0); #ifndef DEBIAN rpmid = pool_str2id(pool, "rpm", 0); rpmrel = 0; if (rpmid && archid) { for (p = 1; p < pool->nsolvables; p++) { Solvable *s = pool->solvables + p; if (s->name == rpmid && s->arch == archid && pool_installable(pool, s)) break; } if (p < pool->nsolvables) rpmrel = pool_rel2id(pool, rpmid, archid, REL_ARCH, 1); } #else rpmrel = 0; #endif queue_init(&job); queue_init(&rids); queue_init(&cand); for (p = 1; p < (nocheck ? nocheck : pool->nsolvables); p++) { Solvable *s = pool->solvables + p; if (!s->repo) continue; if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)) { queue_push(&cand, p); continue; } if (!pool_installable(pool, s)) continue; if (archid && s->arch != archid && s->arch != noarchid) { /* check if we will conflict with a infarch rule, if yes, * don't bother checking the package */ Id rp, rpp; FOR_PROVIDES(rp, rpp, s->name) { if (pool->solvables[rp].name != s->name) continue; if (pool->solvables[rp].arch == archid) break; } if (rp) continue; } queue_push(&cand, p); } if (obsoletepkgcheck) { int obsoleteusesprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES); int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS); for (i = 0; i < cand.count; i++) { Solvable *s; s = pool->solvables + cand.elements[i]; if (s->obsoletes) { Id obs, *obsp = s->repo->idarraydata + s->obsoletes; while ((obs = *obsp++) != 0) { Id op, opp; FOR_PROVIDES(op, opp, obs) { Solvable *os = pool->solvables + op; if (nocheck && op >= nocheck) continue; if (solvable_identical(s, os)) continue; if (!obsoleteusesprovides && !pool_match_nevr(pool, os, obs)) continue; if (obsoleteusescolors && !pool_colormatch(pool, s, os)) continue; status = 2; printf("can't install %s:\n", pool_solvid2str(pool, op)); printf(" package is obsoleted by %s\n", pool_solvable2str(pool, s)); } } } } } solv = solver_create(pool); /* prune cand by doing weak installs */ while (cand.count) { queue_empty(&job); for (i = 0; i < cand.count; i++) { p = cand.elements[i]; queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK, p); } if (rpmrel) queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel); solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); solver_solve(solv, &job); /* prune... */ for (i = j = 0; i < cand.count; i++) { p = cand.elements[i]; if (solver_get_decisionlevel(solv, p) <= 0) { cand.elements[j++] = p; continue; } } cand.count = j; if (i == j) break; } /* now check every candidate */ for (i = 0; i < cand.count; i++) { Solvable *s; int problemcount; p = cand.elements[i]; if (exclude_pat) { char *ptr, *save = 0, *pattern; int match = 0; pattern = solv_strdup(exclude_pat); for (ptr = strtok_r(pattern, " ", &save); ptr; ptr = strtok_r(NULL, " ", &save)) { if (*ptr && strstr(pool_solvid2str(pool, p), ptr)) { match = 1; break; } } solv_free(pattern); if (match) continue; } s = pool->solvables + p; queue_empty(&job); queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE, p); if (rpmrel) queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel); solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); problemcount = solver_solve(solv, &job); if (problemcount) { Id problem = 0; Solvable *s2; status = 1; printf("can't install %s:\n", pool_solvable2str(pool, s)); while ((problem = solver_next_problem(solv, problem)) != 0) { solver_findallproblemrules(solv, problem, &rids); for (j = 0; j < rids.count; j++) { Id probr = rids.elements[j]; int k; Queue rinfo; queue_init(&rinfo); solver_allruleinfos(solv, probr, &rinfo); for (k = 0; k < rinfo.count; k += 4) { Id dep, source, target; source = rinfo.elements[k + 1]; target = rinfo.elements[k + 2]; dep = rinfo.elements[k + 3]; switch (rinfo.elements[k]) { case SOLVER_RULE_DISTUPGRADE: break; case SOLVER_RULE_INFARCH: s = pool_id2solvable(pool, source); printf(" %s has inferior architecture\n", pool_solvable2str(pool, s)); break; case SOLVER_RULE_UPDATE: s = pool_id2solvable(pool, source); printf(" %s can not be updated\n", pool_solvable2str(pool, s)); break; case SOLVER_RULE_JOB: case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: case SOLVER_RULE_JOB_UNKNOWN_PACKAGE: case SOLVER_RULE_JOB_UNSUPPORTED: break; case SOLVER_RULE_RPM: printf(" some dependency problem\n"); break; case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP: printf(" nothing provides requested %s\n", pool_dep2str(pool, dep)); break; case SOLVER_RULE_RPM_NOT_INSTALLABLE: s = pool_id2solvable(pool, source); printf(" package %s is not installable\n", pool_solvable2str(pool, s)); break; case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP: s = pool_id2solvable(pool, source); printf(" nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvable2str(pool, s)); if (ISRELDEP(dep)) { Reldep *rd = GETRELDEP(pool, dep); if (!ISRELDEP(rd->name)) { Id rp, rpp; FOR_PROVIDES(rp, rpp, rd->name) printf(" (we have %s)\n", pool_solvable2str(pool, pool->solvables + rp)); } } break; case SOLVER_RULE_RPM_SAME_NAME: s = pool_id2solvable(pool, source); s2 = pool_id2solvable(pool, target); printf(" cannot install both %s and %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2)); break; case SOLVER_RULE_RPM_PACKAGE_CONFLICT: s = pool_id2solvable(pool, source); s2 = pool_id2solvable(pool, target); printf(" package %s conflicts with %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2)); break; case SOLVER_RULE_RPM_PACKAGE_OBSOLETES: s = pool_id2solvable(pool, source); s2 = pool_id2solvable(pool, target); printf(" package %s obsoletes %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2)); break; case SOLVER_RULE_RPM_PACKAGE_REQUIRES: s = pool_id2solvable(pool, source); printf(" package %s requires %s, but none of the providers can be installed\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep)); break; case SOLVER_RULE_RPM_SELF_CONFLICT: s = pool_id2solvable(pool, source); printf(" package %s conflicts with %s provided by itself\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep)); break; } } } } } } solver_free(solv); exit(status); }