2 * Copyright (c) 2009-2015, SUSE LLC.
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 * - understands globs for package names / dependencies
12 * - understands .arch suffix
13 * - installation of commandline packages
14 * - repository data caching
15 * - on demand loading of secondary repository data
16 * - gpg and checksum verification
19 * - fastestmirror implementation
21 * things available in the library but missing from solv:
22 * - vendor policy loading
23 * - multi version handling
29 #include <sys/utsname.h>
34 #include "selection.h"
37 #include "solverdebug.h"
38 #include "transaction.h"
40 #include "repo_autopattern.h"
44 #include "repoinfo_cache.h"
45 #include "repoinfo_download.h"
47 #if defined(ENABLE_RPMDB)
48 #include "fileprovides.h"
49 #include "fileconflicts.h"
52 #if defined(SUSE) || defined(FEDORA)
53 #include "patchjobs.h"
65 pool_setarch(pool, un.machine);
70 yesno(const char *str)
79 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
84 while (*ip == ' ' || *ip == '\t')
91 if (*ip == 'y' || *ip == 'n')
92 return *ip == 'y' ? 1 : 0;
98 nscallback(Pool *pool, void *data, Id name, Id evr)
101 if (name == NAMESPACE_LANGUAGE)
103 if (!strcmp(pool_id2str(pool, evr), "ja"))
105 if (!strcmp(pool_id2str(pool, evr), "de"))
107 if (!strcmp(pool_id2str(pool, evr), "en"))
109 if (!strcmp(pool_id2str(pool, evr), "en_US"))
119 add_autopackages(Pool *pool)
124 repo_add_autopattern(repo, 0);
130 showdiskusagechanges(Transaction *trans)
135 /* XXX: use mountpoints here */
136 memset(duc, 0, sizeof(duc));
138 duc[1].path = "/usr/share/man";
139 duc[2].path = "/sbin";
140 duc[3].path = "/etc";
141 transaction_calc_duchanges(trans, duc, 4);
142 for (i = 0; i < 4; i++)
143 printf("duchanges %s: %d K %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files);
148 find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
153 for (rp = name; *rp; rp++)
154 if (*rp <= '0' || *rp >= '9')
158 /* repo specified by number */
159 int rnum = atoi(name);
160 for (i = 0; i < nrepoinfos; i++)
162 struct repoinfo *cinfo = repoinfos + i;
163 if (!cinfo->enabled || !cinfo->repo)
166 return cinfo->repo->repoid;
171 /* repo specified by alias */
175 if (!strcasecmp(name, repo->name))
184 #define MODE_INSTALL 1
186 #define MODE_UPDATE 3
187 #define MODE_DISTUPGRADE 4
188 #define MODE_VERIFY 5
191 #define MODE_REPOLIST 8
192 #define MODE_SEARCH 9
197 fprintf(stderr, "Usage: solv COMMAND <select>\n");
198 fprintf(stderr, "\n");
199 fprintf(stderr, " dist-upgrade: replace installed packages with\n");
200 fprintf(stderr, " versions from the repositories\n");
201 fprintf(stderr, " erase: erase installed packages\n");
202 fprintf(stderr, " info: display package information\n");
203 fprintf(stderr, " install: install packages\n");
204 fprintf(stderr, " list: list packages\n");
205 fprintf(stderr, " repos: list enabled repositories\n");
206 fprintf(stderr, " search: search name/summary/description\n");
207 fprintf(stderr, " update: update installed packages\n");
208 fprintf(stderr, " verify: check dependencies of installed packages\n");
209 #if defined(SUSE) || defined(FEDORA)
210 fprintf(stderr, " patch: install newest maintenance updates\n");
212 fprintf(stderr, "\n");
217 main(int argc, char **argv)
220 Repo *commandlinerepo = 0;
221 Id *commandlinepkgs = 0;
223 struct repoinfo *repoinfos, installedrepoinfo;
225 int mainmode = 0, mode = 0;
234 int archfilter_src = 0;
243 while (argc && !strcmp(argv[0], "-d"))
251 if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in"))
253 mainmode = MODE_INSTALL;
254 mode = SOLVER_INSTALL;
256 #if defined(SUSE) || defined(FEDORA)
257 else if (!strcmp(argv[0], "patch"))
259 mainmode = MODE_PATCH;
260 mode = SOLVER_INSTALL;
263 else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm"))
265 mainmode = MODE_ERASE;
268 else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "ls"))
270 mainmode = MODE_LIST;
273 else if (!strcmp(argv[0], "info"))
275 mainmode = MODE_INFO;
278 else if (!strcmp(argv[0], "search") || !strcmp(argv[0], "se"))
280 mainmode = MODE_SEARCH;
283 else if (!strcmp(argv[0], "verify"))
285 mainmode = MODE_VERIFY;
286 mode = SOLVER_VERIFY;
288 else if (!strcmp(argv[0], "update") || !strcmp(argv[0], "up"))
290 mainmode = MODE_UPDATE;
291 mode = SOLVER_UPDATE;
293 else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup"))
295 mainmode = MODE_DISTUPGRADE;
296 mode = SOLVER_DISTUPGRADE;
298 else if (!strcmp(argv[0], "repos") || !strcmp(argv[0], "repolist") || !strcmp(argv[0], "lr"))
300 mainmode = MODE_REPOLIST;
308 if (argc > 2 && !strcmp(argv[1], "--root"))
314 else if (argc > 1 && !strcmp(argv[1], "--clean"))
320 else if (argc > 1 && !strcmp(argv[1], "--best"))
326 if (argc > 2 && !strcmp(argv[1], "--keyname"))
337 pool = pool_create();
338 pool_set_rootdir(pool, rootdir);
342 const char *langs[] = {"de_DE", "de", "en"};
343 pool_set_languages(pool, langs, sizeof(langs)/sizeof(*langs));
347 pool_setloadcallback(pool, load_stub, 0);
349 pool->nscallback = nscallback;
352 pool_setdebuglevel(pool, debuglevel);
354 pool_set_flag(pool, POOL_FLAG_ADDFILEPROVIDESFILTERED, 1);
355 repoinfos = read_repoinfos(pool, &nrepoinfos);
356 sort_repoinfos(repoinfos, nrepoinfos);
358 if (mainmode == MODE_REPOLIST)
361 for (i = 0; i < nrepoinfos; i++)
363 struct repoinfo *cinfo = repoinfos + i;
366 printf("%d: %-20s %s (prio %d)\n", j++, cinfo->alias, cinfo->name, cinfo->priority);
370 memset(&installedrepoinfo, 0, sizeof(installedrepoinfo));
371 if (!read_installed_repo(&installedrepoinfo, pool))
373 read_repos(pool, repoinfos, nrepoinfos);
376 queue_init(&repofilter);
377 queue_init(&kindfilter);
378 queue_init(&archfilter);
381 if (!strcmp(argv[1], "-i"))
383 queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, pool->installed->repoid);
387 else if (argc > 2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "--repo")))
389 Id repoid = find_repo(argv[2], pool, repoinfos, nrepoinfos);
392 fprintf(stderr, "%s: no such repo\n", argv[2]);
395 /* SETVENDOR is actually wrong but useful */
396 queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO | SOLVER_SETVENDOR, repoid);
400 else if (argc > 2 && !strcmp(argv[1], "--arch"))
402 if (!strcmp(argv[2], "src") || !strcmp(argv[2], "nosrc"))
404 queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, argv[2], 1), REL_ARCH, 1));
408 else if (argc > 2 && (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--type")))
410 const char *kind = argv[2];
411 if (!strcmp(kind, "srcpackage"))
413 /* hey! should use --arch! */
414 queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, ARCH_SRC, REL_ARCH, 1));
420 if (!strcmp(kind, "package"))
422 if (!strcmp(kind, "all"))
423 queue_push2(&kindfilter, SOLVER_SOLVABLE_ALL, 0);
425 queue_push2(&kindfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, kind, 1), REL_KIND, 1));
433 if (mainmode == MODE_SEARCH)
439 pool_createwhatprovides(pool);
441 dataiterator_init(&di, pool, 0, 0, 0, argv[1], SEARCH_SUBSTRING|SEARCH_NOCASE);
442 dataiterator_set_keyname(&di, SOLVABLE_NAME);
443 dataiterator_set_search(&di, 0, 0);
444 while (dataiterator_step(&di))
445 queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
446 dataiterator_set_keyname(&di, SOLVABLE_SUMMARY);
447 dataiterator_set_search(&di, 0, 0);
448 while (dataiterator_step(&di))
449 queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
450 dataiterator_set_keyname(&di, SOLVABLE_DESCRIPTION);
451 dataiterator_set_search(&di, 0, 0);
452 while (dataiterator_step(&di))
453 queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
454 dataiterator_free(&di);
455 if (repofilter.count)
456 selection_filter(pool, &sel, &repofilter);
459 selection_solvables(pool, &sel, &q);
461 for (i = 0; i < q.count; i++)
463 Solvable *s = pool_id2solvable(pool, q.elements[i]);
464 printf(" - %s [%s]: %s\n", pool_solvable2str(pool, s), s->repo->name, solvable_lookup_str(s, SOLVABLE_SUMMARY));
470 /* process command line packages */
471 if (mainmode == MODE_LIST || mainmode == MODE_INFO || mainmode == MODE_INSTALL)
473 for (i = 1; i < argc; i++)
475 if (!is_cmdline_package((const char *)argv[i]))
477 if (access(argv[i], R_OK))
482 if (!commandlinepkgs)
483 commandlinepkgs = solv_calloc(argc, sizeof(Id));
484 if (!commandlinerepo)
485 commandlinerepo = repo_create(pool, "@commandline");
486 p = add_cmdline_package(commandlinerepo, (const char *)argv[i]);
489 fprintf(stderr, "could not add '%s'\n", argv[i]);
492 commandlinepkgs[i] = p;
495 repo_internalize(commandlinerepo);
498 #if defined(ENABLE_RPMDB)
499 if (pool->disttype == DISTTYPE_RPM)
500 addfileprovides(pool);
503 add_autopackages(pool);
505 pool_createwhatprovides(pool);
508 keyname = solv_dupjoin("solvable:", keyname, 0);
510 for (i = 1; i < argc; i++)
515 if (commandlinepkgs && commandlinepkgs[i])
517 queue_push2(&job, SOLVER_SOLVABLE, commandlinepkgs[i]);
521 flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB;
522 flags |= SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL;
523 if (kindfilter.count)
524 flags |= SELECTION_SKIP_KIND;
525 if (mode == MODE_LIST || archfilter_src)
526 flags |= SELECTION_WITH_SOURCE;
527 if (argv[i][0] == '/')
528 flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
530 rflags = selection_make(pool, &job2, argv[i], flags);
532 rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
533 if (repofilter.count)
534 selection_filter(pool, &job2, &repofilter);
535 if (archfilter.count)
536 selection_filter(pool, &job2, &archfilter);
537 if (kindfilter.count)
538 selection_filter(pool, &job2, &kindfilter);
541 flags |= SELECTION_NOCASE;
543 rflags = selection_make(pool, &job2, argv[i], flags);
545 rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
546 if (repofilter.count)
547 selection_filter(pool, &job2, &repofilter);
548 if (archfilter.count)
549 selection_filter(pool, &job2, &archfilter);
550 if (kindfilter.count)
551 selection_filter(pool, &job2, &kindfilter);
553 printf("[ignoring case for '%s']\n", argv[i]);
557 fprintf(stderr, "nothing matches '%s'\n", argv[i]);
560 if (rflags & SELECTION_FILELIST)
561 printf("[using file list match for '%s']\n", argv[i]);
562 if (rflags & SELECTION_PROVIDES)
563 printf("[using capability match for '%s']\n", argv[i]);
564 queue_insertn(&job, job.count, job2.count, job2.elements);
567 keyname = solv_free(keyname);
569 if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count || archfilter.count || kindfilter.count))
571 queue_push2(&job, SOLVER_SOLVABLE_ALL, 0);
572 if (repofilter.count)
573 selection_filter(pool, &job, &repofilter);
574 if (archfilter.count)
575 selection_filter(pool, &job, &archfilter);
576 if (kindfilter.count)
577 selection_filter(pool, &job, &kindfilter);
579 queue_free(&repofilter);
580 queue_free(&archfilter);
581 queue_free(&kindfilter);
583 if (!job.count && mainmode != MODE_PATCH)
585 printf("no package matched\n");
589 if (mainmode == MODE_LIST || mainmode == MODE_INFO)
591 /* list mode, no solver needed */
594 for (i = 0; i < job.count; i += 2)
598 pool_job2solvables(pool, &q, job.elements[i], job.elements[i + 1]);
599 for (j = 0; j < q.count; j++)
601 Solvable *s = pool_id2solvable(pool, q.elements[j]);
602 if (mainmode == MODE_INFO)
605 printf("Name: %s\n", pool_solvable2str(pool, s));
606 printf("Repo: %s\n", s->repo->name);
607 printf("Summary: %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY));
608 str = solvable_lookup_str(s, SOLVABLE_URL);
610 printf("Url: %s\n", str);
611 str = solvable_lookup_str(s, SOLVABLE_LICENSE);
613 printf("License: %s\n", str);
614 printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION));
620 const char *sum = solvable_lookup_str_lang(s, SOLVABLE_SUMMARY, "de", 1);
622 const char *sum = solvable_lookup_str_poollang(s, SOLVABLE_SUMMARY);
624 printf(" - %s [%s]\n", pool_solvable2str(pool, s), s->repo->name);
626 printf(" %s\n", sum);
633 free_repoinfos(repoinfos, nrepoinfos);
634 solv_free(commandlinepkgs);
638 #if defined(SUSE) || defined(FEDORA)
639 if (mainmode == MODE_PATCH)
640 add_patchjobs(pool, &job);
644 for (i = 0; i < job.count; i += 2)
646 job.elements[i] |= mode;
647 if (mode == SOLVER_UPDATE && pool_isemptyupdatejob(pool, job.elements[i], job.elements[i + 1]))
648 job.elements[i] ^= SOLVER_UPDATE ^ SOLVER_INSTALL;
650 job.elements[i] |= SOLVER_CLEANDEPS;
652 job.elements[i] |= SOLVER_FORCEBEST;
656 // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1));
657 // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1));
658 // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1));
660 queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
661 queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
664 #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA))
667 solv = solver_create(pool);
668 solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1);
670 solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1);
672 if (mainmode == MODE_ERASE)
673 solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); /* don't nag */
674 solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
678 Id problem, solution;
681 if (!solver_solve(solv, &job))
683 pcnt = solver_problem_count(solv);
684 printf("Found %d problems:\n", pcnt);
685 for (problem = 1; problem <= pcnt; problem++)
688 printf("Problem %d/%d:\n", problem, pcnt);
689 solver_printprobleminfo(solv, problem);
691 scnt = solver_solution_count(solv, problem);
692 for (solution = 1; solution <= scnt; solution++)
694 printf("Solution %d:\n", solution);
695 solver_printsolution(solv, problem, solution);
700 char inbuf[128], *ip;
701 printf("Please choose a solution: ");
704 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
709 while (*ip == ' ' || *ip == '\t')
711 if (*ip >= '0' && *ip <= '9')
714 if (take >= 1 && take <= scnt)
730 solver_take_solution(solv, problem, take, &job);
734 trans = solver_create_transaction(solv);
735 if (!trans->steps.count)
737 printf("Nothing to do.\n");
738 transaction_free(trans);
742 free_repoinfos(repoinfos, nrepoinfos);
743 solv_free(commandlinepkgs);
747 /* display transaction to the user and ask for confirmation */
749 printf("Transaction summary:\n\n");
750 transaction_print(trans);
752 showdiskusagechanges(trans);
754 printf("install size change: %d K\n", transaction_calc_installsizechange(trans));
757 if (!yesno("OK to continue (y/n)? "))
760 transaction_free(trans);
764 free_repoinfos(repoinfos, nrepoinfos);
765 solv_free(commandlinepkgs);
769 /* download all new packages */
771 newpkgs = transaction_installedresult(trans, &checkq);
775 int downloadsize = 0;
776 for (i = 0; i < newpkgs; i++)
780 p = checkq.elements[i];
781 s = pool_id2solvable(pool, p);
782 downloadsize += solvable_lookup_sizek(s, SOLVABLE_DOWNLOADSIZE, 0);
784 printf("Downloading %d packages, %d K\n", newpkgs, downloadsize);
785 newpkgsfps = solv_calloc(newpkgs, sizeof(*newpkgsfps));
786 for (i = 0; i < newpkgs; i++)
790 struct repoinfo *cinfo;
792 p = checkq.elements[i];
793 s = pool_id2solvable(pool, p);
794 if (s->repo == commandlinerepo)
796 loc = solvable_lookup_location(s, 0);
799 if (!(newpkgsfps[i] = fopen(loc, "r")))
807 cinfo = s->repo->appdata;
808 if (!cinfo || cinfo->type == TYPE_INSTALLED)
810 printf("%s: no repository information\n", s->repo->name);
813 loc = solvable_lookup_location(s, 0);
815 continue; /* pseudo package? */
816 #if defined(ENABLE_RPMDB)
817 if (pool->installed && pool->installed->nsolvables)
819 if ((newpkgsfps[i] = trydeltadownload(s, loc)) != 0)
823 continue; /* delta worked! */
827 if ((newpkgsfps[i] = downloadpackage(s, loc)) == 0)
829 printf("\n%s: %s not found in repository\n", s->repo->name, loc);
838 #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
839 /* check for file conflicts */
843 queue_init(&conflicts);
844 if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts))
846 if (yesno("Re-run solver (y/n/q)? "))
848 for (i = 0; i < newpkgs; i++)
850 fclose(newpkgsfps[i]);
851 newpkgsfps = solv_free(newpkgsfps);
854 pool_add_fileconflicts_deps(pool, &conflicts);
855 queue_free(&conflicts);
859 queue_free(&conflicts);
863 /* and finally commit the transaction */
864 printf("Committing transaction:\n\n");
865 transaction_order(trans, 0);
866 for (i = 0; i < trans->steps.count; i++)
872 p = trans->steps.elements[i];
873 type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY);
876 case SOLVER_TRANSACTION_ERASE:
877 printf("erase %s\n", pool_solvid2str(pool, p));
878 commit_transactionelement(pool, type, p, 0);
880 case SOLVER_TRANSACTION_INSTALL:
881 case SOLVER_TRANSACTION_MULTIINSTALL:
882 printf("install %s\n", pool_solvid2str(pool, p));
883 for (j = 0; j < newpkgs; j++)
884 if (checkq.elements[j] == p)
886 fp = j < newpkgs ? newpkgsfps[j] : 0;
889 commit_transactionelement(pool, type, p, fp);
898 for (i = 0; i < newpkgs; i++)
900 fclose(newpkgsfps[i]);
901 solv_free(newpkgsfps);
903 transaction_free(trans);
907 free_repoinfos(repoinfos, nrepoinfos);
908 solv_free(commandlinepkgs);