static void finishpackage(Pool *pool, Solvable *s, int keep, Queue *job) { Id *idp, id, sid; if (!s) return; if (!s->arch) s->arch = ARCH_ANY; if (!s->evr) s->evr = ID_EMPTY; sid = pool_rel2id(pool, s->name, s->evr, REL_EQ, 1); s->provides = repo_addid_dep(s->repo, s->provides, sid, 0); if (!job || !pool->installed || s->repo != pool->installed) return; if (keep == KEEP_VERSION) queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, sid); else if (keep == KEEP_PACKAGE) queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, s->name); else if (keep == KEEP_FEATURE) { for (idp = s->repo->idarraydata + s->provides; (id = *idp) != 0; idp++) { if (id != sid) /* skip self-provides */ queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id); } } }
/* * map a directory (containing a trailing /) into a number. * for unifywithstat this is the offset to the 16 byte stat result. * for unifywithcanon this is the offset to the normailzed dir. */ static Id normalizedir(struct cbdata *cbdata, const char *dir, int dirl, Id hx, int create) { Hashval h, hh; Id qx; Id nspaceoff; int mycnt; if (!hx) hx = dirl + 1; h = hx & cbdata->normapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->normap[2 * h]; if (!qx) break; if (qx == hx) { Id off = cbdata->normap[2 * h + 1]; char *dp = (char *)cbdata->filesspace + cbdata->norq.elements[off]; if (!strncmp(dp, dir, dirl) && dp[dirl] == 0) return cbdata->norq.elements[off + 1]; } h = HASHCHAIN_NEXT(h, hh, cbdata->normapn); } if (!create) return 0; /* new dir. work. */ if (dir >= (const char *)cbdata->filesspace && dir < (const char *)cbdata->filesspace + cbdata->filesspacen) { /* can happen when called from unifywithcanon */ Id off = dir - (const char *)cbdata->filesspace; nspaceoff = addfilesspace(cbdata, dirl + 1); dir = (const char *)cbdata->filesspace + off; } else nspaceoff = addfilesspace(cbdata, dirl + 1); if (dirl) memcpy(cbdata->filesspace + nspaceoff, dir, dirl); cbdata->filesspace[nspaceoff + dirl] = 0; mycnt = cbdata->norq.count; queue_push2(&cbdata->norq, nspaceoff, -1); /* -1: in progress */ cbdata->normap[2 * h] = hx; cbdata->normap[2 * h + 1] = mycnt; if (++cbdata->normapused * 2 > cbdata->normapn) cbdata->normap = growhash(cbdata->normap, &cbdata->normapn); /* unify */ if (cbdata->usestat) nspaceoff = unifywithstat(cbdata, nspaceoff, dirl); else nspaceoff = unifywithcanon(cbdata, nspaceoff, dirl); cbdata->norq.elements[mycnt + 1] = nspaceoff; /* patch in result */ #if 0 if (!cbdata->usestat) printf("%s normalized to %d: %s\n", cbdata->filesspace + cbdata->norq.elements[mycnt], nspaceoff, cbdata->filesspace + nspaceoff); #endif return nspaceoff; }
void pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags) { Id name = 0, arch = 0; int autoinstalled = -1; char *buf, *bp; int x, l, bufl, eof = 0; Id p, pp; queue_empty(q); buf = solv_malloc(4096); bufl = 4096; l = 0; while (!eof) { while (bufl - l < 1024) { bufl += 4096; if (bufl > 1024 * 64) break; /* hmm? */ buf = solv_realloc(buf, bufl); } if (!fgets(buf + l, bufl - l, fp)) { eof = 1; buf[l] = '\n'; buf[l + 1] = 0; } l = strlen(buf); if (l && buf[l - 1] == '\n') buf[--l] = 0; if (!*buf || eof) { l = 0; if (name && autoinstalled > 0) { if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) queue_push2(q, name, arch); else if ((flags & GET_USERINSTALLED_NAMES) != 0) queue_push(q, name); else { FOR_PROVIDES(p, pp, name) { Solvable *s = pool->solvables + p; if (s->name != name) continue; if (arch && s->arch != arch) continue; queue_push(q, p); } } } name = arch = 0; autoinstalled = -1; continue; }
int main(int argc, char **argv) { Pool *pool; Repo *installed; Solvable *s; Id p; int i; Queue todo, conflicts; void *state = 0; pool = pool_create(); pool_setdebuglevel(pool, 1); installed = repo_create(pool, "@System"); pool_set_installed(pool, installed); if (repo_add_rpmdb(installed, 0, 0)) { fprintf(stderr, "findfileconflicts: %s\n", pool_errstr(pool)); exit(1); } queue_init(&todo); queue_init(&conflicts); FOR_REPO_SOLVABLES(installed, p, s) queue_push(&todo, p); pool_findfileconflicts(pool, &todo, 0, &conflicts, &iterate_handle, (void *)&state); queue_free(&todo); for (i = 0; i < conflicts.count; i += 5) printf("%s: %s[%s] %s[%s]\n", pool_id2str(pool, conflicts.elements[i]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_id2str(pool, conflicts.elements[i + 2]), pool_solvid2str(pool, conflicts.elements[i + 3]), pool_id2str(pool, conflicts.elements[i + 4])); if (conflicts.count) { Queue job; int problemcnt; queue_init(&job); pool_add_fileconflicts_deps(pool, &conflicts); pool_addfileprovides(pool); pool_createwhatprovides(pool); pool_setdebuglevel(pool, 0); Solver *solv = solver_create(pool); queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0); #if 0 solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); #endif problemcnt = solver_solve(solv, &job); if (problemcnt) solver_printallsolutions(solv); else { Transaction *trans = solver_create_transaction(solv); transaction_print(trans); transaction_free(trans); } queue_free(&job); solver_free(solv); } queue_free(&conflicts); exit(0); }
static void findfileconflicts_alias_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { int isdir = S_ISDIR(info->mode); struct cbdata *cbdata = cbdatav; const char *dp; Id idx, dirid; Id hx, qx; Hashval h, hh; idx = cbdata->idx; if (!info->dirlen) return; dp = fn + info->dirlen; if (info->diridx != cbdata->lastdiridx) { cbdata->lastdiridx = info->diridx; cbdata->lastdirhash = 0; } dp = fn + info->dirlen; hx = strhash(dp); if (!hx) hx = strlen(fn) + 1; h = hx & cbdata->cflmapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->cflmap[2 * h]; if (!qx) break; if (qx == hx) break; h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn); } if (!qx || cbdata->cflmap[2 * h + 1] != -1) return; if (!cbdata->lastdirhash) cbdata->lastdirhash = strnhash(fn, dp - fn); dirid = normalizedir(cbdata, fn, dp - fn, cbdata->lastdirhash, 1); queue_push2(&cbdata->lookat, hx, idx); queue_push2(&cbdata->lookat, cbdata->lastdirhash, isdir ? -dirid : dirid); }
static Id unifywithstat(struct cbdata *cbdata, Id diroff, int dirl) { struct stat stb; int i; Hashval h, hh; Id hx, qx; Id nspaceoff; unsigned char statdata[16 + sizeof(stb.st_dev) + sizeof(stb.st_ino)]; if (dirl > 1 && cbdata->filesspace[diroff + dirl - 1] == '/') cbdata->filesspace[diroff + dirl - 1] = 0; cbdata->statsmade++; i = stat((char *)cbdata->filesspace + diroff, &stb); if (dirl > 1 && cbdata->filesspace[diroff + dirl - 1] == 0) cbdata->filesspace[diroff + dirl - 1] = '/'; if (i) return diroff; memset(statdata, 0, 16); memcpy(statdata + 8, &stb.st_dev, sizeof(stb.st_dev)); memcpy(statdata, &stb.st_ino, sizeof(stb.st_ino)); hx = 0; for (i = 15; i >= 0; i--) hx = (unsigned int)hx * 13 + statdata[i]; h = hx & cbdata->statmapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->statmap[2 * h]; if (!qx) break; if (qx == hx) { Id off = cbdata->statmap[2 * h + 1]; char *dp = (char *)cbdata->filesspace + cbdata->norq.elements[off]; if (!memcmp(dp, statdata, 16)) return cbdata->norq.elements[off + 1]; } h = HASHCHAIN_NEXT(h, hh, cbdata->statmapn); } /* new stat result. work. */ nspaceoff = addfilesspace(cbdata, 16); memcpy(cbdata->filesspace + nspaceoff, statdata, 16); queue_push2(&cbdata->norq, nspaceoff, nspaceoff); cbdata->statmap[2 * h] = hx; cbdata->statmap[2 * h + 1] = cbdata->norq.count - 2; if (++cbdata->statmapused * 2 > cbdata->statmapn) cbdata->statmap = growhash(cbdata->statmap, &cbdata->statmapn); return nspaceoff; }
void transaction_all_obs_pkgs(Transaction *trans, Id p, Queue *pkgs) { Pool *pool = trans->pool; Solvable *s = pool->solvables + p; Queue *ti = &trans->transaction_info; Id q; int i; queue_empty(pkgs); if (p <= 0 || !s->repo) return; if (s->repo == pool->installed) { q = trans->transaction_installed[p - pool->installed->start]; if (!q) return; if (q > 0) { /* only a single obsoleting package */ queue_push(pkgs, q); return; } /* find which packages obsolete us */ for (i = 0; i < ti->count; i += 2) if (ti->elements[i + 1] == p) queue_push2(pkgs, p, ti->elements[i]); /* sort obsoleters */ if (pkgs->count > 2) solv_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool); for (i = 0; i < pkgs->count; i += 2) pkgs->elements[i / 2] = pkgs->elements[i + 1]; queue_truncate(pkgs, pkgs->count / 2); } else { /* find the packages we obsolete */ for (i = 0; i < ti->count; i += 2) { if (ti->elements[i] == p) queue_push(pkgs, ti->elements[i + 1]); else if (pkgs->count) break; } } }
int main(int argc, char **argv) { Pool *pool; Queue job; Queue solq; Solver *solv; char *result = 0; int resultflags = 0; int debuglevel = 0; int writeresult = 0; int multijob = 0; int rescallback = 0; int c; int ex = 0; const char *list = 0; FILE *fp; const char *p; queue_init(&solq); while ((c = getopt(argc, argv, "vmrhl:s:")) >= 0) { switch (c) { case 'v': debuglevel++; break; case 'r': writeresult++; break; case 'm': rescallback = 1; break; case 'h': usage(0); break; case 'l': list = optarg; break; case 's': if ((p = strchr(optarg, ':'))) queue_push2(&solq, atoi(optarg), atoi(p + 1)); else queue_push2(&solq, 1, atoi(optarg)); break; default: usage(1); break; } } if (optind == argc) usage(1); for (; optind < argc; optind++) { pool = pool_create(); pool_setdebuglevel(pool, debuglevel); fp = fopen(argv[optind], "r"); if (!fp) { perror(argv[optind]); exit(0); } while (!feof(fp)) { queue_init(&job); result = 0; resultflags = 0; solv = testcase_read(pool, fp, argv[optind], &job, &result, &resultflags); if (!solv) { pool_free(pool); exit(1); } if (!multijob && !feof(fp)) multijob = 1; if (multijob) printf("test %d:\n", multijob++); if (list) { queue_empty(&job); selection_make(pool, &job, list, SELECTION_NAME|SELECTION_PROVIDES|SELECTION_FILELIST|SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL|SELECTION_GLOB|SELECTION_FLAT); if (!job.elements) printf("No match\n"); else { Queue q; int i; queue_init(&q); selection_solvables(pool, &job, &q); for (i = 0; i < q.count; i++) printf(" - %s\n", testcase_solvid2str(pool, q.elements[i])); queue_free(&q); } } else if (result || writeresult) { char *myresult, *resultdiff; struct reportsolutiondata reportsolutiondata; memset(&reportsolutiondata, 0, sizeof(reportsolutiondata)); if (rescallback) { solv->solution_callback = reportsolutioncb; solv->solution_callback_data = &reportsolutiondata; } solver_solve(solv, &job); solv->solution_callback = 0; solv->solution_callback_data = 0; if (!resultflags) resultflags = TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS; myresult = testcase_solverresult(solv, resultflags); if (rescallback && reportsolutiondata.result) { reportsolutiondata.result = solv_dupjoin(reportsolutiondata.result, myresult, 0); solv_free(myresult); myresult = reportsolutiondata.result; } if (writeresult) { if (*myresult) { if (writeresult > 1) { const char *p; int i; printf("result "); p = "%s"; for (i = 0; resultflags2str[i].str; i++) if ((resultflags & resultflags2str[i].flag) != 0) { printf(p, resultflags2str[i].str); p = ",%s"; } printf(" <inline>\n"); p = myresult; while (*p) { const char *p2 = strchr(p, '\n'); p2 = p2 ? p2 + 1 : p + strlen(p); printf("#>%.*s", (int)(p2 - p), p); p = p2; } } else printf("%s", myresult); } } else { resultdiff = testcase_resultdiff(result, myresult); if (resultdiff) { printf("Results differ:\n%s", resultdiff); ex = 1; solv_free(resultdiff); } } solv_free(result); solv_free(myresult); } else { int pcnt = solver_solve(solv, &job); if (pcnt && solq.count) { int i, taken = 0; for (i = 0; i < solq.count; i += 2) { if (solq.elements[i] > 0 && solq.elements[i] <= pcnt) if (solq.elements[i + 1] > 0 && solq.elements[i + 1] <= solver_solution_count(solv, solq.elements[i])) { printf("problem %d: taking solution %d\n", solq.elements[i], solq.elements[i + 1]); solver_take_solution(solv, solq.elements[i], solq.elements[i + 1], &job); taken = 1; } } if (taken) pcnt = solver_solve(solv, &job); } if (pcnt) { int problem, solution, scnt; printf("Found %d problems:\n", pcnt); for (problem = 1; problem <= pcnt; problem++) { printf("Problem %d:\n", problem); #if 1 solver_printprobleminfo(solv, problem); #else { Queue pq; int j; queue_init(&pq); solver_findallproblemrules(solv, problem, &pq); for (j = 0; j < pq.count; j++) solver_printproblemruleinfo(solv, pq.elements[j]); queue_free(&pq); } #endif printf("\n"); scnt = solver_solution_count(solv, problem); for (solution = 1; solution <= scnt; solution++) { printf("Solution %d:\n", solution); solver_printsolution(solv, problem, solution); printf("\n"); } } } else { Transaction *trans = solver_create_transaction(solv); printf("Transaction summary:\n\n"); transaction_print(trans); transaction_free(trans); } } queue_free(&job); solver_free(solv); } pool_free(pool); fclose(fp); } queue_free(&solq); exit(ex); }
int repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags) { Pool *pool = repo->pool; char *buf, *p; int bufa, bufl, c; Solvable *s; int instanza = 0; int inrequest = 0; int isinstalled = 0; int keep = 0; Repo *xrepo; xrepo = repo ? repo : installedrepo; if (!xrepo) return -1; buf = solv_malloc(4096); bufa = 4096; bufl = 0; s = 0; while (fgets(buf + bufl, bufa - bufl, fp) > 0) { bufl += strlen(buf + bufl); if (bufl && buf[bufl - 1] != '\n') { if (bufa - bufl < 256) { bufa += 4096; buf = solv_realloc(buf, bufa); } continue; } buf[--bufl] = 0; c = getc(fp); if (c == ' ' || c == '\t') { /* continuation line */ buf[bufl++] = ' '; continue; } if (c != EOF) ungetc(c, fp); bufl = 0; if (*buf == '#') continue; if (!*buf) { if (s && !repo && !isinstalled) { repo_free_solvable(repo, s - pool->solvables, 1); s = 0; } if (s) finishpackage(pool, s, keep, job); s = 0; keep = 0; instanza = 0; inrequest = 0; continue; } p = strchr(buf, ':'); if (!p) continue; /* hmm */ *p++ = 0; while (*p == ' ' || *p == '\t') p++; if (!instanza) { instanza = 1; inrequest = 0; if (!strcmp(buf, "request")) { inrequest = 1; continue; } if (!strcmp(buf, "package")) { s = pool_id2solvable(pool, repo_add_solvable(xrepo)); isinstalled = 0; keep = 0; } } if (inrequest) { if (!job) continue; if (!strcmp(buf, "install")) { Id id, *idp; Offset off = makedeps(xrepo, p, 0, 0); for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++) queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id); } else if (!strcmp(buf, "remove")) { Id id, *idp; Offset off = makedeps(xrepo, p, 0, 0); for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++) queue_push2(job, SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES, id); } else if (!strcmp(buf, "upgrade")) { Id id, *idp; Offset off = makedeps(xrepo, p, 0, 0); for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++) queue_push2(job, SOLVER_INSTALL|SOLVER_ORUPDATE|SOLVER_SOLVABLE_PROVIDES, id); } continue; } if (!s) continue; /* we ignore the preamble for now */ switch (buf[0]) { case 'c': if (!strcmp(buf, "conflicts")) { s->conflicts = makedeps(s->repo, p, s->conflicts, 0); continue; } case 'd': if (!strcmp(buf, "depends")) { s->requires = makedeps(s->repo, p, s->requires, 0); continue; } break; case 'k': if (!strcmp(buf, "keep")) { if (!job) continue; if (!strcmp(p, "version")) keep = KEEP_VERSION; else if (!strcmp(p, "package")) keep = KEEP_PACKAGE; else if (!strcmp(p, "feature")) keep = KEEP_FEATURE; continue; } break; case 'i': if (!strcmp(buf, "installed")) { if (!strcmp(p, "true")) { isinstalled = 1; if (!installedrepo) { repo_free_solvable(repo, s - pool->solvables, 1); s = 0; } else if (s->repo != installedrepo) { copysolvabledata(pool, s, installedrepo); s->repo->nsolvables--; s->repo = installedrepo; if (s - pool->solvables < s->repo->start) s->repo->start = s - pool->solvables; if (s - pool->solvables >= s->repo->end) s->repo->end = s - pool->solvables + 1; s->repo->nsolvables++; } } continue; } break; case 'p': if (!strcmp(buf, "package")) { s->name = pool_str2id(pool, p, 1); continue; } if (!strcmp(buf, "provides")) { s->provides = makedeps(s->repo, p, s->provides, 0); continue; } break; case 'r': if (!strcmp(buf, "depends")) { s->recommends = makedeps(s->repo, p, s->recommends, 0); continue; } break; case 'v': if (!strcmp(buf, "version")) { s->evr = pool_str2id(pool, p, 1); continue; } break; } } if (s && !repo && !isinstalled) { repo_free_solvable(repo, s - pool->solvables, 1); s = 0; } if (s) finishpackage(pool, s, keep, job); solv_free(buf); return 0; }
int repo_add_autopattern(Repo *repo, int flags) { Pool *pool = repo->pool; Repodata *data = 0; Solvable *s, *s2; Queue q, q2; Id p; Id pattern_id; Id autopattern_id = 0; int i, j; queue_init(&q); queue_init(&q2); pattern_id = pool_str2id(pool, "pattern()", 9); FOR_REPO_SOLVABLES(repo, p, s) { const char *n = pool_id2str(pool, s->name); if (!strncmp("pattern:", n, 8)) queue_push(&q, p); else if (s->provides) { Id prv, *prvp = repo->idarraydata + s->provides; while ((prv = *prvp++) != 0) /* go through all provides */ if (ISRELDEP(prv)) { Reldep *rd = GETRELDEP(pool, prv); if (rd->name == pattern_id && rd->flags == REL_EQ) { queue_push2(&q2, p, rd->evr); break; } } } } for (i = 0; i < q2.count; i += 2) { const char *pn = 0; char *newname; Id name, prv, *prvp; const char *str; unsigned long long num; s = pool->solvables + q2.elements[i]; /* construct new name */ newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, q2.elements[i + 1]), 0); unescape(newname); name = pool_str2id(pool, newname, 0); if (name) { /* check if we already have that pattern */ for (j = 0; j < q.count; j++) { s2 = pool->solvables + q.elements[j]; if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr) break; } if (j < q.count) continue; /* yes, do not add again */ } /* new pattern */ if (!name) name = pool_str2id(pool, newname, 1); if (!data) { repo_internalize(repo); /* to make that the lookups work */ data = repo_add_repodata(repo, flags); } s2 = pool_id2solvable(pool, repo_add_solvable(repo)); s = pool->solvables + q2.elements[i]; /* re-calc pointer */ s2->name = name; s2->arch = s->arch; s2->evr = s->evr; s2->vendor = s->vendor; /* add link requires */ s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0); /* add autopattern provides */ if (!autopattern_id) autopattern_id = pool_str2id(pool, "autopattern()", 1); s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0); /* add self provides */ s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0); if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0) repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num); if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0) repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num); if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str); if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str); /* fill in stuff from provides */ prvp = repo->idarraydata + s->provides; while ((prv = *prvp++) != 0) /* go through all provides */ { Id evr = 0; if (ISRELDEP(prv)) { Reldep *rd = GETRELDEP(pool, prv); if (rd->flags != REL_EQ) continue; prv = rd->name; evr = rd->evr; } pn = pool_id2str(pool, prv); if (strncmp("pattern-", pn, 8) != 0) continue; newname = 0; if (evr) { newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0); unescape(newname); } if (!strncmp(pn, "pattern-category(", 17) && evr) { char lang[9]; int l = strlen(pn); Id langtag; if (l > 17 + 9 || pn[l - 1] != ')') continue; strncpy(lang, pn + 17, l - 17 - 1); lang[l - 17 - 1] = 0; langtag = SOLVABLE_CATEGORY; if (*lang && strcmp(lang, "en") != 0) langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1); repodata_set_str(data, s2 - pool->solvables, langtag, newname); } else if (!strcmp(pn, "pattern-includes()") && evr) repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0)); else if (!strcmp(pn, "pattern-extends()") && evr) repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0)); else if (!strcmp(pn, "pattern-icon()") && evr) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname); else if (!strcmp(pn, "pattern-order()") && evr) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname); else if (!strcmp(pn, "pattern-visible()") && !evr) repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE); } } queue_free(&q); queue_free(&q2); if (data && !(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); else if (!data && !(flags & REPO_NO_INTERNALIZE)) repo_internalize(repo); return 0; }
/* same as findfileconflicts_cb, but * - hashes with just the basename * - sets idx in a map instead of pushing to lookat * - sets the hash element to -1 if there may be a conflict */ static void findfileconflicts_basename_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { struct cbdata *cbdata = cbdatav; int isdir = S_ISDIR(info->mode); const char *dp; Id idx, oidx; Id hx, qx; Hashval h, hh; idx = cbdata->idx; if (!info->dirlen) return; dp = fn + info->dirlen; hx = strhash(dp); if (!hx) hx = strlen(fn) + 1; h = hx & cbdata->cflmapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->cflmap[2 * h]; if (!qx) break; if (qx == hx) break; h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn); } if (!qx) { /* a miss */ if (!cbdata->create) return; cbdata->cflmap[2 * h] = hx; cbdata->cflmap[2 * h + 1] = (isdir ? -idx - 2 : idx); if (++cbdata->cflmapused * 2 > cbdata->cflmapn) cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn); return; } oidx = cbdata->cflmap[2 * h + 1]; if (oidx < -1) { int i; if (isdir) { /* both are directories. delay the conflict, keep oidx in slot */ queue_push2(&cbdata->lookat_dir, hx, idx); return; } oidx = -idx - 2; /* now have file, had directories before. */ cbdata->cflmap[2 * h + 1] = oidx; /* make it a file */ /* dump all delayed directory hits for hx */ for (i = 0; i < cbdata->lookat_dir.count; i += 2) if (cbdata->lookat_dir.elements[i] == hx) MAPSET(&cbdata->idxmap, cbdata->lookat_dir.elements[i + 1]); } else if (oidx == idx) return; /* no conflicts with ourself, please */ if (oidx >= 0) MAPSET(&cbdata->idxmap, oidx); MAPSET(&cbdata->idxmap, idx); if (oidx != -1) cbdata->cflmap[2 * h + 1] = -1; }
static void findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { struct cbdata *cbdata = cbdatav; int isdir = S_ISDIR(info->mode); const char *dp; Id idx, oidx; Id hx, qx; Hashval h, hh, dhx; idx = cbdata->idx; if (!info->dirlen) return; dp = fn + info->dirlen; if (info->diridx != cbdata->lastdiridx) { cbdata->lastdiridx = info->diridx; cbdata->lastdirhash = strnhash(fn, dp - fn); } dhx = cbdata->lastdirhash; /* this mirrors the "if (!hx) hx = strlen(fn) + 1" in finddirs_cb */ if (!isindirmap(cbdata, dhx ? dhx : dp - fn + 1)) return; hx = strhash_cont(dp, dhx); if (!hx) hx = strlen(fn) + 1; h = hx & cbdata->cflmapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->cflmap[2 * h]; if (!qx) break; if (qx == hx) break; h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn); } if (!qx) { /* a miss */ if (!cbdata->create) return; cbdata->cflmap[2 * h] = hx; cbdata->cflmap[2 * h + 1] = (isdir ? ~idx : idx); if (++cbdata->cflmapused * 2 > cbdata->cflmapn) cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn); return; } oidx = cbdata->cflmap[2 * h + 1]; if (oidx < 0) { int i; if (isdir) { /* both are directories. delay the conflict, keep oidx in slot */ queue_push2(&cbdata->lookat_dir, hx, idx); return; } oidx = ~oidx; /* now have file, had directories before. */ cbdata->cflmap[2 * h + 1] = oidx; /* make it a file */ /* dump all delayed directory hits for hx */ for (i = 0; i < cbdata->lookat_dir.count; i += 2) if (cbdata->lookat_dir.elements[i] == hx) { queue_push2(&cbdata->lookat, hx, cbdata->lookat_dir.elements[i + 1]); queue_push2(&cbdata->lookat, 0, 0); } } else if (oidx == idx) return; /* no conflicts with ourself, please */ queue_push2(&cbdata->lookat, hx, oidx); queue_push2(&cbdata->lookat, 0, 0); queue_push2(&cbdata->lookat, hx, idx); queue_push2(&cbdata->lookat, 0, 0); }
int main(int argc, char **argv) { Pool *pool; Repo *commandlinerepo = 0; Id *commandlinepkgs = 0; Id p; struct repoinfo *repoinfos, installedrepoinfo; int nrepoinfos = 0; int mainmode = 0, mode = 0; int i, newpkgs; Queue job, checkq; Solver *solv = 0; Transaction *trans; FILE **newpkgsfps; Queue repofilter; Queue kindfilter; Queue archfilter; int archfilter_src = 0; int cleandeps = 0; int forcebest = 0; char *rootdir = 0; char *keyname = 0; int keyname_depstr = 0; int debuglevel = 0; int answer, acnt = 0; argc--; argv++; while (argc && !strcmp(argv[0], "-d")) { debuglevel++; argc--; argv++; } if (!argv[0]) usage(1); if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in")) { mainmode = MODE_INSTALL; mode = SOLVER_INSTALL; } #if defined(SUSE) || defined(FEDORA) else if (!strcmp(argv[0], "patch")) { mainmode = MODE_PATCH; mode = SOLVER_INSTALL; } #endif else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm")) { mainmode = MODE_ERASE; mode = SOLVER_ERASE; } else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "ls")) { mainmode = MODE_LIST; mode = 0; } else if (!strcmp(argv[0], "info")) { mainmode = MODE_INFO; mode = 0; } else if (!strcmp(argv[0], "search") || !strcmp(argv[0], "se")) { mainmode = MODE_SEARCH; mode = 0; } else if (!strcmp(argv[0], "verify")) { mainmode = MODE_VERIFY; mode = SOLVER_VERIFY; } else if (!strcmp(argv[0], "update") || !strcmp(argv[0], "up")) { mainmode = MODE_UPDATE; mode = SOLVER_UPDATE; } else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup")) { mainmode = MODE_DISTUPGRADE; mode = SOLVER_DISTUPGRADE; } else if (!strcmp(argv[0], "repos") || !strcmp(argv[0], "repolist") || !strcmp(argv[0], "lr")) { mainmode = MODE_REPOLIST; mode = 0; } else usage(1); for (;;) { if (argc > 2 && !strcmp(argv[1], "--root")) { rootdir = argv[2]; argc -= 2; argv += 2; } else if (argc > 1 && !strcmp(argv[1], "--clean")) { cleandeps = 1; argc--; argv++; } else if (argc > 1 && !strcmp(argv[1], "--best")) { forcebest = 1; argc--; argv++; } else if (argc > 1 && !strcmp(argv[1], "--depstr")) { keyname_depstr = 1; argc--; argv++; } else if (argc > 2 && !strcmp(argv[1], "--keyname")) { keyname = argv[2]; argc -= 2; argv += 2; } else break; } set_userhome(); pool = pool_create(); pool_set_rootdir(pool, rootdir); #if 0 { const char *langs[] = {"de_DE", "de", "en"}; pool_set_languages(pool, langs, sizeof(langs)/sizeof(*langs)); } #endif pool_setloadcallback(pool, load_stub, 0); #ifdef SUSE pool->nscallback = nscallback; #endif if (debuglevel) pool_setdebuglevel(pool, debuglevel); setarch(pool); pool_set_flag(pool, POOL_FLAG_ADDFILEPROVIDESFILTERED, 1); repoinfos = read_repoinfos(pool, &nrepoinfos); sort_repoinfos(repoinfos, nrepoinfos); if (mainmode == MODE_REPOLIST) { int j = 1; for (i = 0; i < nrepoinfos; i++) { struct repoinfo *cinfo = repoinfos + i; if (!cinfo->enabled) continue; printf("%d: %-20s %s (prio %d)\n", j++, cinfo->alias, cinfo->name, cinfo->priority); } exit(0); } memset(&installedrepoinfo, 0, sizeof(installedrepoinfo)); if (!read_installed_repo(&installedrepoinfo, pool)) exit(1); read_repos(pool, repoinfos, nrepoinfos); /* setup filters */ queue_init(&repofilter); queue_init(&kindfilter); queue_init(&archfilter); while (argc > 1) { if (!strcmp(argv[1], "-i")) { queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, pool->installed->repoid); argc--; argv++; } else if (argc > 2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "--repo"))) { Id repoid = find_repo(argv[2], pool, repoinfos, nrepoinfos); if (!repoid) { fprintf(stderr, "%s: no such repo\n", argv[2]); exit(1); } /* SETVENDOR is actually wrong but useful */ queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO | SOLVER_SETVENDOR, repoid); argc -= 2; argv += 2; } else if (argc > 2 && !strcmp(argv[1], "--arch")) { if (!strcmp(argv[2], "src") || !strcmp(argv[2], "nosrc")) archfilter_src = 1; queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, argv[2], 1), REL_ARCH, 1)); argc -= 2; argv += 2; } else if (argc > 2 && (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--type"))) { const char *kind = argv[2]; if (!strcmp(kind, "srcpackage")) { /* hey! should use --arch! */ queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, ARCH_SRC, REL_ARCH, 1)); archfilter_src = 1; argc -= 2; argv += 2; continue; } if (!strcmp(kind, "package")) kind = ""; if (!strcmp(kind, "all")) queue_push2(&kindfilter, SOLVER_SOLVABLE_ALL, 0); else queue_push2(&kindfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, kind, 1), REL_KIND, 1)); argc -= 2; argv += 2; } else break; } if (mainmode == MODE_SEARCH) { Queue sel, q; Dataiterator di; if (argc != 2) usage(1); pool_createwhatprovides(pool); queue_init(&sel); dataiterator_init(&di, pool, 0, 0, 0, argv[1], SEARCH_SUBSTRING|SEARCH_NOCASE); dataiterator_set_keyname(&di, SOLVABLE_NAME); dataiterator_set_search(&di, 0, 0); while (dataiterator_step(&di)) queue_push2(&sel, SOLVER_SOLVABLE, di.solvid); dataiterator_set_keyname(&di, SOLVABLE_SUMMARY); dataiterator_set_search(&di, 0, 0); while (dataiterator_step(&di)) queue_push2(&sel, SOLVER_SOLVABLE, di.solvid); dataiterator_set_keyname(&di, SOLVABLE_DESCRIPTION); dataiterator_set_search(&di, 0, 0); while (dataiterator_step(&di)) queue_push2(&sel, SOLVER_SOLVABLE, di.solvid); dataiterator_free(&di); if (repofilter.count) selection_filter(pool, &sel, &repofilter); queue_init(&q); selection_solvables(pool, &sel, &q); queue_free(&sel); for (i = 0; i < q.count; i++) { Solvable *s = pool_id2solvable(pool, q.elements[i]); printf(" - %s [%s]: %s\n", pool_solvable2str(pool, s), s->repo->name, solvable_lookup_str(s, SOLVABLE_SUMMARY)); } queue_free(&q); exit(0); } /* process command line packages */ if (mainmode == MODE_LIST || mainmode == MODE_INFO || mainmode == MODE_INSTALL) { for (i = 1; i < argc; i++) { if (!is_cmdline_package((const char *)argv[i])) continue; if (access(argv[i], R_OK)) { perror(argv[i]); exit(1); } if (!commandlinepkgs) commandlinepkgs = solv_calloc(argc, sizeof(Id)); if (!commandlinerepo) commandlinerepo = repo_create(pool, "@commandline"); p = add_cmdline_package(commandlinerepo, (const char *)argv[i]); if (!p) { fprintf(stderr, "could not add '%s'\n", argv[i]); exit(1); } commandlinepkgs[i] = p; } if (commandlinerepo) repo_internalize(commandlinerepo); } #if defined(ENABLE_RPMDB) if (pool->disttype == DISTTYPE_RPM) addfileprovides(pool); #endif #ifdef SUSE add_autopackages(pool); #endif pool_createwhatprovides(pool); if (keyname) keyname = solv_dupjoin("solvable:", keyname, 0); queue_init(&job); for (i = 1; i < argc; i++) { Queue job2; int flags, rflags; if (commandlinepkgs && commandlinepkgs[i]) { queue_push2(&job, SOLVER_SOLVABLE, commandlinepkgs[i]); continue; } queue_init(&job2); flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB; flags |= SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL; if (kindfilter.count) flags |= SELECTION_SKIP_KIND; if (mode == MODE_LIST || archfilter_src) flags |= SELECTION_WITH_SOURCE; if (argv[i][0] == '/') flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0); if (!keyname) rflags = selection_make(pool, &job2, argv[i], flags); else { if (keyname_depstr) flags |= SELECTION_MATCH_DEPSTR; rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0); } if (repofilter.count) selection_filter(pool, &job2, &repofilter); if (archfilter.count) selection_filter(pool, &job2, &archfilter); if (kindfilter.count) selection_filter(pool, &job2, &kindfilter); if (!job2.count) { flags |= SELECTION_NOCASE; if (!keyname) rflags = selection_make(pool, &job2, argv[i], flags); else rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0); if (repofilter.count) selection_filter(pool, &job2, &repofilter); if (archfilter.count) selection_filter(pool, &job2, &archfilter); if (kindfilter.count) selection_filter(pool, &job2, &kindfilter); if (job2.count) printf("[ignoring case for '%s']\n", argv[i]); } if (!job2.count) { fprintf(stderr, "nothing matches '%s'\n", argv[i]); exit(1); } if (rflags & SELECTION_FILELIST) printf("[using file list match for '%s']\n", argv[i]); if (rflags & SELECTION_PROVIDES) printf("[using capability match for '%s']\n", argv[i]); queue_insertn(&job, job.count, job2.count, job2.elements); queue_free(&job2); } keyname = solv_free(keyname); if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count || archfilter.count || kindfilter.count)) { queue_push2(&job, SOLVER_SOLVABLE_ALL, 0); if (repofilter.count) selection_filter(pool, &job, &repofilter); if (archfilter.count) selection_filter(pool, &job, &archfilter); if (kindfilter.count) selection_filter(pool, &job, &kindfilter); } queue_free(&repofilter); queue_free(&archfilter); queue_free(&kindfilter); if (!job.count && mainmode != MODE_PATCH) { printf("no package matched\n"); exit(1); } if (mainmode == MODE_LIST || mainmode == MODE_INFO) { /* list mode, no solver needed */ Queue q; queue_init(&q); for (i = 0; i < job.count; i += 2) { int j; queue_empty(&q); pool_job2solvables(pool, &q, job.elements[i], job.elements[i + 1]); for (j = 0; j < q.count; j++) { Solvable *s = pool_id2solvable(pool, q.elements[j]); if (mainmode == MODE_INFO) { const char *str; printf("Name: %s\n", pool_solvable2str(pool, s)); printf("Repo: %s\n", s->repo->name); printf("Summary: %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY)); str = solvable_lookup_str(s, SOLVABLE_URL); if (str) printf("Url: %s\n", str); str = solvable_lookup_str(s, SOLVABLE_LICENSE); if (str) printf("License: %s\n", str); printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION)); printf("\n"); } else { #if 1 const char *sum = solvable_lookup_str_lang(s, SOLVABLE_SUMMARY, "de", 1); #else const char *sum = solvable_lookup_str_poollang(s, SOLVABLE_SUMMARY); #endif printf(" - %s [%s]\n", pool_solvable2str(pool, s), s->repo->name); if (sum) printf(" %s\n", sum); } } } queue_free(&q); queue_free(&job); pool_free(pool); free_repoinfos(repoinfos, nrepoinfos); solv_free(commandlinepkgs); exit(0); } #if defined(SUSE) || defined(FEDORA) if (mainmode == MODE_PATCH) add_patchjobs(pool, &job); #endif // add mode for (i = 0; i < job.count; i += 2) { job.elements[i] |= mode; if (mode == SOLVER_UPDATE && pool_isemptyupdatejob(pool, job.elements[i], job.elements[i + 1])) job.elements[i] ^= SOLVER_UPDATE ^ SOLVER_INSTALL; if (cleandeps) job.elements[i] |= SOLVER_CLEANDEPS; if (forcebest) job.elements[i] |= SOLVER_FORCEBEST; } // multiversion test // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1)); // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1)); // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1)); #if 0 queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); #endif rerunsolver: solv = solver_create(pool); solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1); #ifdef FEDORA solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1); #endif if (mainmode == MODE_ERASE) solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); /* don't nag */ solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1); for (;;) { Id problem, solution; int pcnt, scnt; if (!solver_solve(solv, &job)) break; pcnt = solver_problem_count(solv); printf("Found %d problems:\n", pcnt); for (problem = 1; problem <= pcnt; problem++) { int take = 0; printf("Problem %d/%d:\n", problem, pcnt); solver_printprobleminfo(solv, problem); printf("\n"); scnt = solver_solution_count(solv, problem); for (solution = 1; solution <= scnt; solution++) { printf("Solution %d:\n", solution); solver_printsolution(solv, problem, solution); printf("\n"); } for (;;) { char inbuf[128], *ip; printf("Please choose a solution: "); fflush(stdout); *inbuf = 0; if (!(ip = fgets(inbuf, sizeof(inbuf), stdin))) { printf("Abort.\n"); exit(1); } while (*ip == ' ' || *ip == '\t') ip++; if (*ip >= '0' && *ip <= '9') { take = atoi(ip); if (take >= 1 && take <= scnt) break; } if (*ip == 's') { take = 0; break; } if (*ip == 'q') { printf("Abort.\n"); exit(1); } } if (!take) continue; solver_take_solution(solv, problem, take, &job); } } trans = solver_create_transaction(solv); if (!trans->steps.count) { printf("Nothing to do.\n"); transaction_free(trans); solver_free(solv); queue_free(&job); pool_free(pool); free_repoinfos(repoinfos, nrepoinfos); solv_free(commandlinepkgs); exit(1); } /* display transaction to the user and ask for confirmation */ printf("\n"); printf("Transaction summary:\n\n"); transaction_print(trans); #if defined(SUSE) showdiskusagechanges(trans); #endif printf("install size change: %d K\n", transaction_calc_installsizechange(trans)); printf("\n"); acnt = solver_alternatives_count(solv); if (acnt) { if (acnt == 1) printf("Have one alternative:\n"); else printf("Have %d alternatives:\n", acnt); for (i = 1; i <= acnt; i++) { Id id, from; int atype = solver_get_alternative(solv, i, &id, &from, 0, 0, 0); printf(" - %s\n", solver_alternative2str(solv, atype, id, from)); } printf("\n"); answer = yesno("OK to continue (y/n/a)? ", 'a'); } else answer = yesno("OK to continue (y/n)? ", 0); if (answer == 'a') { Queue choicesq; Queue answerq; Id id, from, chosen; int j; queue_init(&choicesq); queue_init(&answerq); for (i = 1; i <= acnt; i++) { int atype = solver_get_alternative(solv, i, &id, &from, &chosen, &choicesq, 0); printf("\n%s\n", solver_alternative2str(solv, atype, id, from)); for (j = 0; j < choicesq.count; j++) { Id p = choicesq.elements[j]; if (p < 0) p = -p; queue_push(&answerq, p); printf("%6d: %s\n", answerq.count, pool_solvid2str(pool, p)); } } queue_free(&choicesq); printf("\n"); for (;;) { char inbuf[128], *ip; int neg = 0; printf("OK to continue (y/n), or number to change alternative: "); fflush(stdout); *inbuf = 0; if (!(ip = fgets(inbuf, sizeof(inbuf), stdin))) { printf("Abort.\n"); exit(1); } while (*ip == ' ' || *ip == '\t') ip++; if (*ip == '-' && ip[1] >= '0' && ip[1] <= '9') { neg = 1; ip++; } if (*ip >= '0' && *ip <= '9') { int take = atoi(ip); if (take > 0 && take <= answerq.count) { Id p = answerq.elements[take - 1]; queue_free(&answerq); queue_push2(&job, (neg ? SOLVER_DISFAVOR : SOLVER_FAVOR) | SOLVER_SOLVABLE_NAME, pool->solvables[p].name); solver_free(solv); solv = 0; goto rerunsolver; break; } } if (*ip == 'n' || *ip == 'y') { answer = *ip == 'n' ? 0 : *ip; break; } } queue_free(&answerq); } if (!answer) { printf("Abort.\n"); transaction_free(trans); solver_free(solv); queue_free(&job); pool_free(pool); free_repoinfos(repoinfos, nrepoinfos); solv_free(commandlinepkgs); exit(1); } /* download all new packages */ queue_init(&checkq); newpkgs = transaction_installedresult(trans, &checkq); newpkgsfps = 0; if (newpkgs) { int downloadsize = 0; for (i = 0; i < newpkgs; i++) { Solvable *s; p = checkq.elements[i]; s = pool_id2solvable(pool, p); downloadsize += solvable_lookup_sizek(s, SOLVABLE_DOWNLOADSIZE, 0); } printf("Downloading %d packages, %d K\n", newpkgs, downloadsize); newpkgsfps = solv_calloc(newpkgs, sizeof(*newpkgsfps)); for (i = 0; i < newpkgs; i++) { const char *loc; Solvable *s; struct repoinfo *cinfo; p = checkq.elements[i]; s = pool_id2solvable(pool, p); if (s->repo == commandlinerepo) { loc = solvable_lookup_location(s, 0); if (!loc) continue; if (!(newpkgsfps[i] = fopen(loc, "r"))) { perror(loc); exit(1); } putchar('.'); continue; } cinfo = s->repo->appdata; if (!cinfo || cinfo->type == TYPE_INSTALLED) { printf("%s: no repository information\n", s->repo->name); exit(1); } loc = solvable_lookup_location(s, 0); if (!loc) continue; /* pseudo package? */ #if defined(ENABLE_RPMDB) if (pool->installed && pool->installed->nsolvables) { if ((newpkgsfps[i] = trydeltadownload(s, loc)) != 0) { putchar('d'); fflush(stdout); continue; /* delta worked! */ } } #endif if ((newpkgsfps[i] = downloadpackage(s, loc)) == 0) { printf("\n%s: %s not found in repository\n", s->repo->name, loc); exit(1); } putchar('.'); fflush(stdout); } putchar('\n'); } #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) /* check for file conflicts */ if (newpkgs) { Queue conflicts; queue_init(&conflicts); if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts)) { if (yesno("Re-run solver (y/n/q)? ", 0)) { for (i = 0; i < newpkgs; i++) if (newpkgsfps[i]) fclose(newpkgsfps[i]); newpkgsfps = solv_free(newpkgsfps); solver_free(solv); solv = 0; pool_add_fileconflicts_deps(pool, &conflicts); queue_free(&conflicts); goto rerunsolver; } } queue_free(&conflicts); } #endif /* and finally commit the transaction */ printf("Committing transaction:\n\n"); transaction_order(trans, 0); for (i = 0; i < trans->steps.count; i++) { int j; FILE *fp; Id type; p = trans->steps.elements[i]; type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY); switch(type) { case SOLVER_TRANSACTION_ERASE: printf("erase %s\n", pool_solvid2str(pool, p)); commit_transactionelement(pool, type, p, 0); break; case SOLVER_TRANSACTION_INSTALL: case SOLVER_TRANSACTION_MULTIINSTALL: printf("install %s\n", pool_solvid2str(pool, p)); for (j = 0; j < newpkgs; j++) if (checkq.elements[j] == p) break; fp = j < newpkgs ? newpkgsfps[j] : 0; if (!fp) continue; commit_transactionelement(pool, type, p, fp); fclose(fp); newpkgsfps[j] = 0; break; default: break; } } for (i = 0; i < newpkgs; i++) if (newpkgsfps[i]) fclose(newpkgsfps[i]); solv_free(newpkgsfps); queue_free(&checkq); transaction_free(trans); solver_free(solv); queue_free(&job); pool_free(pool); free_repoinfos(repoinfos, nrepoinfos); solv_free(commandlinepkgs); exit(0); }
int repo_add_autopattern(Repo *repo, int flags) { Pool *pool = repo->pool; Repodata *data = 0; Solvable *s, *s2; Queue patq, patq2; Queue prdq, prdq2; Id p; Id pattern_id, product_id; Id autopattern_id = 0, autoproduct_id = 0; int i, j; queue_init(&patq); queue_init(&patq2); queue_init(&prdq); queue_init(&prdq2); pattern_id = pool_str2id(pool, "pattern()", 9); product_id = pool_str2id(pool, "product()", 9); FOR_REPO_SOLVABLES(repo, p, s) { const char *n = pool_id2str(pool, s->name); if (*n == 'p') { if (!strncmp("pattern:", n, 8)) { queue_push(&patq, p); continue; } else if (!strncmp("product:", n, 8)) { queue_push(&prdq, p); continue; } } if (s->provides) { Id prv, *prvp = repo->idarraydata + s->provides; while ((prv = *prvp++) != 0) /* go through all provides */ if (ISRELDEP(prv)) { Reldep *rd = GETRELDEP(pool, prv); if (rd->flags != REL_EQ) continue; if (rd->name == pattern_id) { queue_push2(&patq2, p, rd->evr); break; } if (rd->name == product_id) { queue_push2(&prdq2, p, rd->evr); break; } } } } for (i = 0; i < patq2.count; i += 2) { const char *pn = 0; char *newname; Id name, prv, *prvp; const char *str; unsigned long long num; s = pool->solvables + patq2.elements[i]; /* construct new name */ newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, patq2.elements[i + 1]), 0); unescape(newname); name = pool_str2id(pool, newname, 0); if (name) { /* check if we already have that pattern */ for (j = 0; j < patq.count; j++) { s2 = pool->solvables + patq.elements[j]; if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr) break; } if (j < patq.count) continue; /* yes, do not add again */ } /* new pattern */ if (!name) name = pool_str2id(pool, newname, 1); if (!data) { repo_internalize(repo); /* to make that the lookups work */ data = repo_add_repodata(repo, flags); } s2 = pool_id2solvable(pool, repo_add_solvable(repo)); s = pool->solvables + patq2.elements[i]; /* re-calc pointer */ s2->name = name; s2->arch = s->arch; s2->evr = s->evr; s2->vendor = s->vendor; /* add link requires */ s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0); /* add autopattern provides */ if (!autopattern_id) autopattern_id = pool_str2id(pool, "autopattern()", 1); s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0); /* add self provides */ s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0); if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0) repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num); if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0) repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num); if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str); if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str); /* fill in stuff from provides */ prvp = repo->idarraydata + s->provides; while ((prv = *prvp++) != 0) /* go through all provides */ { Id evr = 0; if (ISRELDEP(prv)) { Reldep *rd = GETRELDEP(pool, prv); if (rd->flags != REL_EQ) continue; prv = rd->name; evr = rd->evr; } pn = pool_id2str(pool, prv); if (strncmp("pattern-", pn, 8) != 0) continue; newname = 0; if (evr) { newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0); unescape(newname); } if (!strncmp(pn, "pattern-category(", 17) && evr) { char lang[9]; int l = strlen(pn); Id langtag; if (l > 17 + 9 || pn[l - 1] != ')') continue; strncpy(lang, pn + 17, l - 17 - 1); lang[l - 17 - 1] = 0; langtag = SOLVABLE_CATEGORY; if (*lang && strcmp(lang, "en") != 0) langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1); if (newname[solv_validutf8(newname)] == 0) repodata_set_str(data, s2 - pool->solvables, langtag, newname); else { char *ustr = solv_latin1toutf8(newname); repodata_set_str(data, s2 - pool->solvables, langtag, ustr); solv_free(ustr); } } else if (!strcmp(pn, "pattern-includes()") && evr) repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0)); else if (!strcmp(pn, "pattern-extends()") && evr) repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0)); else if (!strcmp(pn, "pattern-icon()") && evr) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname); else if (!strcmp(pn, "pattern-order()") && evr) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname); else if (!strcmp(pn, "pattern-visible()") && !evr) repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE); } } queue_free(&patq); queue_free(&patq2); if (repo == pool->installed) queue_empty(&prdq2); /* no auto products for installed repos */ for (i = 0; i < prdq2.count; i += 2) { const char *pn = 0; char *newname; Id name, evr = 0, prv, *prvp; const char *str; unsigned long long num; s = pool->solvables + prdq2.elements[i]; /* construct new name */ newname = pool_tmpjoin(pool, "product(", pool_id2str(pool, prdq2.elements[i + 1]), ")"); unescape(newname); name = pool_str2id(pool, newname, 0); if (!name) continue; /* must have it in provides! */ prvp = repo->idarraydata + s->provides; while ((prv = *prvp++) != 0) /* go through all provides */ { if (ISRELDEP(prv)) { Reldep *rd = GETRELDEP(pool, prv); if (rd->name == name && rd->flags == REL_EQ) { evr = rd->evr; break; } } } if (!prv) continue; /* not found in provides */ newname = pool_tmpjoin(pool, "product:", pool_id2str(pool, prdq2.elements[i + 1]), 0); unescape(newname); name = pool_str2id(pool, newname, 0); if (name) { /* check if we already have that product */ for (j = 0; j < prdq.count; j++) { s2 = pool->solvables + prdq.elements[j]; if (s2->name == name && s2->arch == s->arch && s2->evr == evr) break; } if (j < prdq.count) continue; /* yes, do not add again */ } /* new product */ if (!name) name = pool_str2id(pool, newname, 1); if (!data) { repo_internalize(repo); /* to make that the lookups work */ data = repo_add_repodata(repo, flags); } if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0) continue; /* eek, not for installed packages, please! */ s2 = pool_id2solvable(pool, repo_add_solvable(repo)); s = pool->solvables + prdq2.elements[i]; /* re-calc pointer */ s2->name = name; s2->arch = s->arch; s2->evr = evr; s2->vendor = s->vendor; /* add link requires */ s2->requires = repo_addid_dep(repo, s2->requires, prv, 0); if (!autoproduct_id) autoproduct_id = pool_str2id(pool, "autoproduct()", 1); s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autoproduct_id, s->name, REL_EQ, 1), 0); /* add self provides */ s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0); if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0) repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num); if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str); if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str); if ((str = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION)) != 0) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DISTRIBUTION, str); /* fill in stuff from provides */ prvp = repo->idarraydata + s->provides; while ((prv = *prvp++) != 0) /* go through all provides */ { Id evr = 0; if (ISRELDEP(prv)) { Reldep *rd = GETRELDEP(pool, prv); if (rd->flags != REL_EQ) continue; prv = rd->name; evr = rd->evr; } pn = pool_id2str(pool, prv); if (strncmp("product-", pn, 8) != 0) continue; newname = 0; if (evr) { newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0); unescape(newname); } if (!strcmp(pn, "product-label()") && evr) repodata_set_str(data, s2 - pool->solvables, PRODUCT_SHORTLABEL, newname); else if (!strcmp(pn, "product-type()") && evr) repodata_set_str(data, s2 - pool->solvables, PRODUCT_TYPE, newname); else if (!strcmp(pn, "product-cpeid()") && evr) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_CPEID, newname); else if (!strcmp(pn, "product-flags()") && evr) repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_FLAGS, newname); else if (!strcmp(pn, "product-updates-repoid()") && evr) repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_UPDATES_REPOID, newname); else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32) { char type[34]; strcpy(type, pn + 12); type[strlen(type) - 1] = 0; /* closing ) */ repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL_TYPE, type); repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL, newname); } } } queue_free(&prdq); queue_free(&prdq2); if (data && !(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); else if (!data && !(flags & REPO_NO_INTERNALIZE)) repo_internalize(repo); return 0; }
/* * returns: * 0: no blocks * 1: matches all * -1: at least one block */ static int normalize_dep(Pool *pool, Id dep, Queue *bq, int flags) { int bqcnt = bq->count; int bqcnt2; int todnf = flags & CPLXDEPS_TODNF ? 1 : 0; Id p, dp; #ifdef CPLXDEBUG printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf); #endif if (pool_is_complex_dep(pool, dep)) { Reldep *rd = GETRELDEP(pool, dep); if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND) { int rdflags = rd->flags; Id name = rd->name; Id evr = rd->evr; int r, mode; if (rdflags == REL_COND) { /* check for relly complex ELSE case */ if (ISRELDEP(evr)) { Reldep *rd2 = GETRELDEP(pool, evr); if (rd2->flags == REL_ELSE) { int r2; /* really complex case */ if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_1) { /* A OR ~B */ rdflags = REL_COND; evr = rd2->name; } else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_2) { /* C OR B */ rdflags = REL_OR; name = rd2->evr; evr = rd2->name; } else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_1) { /* A AND B */ rdflags = REL_AND; evr = rd2->name; } else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_2) { /* A AND C */ rdflags = REL_AND; evr = rd2->evr; } else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_3) { /* C AND ~B */ rdflags = REL_ELSE; name = rd2->evr; evr = rd2->name; } else if (!todnf) { /* we want AND: A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */ r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_1); if (r == 0 && (flags & CPLXDEPS_DONTFIX) == 0) return 0; r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_2); if (r2 == 0 && (flags & CPLXDEPS_DONTFIX) == 0) { queue_truncate(bq, bqcnt); return 0; } if (r == -1 || r2 == -1) return -1; return r == 1 || r2 == 1 ? 1 : 0; } else { int r2, r3; /* we want OR: A IF (B ELSE C) -> (A AND B) OR (A AND C) OR (~B AND C) */ r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_1); if (r == 1) return 1; r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_2); if (r2 == 1) { queue_truncate(bq, bqcnt); return 1; } r3 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_3); if (r3 == 1) { queue_truncate(bq, bqcnt); return 1; } if (r == -1 || r2 == -1 || r3 == -1) return -1; return 0; } } } } mode = rdflags == REL_AND || rdflags == REL_ELSE ? 0 : 1; /* get blocks of first argument */ r = normalize_dep(pool, name, bq, flags); if (r == 0) { if (rdflags == REL_ELSE) return 0; if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0) return 0; if (rdflags == REL_COND) { r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX); return invert_depblocks(pool, bq, bqcnt, r); /* invert block for COND */ } return normalize_dep(pool, evr, bq, flags); } if (r == 1) { if (rdflags == REL_ELSE) { r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX); return invert_depblocks(pool, bq, bqcnt, r); /* invert block for ELSE */ } if (rdflags == REL_OR || rdflags == REL_COND) return 1; return normalize_dep(pool, evr, bq, flags); } /* get blocks of second argument */ bqcnt2 = bq->count; /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */ r = normalize_dep(pool, evr, bq, rdflags == REL_COND || rdflags == REL_ELSE ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags); if (rdflags == REL_COND || rdflags == REL_ELSE) r = invert_depblocks(pool, bq, bqcnt2, r); /* invert 2nd block */ if (r == 0) { if (rdflags == REL_OR) return -1; if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0) return -1; queue_truncate(bq, bqcnt); return 0; } if (r == 1) { if (rdflags == REL_COND || rdflags == REL_OR) { queue_truncate(bq, bqcnt); return 1; } return -1; } if (mode == todnf) { /* simple case: just join em. nothing more to do here. */ #ifdef CPLXDEBUG printf("SIMPLE JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count); #endif return -1; } else { /* complex case: mix em */ int i, j, bqcnt3; #ifdef CPLXDEBUG printf("COMPLEX JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count); #endif bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2); bqcnt3 = bq->count; for (i = bqcnt; i < bqcnt2; i++) { for (j = bqcnt2; j < bqcnt3; j++) { int a, b; int bqcnt4 = bq->count; int k = i; /* mix i block with j block, both blocks are sorted */ while (bq->elements[k] && bq->elements[j]) { if (bq->elements[k] < bq->elements[j]) queue_push(bq, bq->elements[k++]); else { if (bq->elements[k] == bq->elements[j]) k++; queue_push(bq, bq->elements[j++]); } } while (bq->elements[j]) queue_push(bq, bq->elements[j++]); while (bq->elements[k]) queue_push(bq, bq->elements[k++]); /* block is finished, check for A + -A */ for (a = bqcnt4, b = bq->count - 1; a < b; ) { if (-bq->elements[a] == bq->elements[b]) break; if (-bq->elements[a] > bq->elements[b]) a++; else b--; } if (a < b) queue_truncate(bq, bqcnt4); /* ignore this block */ else queue_push(bq, 0); /* finish block */ } /* advance to next block */ while (bq->elements[i]) i++; } i = -1; if (bqcnt3 == bq->count) /* ignored all blocks? */ i = todnf ? 0 : 1; queue_deleten(bq, bqcnt, bqcnt3 - bqcnt); return i; } } } /* fallback case: just use package list */ dp = pool_whatprovides(pool, dep); if (dp <= 2 || !pool->whatprovidesdata[dp]) return dp == 2 ? 1 : 0; if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE) return 1; bqcnt = bq->count; if ((flags & CPLXDEPS_NAME) != 0) { while ((p = pool->whatprovidesdata[dp++]) != 0) { if (!pool_match_nevr(pool, pool->solvables + p, dep)) continue; queue_push(bq, p); if (todnf) queue_push(bq, 0); } } else if (todnf) { while ((p = pool->whatprovidesdata[dp++]) != 0) queue_push2(bq, p, 0); } else queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker + offset */ if (bq->count == bqcnt) return 0; /* no provider */ if (!todnf) queue_push(bq, 0); /* finish block */ return -1; }