2 * Copyright (c) 2009, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
8 /* solv, a little software installer demoing the sat solver library */
11 * - vendor policy loading
23 #include <sys/utsname.h>
24 #include <sys/types.h>
32 #include "solverdebug.h"
34 #include "repo_solv.h"
36 #include "repo_write.h"
37 #include "repo_rpmdb.h"
38 #include "repo_products.h"
39 #include "repo_rpmmd.h"
40 #include "repo_susetags.h"
41 #include "repo_repomdxml.h"
42 #include "repo_content.h"
43 #include "pool_fileconflicts.h"
47 # define REPOINFO_PATH "/etc/yum.repos.d"
49 # define REPOINFO_PATH "/etc/zypp/repos.d"
50 # define PRODUCTS_PATH "/etc/products.d"
53 #define SOLVCACHE_PATH "/var/cache/solv"
71 #define TYPE_UNKNOWN 0
72 #define TYPE_SUSETAGS 1
74 #define TYPE_PLAINDIR 3
77 read_repoinfos_sort(const void *ap, const void *bp)
79 const struct repoinfo *a = ap;
80 const struct repoinfo *b = bp;
81 return strcmp(a->alias, b->alias);
85 read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
88 char buf2[4096], *kp, *vp, *kpe;
93 struct repoinfo *repoinfos = 0, *cinfo;
96 rdlen = strlen(reposdir);
97 dir = opendir(reposdir);
103 while ((ent = readdir(dir)) != 0)
105 l = strlen(ent->d_name);
106 if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0)
108 snprintf(buf, sizeof(buf), "%s/%s", reposdir, ent->d_name);
109 if ((fp = fopen(buf, "r")) == 0)
115 while(fgets(buf2, sizeof(buf2), fp))
120 while (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t')
123 while (*kp == ' ' || *kp == '\t')
125 if (!*kp || *kp == '#')
131 vp = strrchr(kp, ']');
135 repoinfos = sat_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
136 cinfo = repoinfos + nrepoinfos++;
137 memset(cinfo, 0, sizeof(*cinfo));
138 cinfo->alias = strdup(kp + 1);
140 cinfo->type = TYPE_RPMMD;
143 vp = strchr(kp, '=');
146 for (kpe = vp - 1; kpe >= kp; kpe--)
147 if (*kpe != ' ' && *kpe != '\t')
152 while (*vp == ' ' || *vp == '\t')
155 if (!strcmp(kp, "name"))
156 cinfo->name = strdup(vp);
157 else if (!strcmp(kp, "enabled"))
158 cinfo->enabled = *vp == '0' ? 0 : 1;
159 else if (!strcmp(kp, "autorefresh"))
160 cinfo->autorefresh = *vp == '0' ? 0 : 1;
161 else if (!strcmp(kp, "gpgcheck"))
162 cinfo->gpgcheck = *vp == '0' ? 0 : 1;
163 else if (!strcmp(kp, "baseurl"))
164 cinfo->baseurl = strdup(vp);
165 else if (!strcmp(kp, "path"))
167 if (vp && strcmp(vp, "/") != 0)
168 cinfo->path = strdup(vp);
170 else if (!strcmp(kp, "type"))
172 if (!strcmp(vp, "yast2"))
173 cinfo->type = TYPE_SUSETAGS;
174 else if (!strcmp(vp, "rpm-md"))
175 cinfo->type = TYPE_RPMMD;
176 else if (!strcmp(vp, "plaindir"))
177 cinfo->type = TYPE_PLAINDIR;
179 cinfo->type = TYPE_UNKNOWN;
181 else if (!strcmp(kp, "priority"))
182 cinfo->priority = atoi(vp);
183 else if (!strcmp(kp, "keeppackages"))
184 cinfo->keeppackages = *vp == '0' ? 0 : 1;
190 qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), read_repoinfos_sort);
191 *nrepoinfosp = nrepoinfos;
196 cookie_gzread(void *cookie, char *buf, size_t nbytes)
198 return gzread((gzFile *)cookie, buf, nbytes);
202 cookie_gzclose(void *cookie)
204 return gzclose((gzFile *)cookie);
208 curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype)
215 const char *baseurl = cinfo->baseurl;
218 if (l && baseurl[l - 1] == '/')
219 snprintf(url, sizeof(url), "%s%s", baseurl, file);
221 snprintf(url, sizeof(url), "%s/%s", baseurl, file);
222 strcpy(tmpl, "/var/tmp/solvXXXXXX");
230 if ((pid = fork()) == (pid_t)-1)
242 execlp("curl", "curl", "-s", "-L", url, (char *)0);
246 while (waitpid(pid, &status, 0) != pid)
248 if (lseek(fd, 0, SEEK_END) == 0)
254 lseek(fd, 0, SEEK_SET);
259 void *h = sat_chksum_create(chksumtype);
264 printf("%s: unknown checksum type\n", file);
268 while ((l = read(fd, buf, sizeof(buf))) > 0)
269 sat_chksum_add(h, buf, l);
270 lseek(fd, 0, SEEK_SET);
272 sum = sat_chksum_get(h, &l);
273 if (memcmp(sum, chksum, l))
275 printf("%s: checksum mismatch\n", file);
282 cookie_io_functions_t cio;
285 sprintf(tmpl, "/dev/fd/%d", fd);
286 gzf = gzopen(tmpl, "r");
290 memset(&cio, 0, sizeof(cio));
291 cio.read = cookie_gzread;
292 cio.close = cookie_gzclose;
293 return fopencookie(gzf, "r", cio);
295 fcntl(fd, F_SETFD, FD_CLOEXEC);
296 return fdopen(fd, "r");
300 calc_checksum_fp(FILE *fp, Id chktype, unsigned char *out)
303 void *h = sat_chksum_create(chktype);
306 while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
307 sat_chksum_add(h, buf, l);
309 sat_chksum_free(h, out);
313 cleanupgpg(char *gpgdir)
316 snprintf(cmd, sizeof(cmd), "%s/pubring.gpg", gpgdir);
318 snprintf(cmd, sizeof(cmd), "%s/pubring.gpg~", gpgdir);
320 snprintf(cmd, sizeof(cmd), "%s/secring.gpg", gpgdir);
322 snprintf(cmd, sizeof(cmd), "%s/trustdb.gpg", gpgdir);
324 snprintf(cmd, sizeof(cmd), "%s/keys", gpgdir);
330 checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
339 off_t posfp, possigfp;
342 gpgdir = mkdtemp(pool_tmpjoin(sigpool, "/var/tmp/solvgpg.XXXXXX", 0, 0));
345 keysfile = pool_tmpjoin(sigpool, gpgdir, "/keys", 0);
346 if (!(kfp = fopen(keysfile, "w")) )
351 for (p = 1, s = sigpool->solvables + p; p < sigpool->nsolvables; p++, s++)
355 pubkey = solvable_lookup_str(s, SOLVABLE_DESCRIPTION);
356 if (!pubkey || !*pubkey)
358 if (fwrite(pubkey, strlen(pubkey), 1, kfp) != 1)
360 if (fputc('\n', kfp) == EOF) /* Just in case... */
368 snprintf(cmd, sizeof(cmd), "gpg -q --homedir %s --import %s", gpgdir, keysfile);
371 fprintf(stderr, "key import error\n");
376 posfp = lseek(fileno(fp), 0, SEEK_CUR);
377 lseek(fileno(fp), 0, SEEK_SET);
378 possigfp = lseek(fileno(sigfp), 0, SEEK_CUR);
379 lseek(fileno(sigfp), 0, SEEK_SET);
380 snprintf(cmd, sizeof(cmd), "gpg -q --homedir %s --verify /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, fileno(sigfp), fileno(fp));
381 fcntl(fileno(fp), F_SETFD, 0); /* clear CLOEXEC */
382 fcntl(fileno(sigfp), F_SETFD, 0); /* clear CLOEXEC */
384 lseek(fileno(sigfp), possigfp, SEEK_SET);
385 lseek(fileno(fp), posfp, SEEK_SET);
386 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
387 fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
389 return r == 0 ? 1 : 0;
393 calc_checksum_stat(struct stat *stb, Id chktype, unsigned char *out)
395 void *h = sat_chksum_create(chktype);
396 sat_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev));
397 sat_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino));
398 sat_chksum_add(h, &stb->st_size, sizeof(stb->st_size));
399 sat_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime));
400 sat_chksum_free(h, out);
412 pool_setarch(pool, un.machine);
415 char *calccachepath(Repo *repo)
417 char *q, *p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", repo->name);
418 p = pool_tmpjoin(repo->pool, p, ".solv", 0);
419 q = p + strlen(SOLVCACHE_PATH) + 1;
429 usecachedrepo(Repo *repo, unsigned char *cookie)
432 unsigned char mycookie[32];
434 if (!(fp = fopen(calccachepath(repo), "r")))
436 if (fseek(fp, -sizeof(mycookie), SEEK_END) || fread(mycookie, sizeof(mycookie), 1, fp) != 1)
441 if (cookie && memcmp(cookie, mycookie, sizeof(mycookie)))
447 if (repo_add_solv(repo, fp))
457 writecachedrepo(Repo *repo, unsigned char *cookie)
459 Id *addedfileprovides = 0;
465 mkdir(SOLVCACHE_PATH, 0755);
466 tmpl = sat_dupjoin(SOLVCACHE_PATH, "/", ".newsolv-XXXXXX");
474 if (!(fp = fdopen(fd, "w")))
481 info = repo_add_repodata(repo, 0);
482 pool_addfileprovides_ids(repo->pool, 0, &addedfileprovides);
483 if (addedfileprovides && *addedfileprovides)
485 for (i = 0; addedfileprovides[i]; i++)
486 repodata_add_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[i]);
488 sat_free(addedfileprovides);
489 repodata_internalize(info);
490 repo_write(repo, fp, 0, 0, 0);
492 if (fwrite(cookie, 32, 1, fp) != 1)
505 if (!rename(tmpl, calccachepath(repo)))
513 Pool *sigpool = pool_create();
514 Repo *repo = repo_create(sigpool, "rpmdbkeys");
515 repo_add_rpmdb_pubkeys(repo, 0, 0);
520 read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
523 struct repoinfo *cinfo;
527 const char *primaryfile;
528 const unsigned char *primaryfilechksum;
529 Id primaryfilechksumtype;
530 const char *descrdir;
533 unsigned char cookie[32];
536 repo = repo_create(pool, "@System");
537 printf("rpm database:");
538 if (stat("/var/lib/rpm/Packages", &stb))
539 memset(&stb, 0, sizeof(&stb));
540 calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cookie);
541 if (usecachedrepo(repo, cookie))
546 printf(" reading\n");
550 repo_add_products(repo, PRODUCTS_PATH, 0, REPO_NO_INTERNALIZE);
552 if ((ofp = fopen(calccachepath(repo), "r")) != 0)
554 Repo *ref = repo_create(pool, "@System.old");
555 if (!repo_add_solv(ref, ofp))
557 repo_add_rpmdb(repo, ref, 0, REPO_REUSE_REPODATA);
564 repo_add_rpmdb(repo, 0, 0, REPO_REUSE_REPODATA);
565 writecachedrepo(repo, cookie);
567 pool_set_installed(pool, repo);
569 for (i = 0; i < nrepoinfos; i++)
571 cinfo = repoinfos + i;
575 repo = repo_create(pool, cinfo->alias);
577 repo->appdata = cinfo;
578 repo->priority = 99 - cinfo->priority;
580 if (!cinfo->autorefresh && usecachedrepo(repo, 0))
582 printf("repo '%s':", cinfo->alias);
589 printf("rpmmd repo '%s':", cinfo->alias);
591 if ((fp = curlfopen(cinfo, "repodata/repomd.xml", 0, 0, 0)) == 0)
593 printf(" no repomd.xml file, skipped\n");
598 calc_checksum_fp(fp, REPOKEY_TYPE_SHA256, cookie);
599 if (usecachedrepo(repo, cookie))
608 if ((sigfp = curlfopen(cinfo, "repodata/repomd.xml.asc", 0, 0, 0)) == 0)
610 printf(" unsigned, skipped\n");
615 sigpool = read_sigs();
616 if (!checksig(sigpool, fp, sigfp))
618 printf(" checksig failed, skipped\n");
625 repo_add_repomdxml(repo, fp, 0);
628 primaryfilechksum = 0;
629 primaryfilechksumtype = 0;
630 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, "primary", SEARCH_STRING);
631 dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
632 if (dataiterator_step(&di))
634 dataiterator_setpos_parent(&di);
635 primaryfile = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
636 primaryfilechksum = pool_lookup_bin_checksum(pool, SOLVID_POS, REPOSITORY_REPOMD_CHECKSUM, &primaryfilechksumtype);
638 dataiterator_free(&di);
641 printf(" no primary file entry, skipped\n");
644 if (!primaryfilechksumtype)
646 printf(" no primary file checksum, skipped\n");
649 printf(" reading\n");
650 if ((fp = curlfopen(cinfo, primaryfile, 1, primaryfilechksum, primaryfilechksumtype)) == 0)
652 repo_add_rpmmd(repo, fp, 0, 0);
654 writecachedrepo(repo, cookie);
657 printf("susetags repo '%s':", cinfo->alias);
659 repo = repo_create(pool, cinfo->alias);
661 repo->appdata = cinfo;
662 repo->priority = 99 - cinfo->priority;
665 if ((fp = curlfopen(cinfo, "content", 0, 0, 0)) == 0)
667 printf(" no content file, skipped\n");
672 calc_checksum_fp(fp, REPOKEY_TYPE_SHA256, cookie);
673 if (usecachedrepo(repo, cookie))
682 if ((sigfp = curlfopen(cinfo, "content.asc", 0, 0, 0)) == 0)
684 printf(" unsigned, skipped\n");
689 sigpool = read_sigs();
690 if (!checksig(sigpool, fp, sigfp))
692 printf(" checksig failed, skipped\n");
698 repo_add_content(repo, fp, 0);
700 defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
701 descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
703 descrdir = "suse/setup/descr";
705 dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, "packages.gz", SEARCH_STRING);
706 dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
707 if (dataiterator_step(&di))
709 dataiterator_setpos_parent(&di);
710 primaryfilechksum = pool_lookup_bin_checksum(pool, SOLVID_POS, SUSETAGS_FILE_CHECKSUM, &primaryfilechksumtype);
711 primaryfile = "packages.gz";
713 dataiterator_free(&di);
716 dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, "packages", SEARCH_STRING);
717 dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
718 if (dataiterator_step(&di))
720 dataiterator_setpos_parent(&di);
721 primaryfilechksum = pool_lookup_bin_checksum(pool, SOLVID_POS, SUSETAGS_FILE_CHECKSUM, &primaryfilechksumtype);
722 primaryfile = "packages";
724 dataiterator_free(&di);
728 printf(" no packages file entry, skipped\n");
731 if (!primaryfilechksumtype)
733 printf(" no packages file checksum, skipped\n");
736 printf(" reading\n");
737 if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", primaryfile), !strcmp(primaryfile, "packages.gz") ? 1 : 0, primaryfilechksum, primaryfilechksumtype)) == 0)
739 repo_add_susetags(repo, fp, defvendor, 0, 0);
741 writecachedrepo(repo, cookie);
744 printf("unsupported repo '%s': skipped\n", cinfo->alias);
755 mkselect(Pool *pool, const char *arg, int flags, Queue *out)
761 id = str2id(pool, arg, 0);
764 FOR_PROVIDES(p, pp, id)
766 Solvable *s = pool_id2solvable(pool, p);
769 type = SOLVER_SOLVABLE_NAME;
772 type = SOLVER_SOLVABLE_PROVIDES;
777 /* did not find a solvable, see if it's a relation */
778 if ((r = strpbrk(arg, "<=>")) != 0)
782 for (r2 = r; r2 > arg && (r2[-1] == ' ' || r2[-1] == '\t'); )
784 rname = r2 > arg ? strn2id(pool, arg, r2 - arg, 1) : 0;
796 while (*r == ' ' || *r == '\t')
798 revr = *r ? str2id(pool, r, 1) : 0;
799 rid = rname && revr ? rel2id(pool, rname, revr, rflags, 1) : 0;
802 FOR_PROVIDES(p, pp, rid)
804 Solvable *s = pool_id2solvable(pool, p);
805 if (pool_match_nevr(pool, s, rid))
807 type = SOLVER_SOLVABLE_NAME;
810 type = SOLVER_SOLVABLE_PROVIDES;
819 queue_push(out, type);
825 yesno(const char *str)
827 char inbuf[128], *ip;
834 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
839 while (*ip == ' ' || *ip == '\t')
846 if (*ip == 'y' || *ip == 'n')
847 return *ip == 'y' ? 1 : 0;
859 fc_cb(Pool *pool, Id p, void *cbdata)
861 struct fcstate *fcstate = cbdata;
869 rpm_byrpmdbid(0, 0, &fcstate->rpmdbstate);
872 s = pool_id2solvable(pool, p);
873 if (pool->installed && s->repo == pool->installed)
875 if (!s->repo->rpmdbid)
877 rpmdbid = s->repo->rpmdbid[p - s->repo->start];
880 return rpm_byrpmdbid(rpmdbid, 0, &fcstate->rpmdbstate);
882 for (i = 0; i < fcstate->newpkgscnt; i++)
883 if (fcstate->checkq->elements[i] == p)
885 if (i == fcstate->newpkgscnt)
887 fp = fcstate->newpkgsfps[i];
891 return rpm_byfp(fp, solvable2str(pool, s), &fcstate->rpmdbstate);
895 runrpm(const char *arg, const char *name, int dupfd3)
900 if ((pid = fork()) == (pid_t)-1)
907 if (dupfd3 != -1 && dupfd3 != 3)
913 fcntl(3, F_SETFD, 0); /* clear CLOEXEC */
914 if (strcmp(arg, "-e") == 0)
915 execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", name, (char *)0);
917 execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", name, (char *)0);
921 while (waitpid(pid, &status, 0) != pid)
925 printf("rpm failed\n");
931 nscallback(Pool *pool, void *data, Id name, Id evr)
933 if (name == NAMESPACE_PRODUCTBUDDY)
935 /* SUSE specific hack: each product has an associated rpm */
936 Solvable *s = pool->solvables + evr;
939 cap = str2id(pool, pool_tmpjoin(pool, "product(", id2str(pool, s->name) + 8, ")"), 0);
942 cap = rel2id(pool, cap, s->evr, REL_EQ, 0);
945 FOR_PROVIDES(p, pp, cap)
947 Solvable *ps = pool->solvables + p;
948 if (ps->repo == s->repo && ps->arch == s->arch)
958 main(int argc, char **argv)
962 struct repoinfo *repoinfos;
964 int i, mode, newpkgs;
968 char inbuf[128], *ip;
972 struct fcstate fcstate;
978 fprintf(stderr, "Usage: solv install|erase|update|show <select>\n");
981 if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in"))
982 mode = SOLVER_INSTALL;
983 else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm"))
985 else if (!strcmp(argv[0], "show"))
987 else if (!strcmp(argv[0], "update") || !strcmp(argv[0], "up"))
988 mode = SOLVER_UPDATE;
989 else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup"))
991 mode = SOLVER_UPDATE;
996 fprintf(stderr, "Usage: solv install|erase|update|show <select>\n");
1000 pool = pool_create();
1001 pool->nscallback = nscallback;
1002 // pool_setdebuglevel(pool, 2);
1004 repoinfos = read_repoinfos(pool, REPOINFO_PATH, &nrepoinfos);
1005 read_repos(pool, repoinfos, nrepoinfos);
1006 // FOR_REPOS(i, repo)
1007 // printf("%s: %d solvables\n", repo->name, repo->nsolvables);
1008 pool_addfileprovides(pool);
1009 pool_createwhatprovides(pool);
1012 for (i = 1; i < argc; i++)
1013 mkselect(pool, argv[i], 0, &job);
1014 if (!job.count && mode == SOLVER_UPDATE)
1016 else if (!job.count)
1018 printf("no package matched\n");
1024 /* show mode, no solver needed */
1025 for (i = 0; i < job.count; i += 2)
1027 FOR_JOB_SELECT(p, pp, job.elements[i], job.elements[i + 1])
1029 Solvable *s = pool_id2solvable(pool, p);
1030 printf(" - %s [%s]\n", solvable2str(pool, s), s->repo->name);
1037 for (i = 0; i < job.count; i += 2)
1038 job.elements[i] |= mode;
1040 // multiversion test
1041 // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, str2id(pool, "kernel-pae", 1));
1042 // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, str2id(pool, "kernel-pae-base", 1));
1043 // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, str2id(pool, "kernel-pae-extra", 1));
1048 Id problem, solution;
1051 solv = solver_create(pool);
1052 solv->ignorealreadyrecommended = 1;
1053 solv->updatesystem = updateall;
1054 solv->dosplitprovides = updateall;
1055 if (updateall && distupgrade)
1057 solv->distupgrade = 1;
1058 solv->allowdowngrade = 1;
1059 solv->allowarchchange = 1;
1060 solv->allowvendorchange = 1;
1062 // queue_push2(&job, SOLVER_DISTUPGRADE, 3);
1063 solver_solve(solv, &job);
1064 if (!solv->problems.count)
1066 pcnt = solver_problem_count(solv);
1067 printf("Found %d problems:\n", pcnt);
1068 for (problem = 1; problem <= pcnt; problem++)
1071 printf("Problem %d:\n", problem);
1072 solver_printprobleminfo(solv, problem);
1074 scnt = solver_solution_count(solv, problem);
1075 for (solution = 1; solution <= scnt; solution++)
1077 printf("Solution %d:\n", solution);
1078 solver_printsolution(solv, problem, solution);
1083 printf("Please choose a solution: ");
1086 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
1091 while (*ip == ' ' || *ip == '\t')
1093 if (*ip >= '0' && *ip <= '9')
1096 if (take >= 1 && take <= scnt)
1112 solver_take_solution(solv, problem, take, &job);
1117 if (!solv->trans.steps.count)
1119 printf("Nothing to do.\n");
1123 printf("Transaction summary:\n\n");
1124 solver_printtransaction(solv);
1125 if (!yesno("OK to continue (y/n)? "))
1131 trans = &solv->trans;
1132 queue_init(&checkq);
1133 newpkgs = transaction_installedresult(trans, &checkq);
1138 printf("Downloading %d packages\n", newpkgs);
1139 newpkgsfps = sat_calloc(newpkgs, sizeof(*newpkgsfps));
1140 for (i = 0; i < newpkgs; i++)
1142 unsigned int medianr;
1145 struct repoinfo *cinfo;
1146 const unsigned char *chksum;
1149 p = checkq.elements[i];
1150 s = pool_id2solvable(pool, p);
1151 cinfo = s->repo->appdata;
1154 printf("%s: no repository information\n", s->repo->name);
1157 loc = solvable_get_location(s, &medianr);
1160 if (cinfo->type == TYPE_SUSETAGS)
1162 const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR);
1163 loc = pool_tmpjoin(pool, datadir ? datadir : "suse", "/", loc);
1166 chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
1167 if ((newpkgsfps[i] = curlfopen(cinfo, loc, 0, chksum, chksumtype)) == 0)
1169 printf("%s: %s not found in repository\n", s->repo->name, loc);
1179 printf("Searching for file conflicts\n");
1180 queue_init(&conflicts);
1181 fcstate.rpmdbstate = 0;
1182 fcstate.newpkgscnt = newpkgs;
1183 fcstate.checkq = &checkq;
1184 fcstate.newpkgsfps = newpkgsfps;
1185 pool_findfileconflicts(pool, &checkq, newpkgs, &conflicts, &fc_cb, &fcstate);
1186 if (conflicts.count)
1189 for (i = 0; i < conflicts.count; i += 5)
1190 printf("file %s of package %s conflicts with package %s\n", id2str(pool, conflicts.elements[i]), solvid2str(pool, conflicts.elements[i + 1]), solvid2str(pool, conflicts.elements[i + 3]));
1192 if (yesno("Re-run solver (y/n/q)? "))
1194 for (i = 0; i < newpkgs; i++)
1196 fclose(newpkgsfps[i]);
1197 newpkgsfps = sat_free(newpkgsfps);
1199 pool_add_fileconflicts_deps(pool, &conflicts);
1200 pool_createwhatprovides(pool); /* Hmm... */
1204 queue_free(&conflicts);
1207 printf("Committing transaction:\n\n");
1208 transaction_order(trans, 0);
1209 for (i = 0; i < trans->steps.count; i++)
1211 const char *evr, *evrp, *nvra;
1216 p = trans->steps.elements[i];
1217 s = pool_id2solvable(pool, p);
1218 Id type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY);
1221 case SOLVER_TRANSACTION_ERASE:
1222 printf("erase %s\n", solvid2str(pool, p));
1223 if (!s->repo->rpmdbid || !s->repo->rpmdbid[p - s->repo->start])
1225 /* strip epoch from evr */
1226 evr = evrp = id2str(pool, s->evr);
1227 while (*evrp >= '0' && *evrp <= '9')
1229 if (evrp > evr && evrp[0] == ':' && evrp[1])
1231 nvra = pool_tmpjoin(pool, id2str(pool, s->name), "-", evr);
1232 nvra = pool_tmpjoin(pool, nvra, ".", id2str(pool, s->arch));
1233 runrpm("-e", nvra, -1); /* to bad that --querybynumber doesn't work */
1235 case SOLVER_TRANSACTION_INSTALL:
1236 case SOLVER_TRANSACTION_MULTIINSTALL:
1237 printf("install %s\n", solvid2str(pool, p));
1238 for (j = 0; j < newpkgs; j++)
1239 if (checkq.elements[j] == p)
1241 fp = j < newpkgs ? newpkgsfps[j] : 0;
1245 lseek(fileno(fp), 0, SEEK_SET);
1246 runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp));
1255 for (i = 0; i < newpkgs; i++)
1257 fclose(newpkgsfps[i]);
1258 sat_free(newpkgsfps);
1259 queue_free(&checkq);