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) || defined(MAGEIA)
53 #include "patchjobs.h"
65 pool_setarch(pool, un.machine);
70 yesno(const char *str, int other)
79 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
84 while (*ip == ' ' || *ip == '\t')
91 if (*ip == 'y' || *ip == 'n' || *ip == other)
92 return *ip == 'n' ? 0 : *ip;
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 showdiskusagechanges(Transaction *trans)
124 /* XXX: use mountpoints here */
125 memset(duc, 0, sizeof(duc));
127 duc[1].path = "/usr/share/man";
128 duc[2].path = "/sbin";
129 duc[3].path = "/etc";
130 transaction_calc_duchanges(trans, duc, 4);
131 for (i = 0; i < 4; i++)
132 printf("duchanges %s: %d K %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files);
137 find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
142 for (rp = name; *rp; rp++)
143 if (*rp <= '0' || *rp >= '9')
147 /* repo specified by number */
148 int rnum = atoi(name);
149 for (i = 0; i < nrepoinfos; i++)
151 struct repoinfo *cinfo = repoinfos + i;
152 if (!cinfo->enabled || !cinfo->repo)
155 return cinfo->repo->repoid;
160 /* repo specified by alias */
164 if (!strcasecmp(name, repo->name))
173 #define MODE_INSTALL 1
175 #define MODE_UPDATE 3
176 #define MODE_DISTUPGRADE 4
177 #define MODE_VERIFY 5
180 #define MODE_REPOLIST 8
181 #define MODE_SEARCH 9
186 fprintf(stderr, "Usage: solv COMMAND <select>\n");
187 fprintf(stderr, "\n");
188 fprintf(stderr, " dist-upgrade: replace installed packages with\n");
189 fprintf(stderr, " versions from the repositories\n");
190 fprintf(stderr, " erase: erase installed packages\n");
191 fprintf(stderr, " info: display package information\n");
192 fprintf(stderr, " install: install packages\n");
193 fprintf(stderr, " list: list packages\n");
194 fprintf(stderr, " repos: list enabled repositories\n");
195 fprintf(stderr, " search: search name/summary/description\n");
196 fprintf(stderr, " update: update installed packages\n");
197 fprintf(stderr, " verify: check dependencies of installed packages\n");
198 #if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
199 fprintf(stderr, " patch: install newest maintenance updates\n");
201 fprintf(stderr, "\n");
206 main(int argc, char **argv)
209 Repo *commandlinerepo = 0;
210 Id *commandlinepkgs = 0;
212 struct repoinfo *repoinfos, installedrepoinfo;
214 int mainmode = 0, mode = 0;
223 int archfilter_src = 0;
228 int keyname_depstr = 0;
230 int answer, acnt = 0;
234 while (argc && !strcmp(argv[0], "-d"))
242 if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in"))
244 mainmode = MODE_INSTALL;
245 mode = SOLVER_INSTALL;
247 #if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
248 else if (!strcmp(argv[0], "patch"))
250 mainmode = MODE_PATCH;
251 mode = SOLVER_INSTALL;
254 else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm"))
256 mainmode = MODE_ERASE;
259 else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "ls"))
261 mainmode = MODE_LIST;
264 else if (!strcmp(argv[0], "info"))
266 mainmode = MODE_INFO;
269 else if (!strcmp(argv[0], "search") || !strcmp(argv[0], "se"))
271 mainmode = MODE_SEARCH;
274 else if (!strcmp(argv[0], "verify"))
276 mainmode = MODE_VERIFY;
277 mode = SOLVER_VERIFY;
279 else if (!strcmp(argv[0], "update") || !strcmp(argv[0], "up"))
281 mainmode = MODE_UPDATE;
282 mode = SOLVER_UPDATE;
284 else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup"))
286 mainmode = MODE_DISTUPGRADE;
287 mode = SOLVER_DISTUPGRADE;
289 else if (!strcmp(argv[0], "repos") || !strcmp(argv[0], "repolist") || !strcmp(argv[0], "lr"))
291 mainmode = MODE_REPOLIST;
299 if (argc > 2 && !strcmp(argv[1], "--root"))
305 else if (argc > 1 && !strcmp(argv[1], "--clean"))
311 else if (argc > 1 && !strcmp(argv[1], "--best"))
317 else if (argc > 1 && !strcmp(argv[1], "--depstr"))
323 else if (argc > 2 && !strcmp(argv[1], "--keyname"))
334 pool = pool_create();
335 pool_set_rootdir(pool, rootdir);
339 const char *langs[] = {"de_DE", "de", "en"};
340 pool_set_languages(pool, langs, sizeof(langs)/sizeof(*langs));
344 pool_setloadcallback(pool, load_stub, 0);
346 pool->nscallback = nscallback;
349 pool_setdebuglevel(pool, debuglevel);
351 pool_set_flag(pool, POOL_FLAG_ADDFILEPROVIDESFILTERED, 1);
352 repoinfos = read_repoinfos(pool, &nrepoinfos);
353 sort_repoinfos(repoinfos, nrepoinfos);
355 if (mainmode == MODE_REPOLIST)
358 for (i = 0; i < nrepoinfos; i++)
360 struct repoinfo *cinfo = repoinfos + i;
363 printf("%d: %-20s %s (prio %d)\n", j++, cinfo->alias, cinfo->name, cinfo->priority);
367 memset(&installedrepoinfo, 0, sizeof(installedrepoinfo));
368 if (!read_installed_repo(&installedrepoinfo, pool))
370 read_repos(pool, repoinfos, nrepoinfos);
373 queue_init(&repofilter);
374 queue_init(&kindfilter);
375 queue_init(&archfilter);
378 if (!strcmp(argv[1], "-i"))
380 queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, pool->installed->repoid);
384 else if (argc > 2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "--repo")))
386 Id repoid = find_repo(argv[2], pool, repoinfos, nrepoinfos);
389 fprintf(stderr, "%s: no such repo\n", argv[2]);
392 /* SETVENDOR is actually wrong but useful */
393 queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO | SOLVER_SETVENDOR, repoid);
397 else if (argc > 2 && !strcmp(argv[1], "--arch"))
399 if (!strcmp(argv[2], "src") || !strcmp(argv[2], "nosrc"))
401 queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, argv[2], 1), REL_ARCH, 1));
405 else if (argc > 2 && (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--type")))
407 const char *kind = argv[2];
408 if (!strcmp(kind, "srcpackage"))
410 /* hey! should use --arch! */
411 queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, ARCH_SRC, REL_ARCH, 1));
417 if (!strcmp(kind, "package"))
419 if (!strcmp(kind, "all"))
420 queue_push2(&kindfilter, SOLVER_SOLVABLE_ALL, 0);
422 queue_push2(&kindfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, kind, 1), REL_KIND, 1));
430 if (mainmode == MODE_SEARCH)
436 pool_createwhatprovides(pool);
438 dataiterator_init(&di, pool, 0, 0, 0, argv[1], SEARCH_SUBSTRING|SEARCH_NOCASE);
439 dataiterator_set_keyname(&di, SOLVABLE_NAME);
440 dataiterator_set_search(&di, 0, 0);
441 while (dataiterator_step(&di))
442 queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
443 dataiterator_set_keyname(&di, SOLVABLE_SUMMARY);
444 dataiterator_set_search(&di, 0, 0);
445 while (dataiterator_step(&di))
446 queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
447 dataiterator_set_keyname(&di, SOLVABLE_DESCRIPTION);
448 dataiterator_set_search(&di, 0, 0);
449 while (dataiterator_step(&di))
450 queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
451 dataiterator_free(&di);
452 if (repofilter.count)
453 selection_filter(pool, &sel, &repofilter);
456 selection_solvables(pool, &sel, &q);
458 for (i = 0; i < q.count; i++)
460 Solvable *s = pool_id2solvable(pool, q.elements[i]);
461 printf(" - %s [%s]: %s\n", pool_solvable2str(pool, s), s->repo->name, solvable_lookup_str(s, SOLVABLE_SUMMARY));
467 /* process command line packages */
468 if (mainmode == MODE_LIST || mainmode == MODE_INFO || mainmode == MODE_INSTALL)
470 for (i = 1; i < argc; i++)
472 if (!is_cmdline_package((const char *)argv[i]))
474 if (access(argv[i], R_OK))
479 if (!commandlinepkgs)
480 commandlinepkgs = solv_calloc(argc, sizeof(Id));
481 if (!commandlinerepo)
482 commandlinerepo = repo_create(pool, "@commandline");
483 p = add_cmdline_package(commandlinerepo, (const char *)argv[i]);
486 fprintf(stderr, "could not add '%s'\n", argv[i]);
489 commandlinepkgs[i] = p;
493 repo_internalize(commandlinerepo);
495 repo_add_autopattern(commandlinerepo, 0);
500 #if defined(ENABLE_RPMDB)
501 if (pool->disttype == DISTTYPE_RPM)
502 addfileprovides(pool);
504 pool_createwhatprovides(pool);
507 keyname = solv_dupjoin("solvable:", keyname, 0);
509 for (i = 1; i < argc; i++)
514 if (commandlinepkgs && commandlinepkgs[i])
516 queue_push2(&job, SOLVER_SOLVABLE, commandlinepkgs[i]);
520 flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB;
521 flags |= SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL;
522 if (kindfilter.count)
523 flags |= SELECTION_SKIP_KIND;
524 if (mode == MODE_LIST || archfilter_src)
525 flags |= SELECTION_WITH_SOURCE;
526 if (argv[i][0] == '/')
527 flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
529 rflags = selection_make(pool, &job2, argv[i], flags);
533 flags |= SELECTION_MATCH_DEPSTR;
534 rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
536 if (repofilter.count)
537 selection_filter(pool, &job2, &repofilter);
538 if (archfilter.count)
539 selection_filter(pool, &job2, &archfilter);
540 if (kindfilter.count)
541 selection_filter(pool, &job2, &kindfilter);
544 flags |= SELECTION_NOCASE;
546 rflags = selection_make(pool, &job2, argv[i], flags);
548 rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
549 if (repofilter.count)
550 selection_filter(pool, &job2, &repofilter);
551 if (archfilter.count)
552 selection_filter(pool, &job2, &archfilter);
553 if (kindfilter.count)
554 selection_filter(pool, &job2, &kindfilter);
556 printf("[ignoring case for '%s']\n", argv[i]);
560 fprintf(stderr, "nothing matches '%s'\n", argv[i]);
563 if (rflags & SELECTION_FILELIST)
564 printf("[using file list match for '%s']\n", argv[i]);
565 if (rflags & SELECTION_PROVIDES)
566 printf("[using capability match for '%s']\n", argv[i]);
567 queue_insertn(&job, job.count, job2.count, job2.elements);
570 keyname = solv_free(keyname);
572 if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count || archfilter.count || kindfilter.count))
574 queue_push2(&job, SOLVER_SOLVABLE_ALL, 0);
575 if (repofilter.count)
576 selection_filter(pool, &job, &repofilter);
577 if (archfilter.count)
578 selection_filter(pool, &job, &archfilter);
579 if (kindfilter.count)
580 selection_filter(pool, &job, &kindfilter);
582 queue_free(&repofilter);
583 queue_free(&archfilter);
584 queue_free(&kindfilter);
586 if (!job.count && mainmode != MODE_PATCH)
588 printf("no package matched\n");
592 if (mainmode == MODE_LIST || mainmode == MODE_INFO)
594 /* list mode, no solver needed */
597 for (i = 0; i < job.count; i += 2)
601 pool_job2solvables(pool, &q, job.elements[i], job.elements[i + 1]);
602 for (j = 0; j < q.count; j++)
604 Solvable *s = pool_id2solvable(pool, q.elements[j]);
605 if (mainmode == MODE_INFO)
608 printf("Name: %s\n", pool_solvable2str(pool, s));
609 printf("Repo: %s\n", s->repo->name);
610 printf("Summary: %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY));
611 str = solvable_lookup_str(s, SOLVABLE_URL);
613 printf("Url: %s\n", str);
614 str = solvable_lookup_str(s, SOLVABLE_LICENSE);
616 printf("License: %s\n", str);
617 printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION));
623 const char *sum = solvable_lookup_str_lang(s, SOLVABLE_SUMMARY, "de", 1);
625 const char *sum = solvable_lookup_str_poollang(s, SOLVABLE_SUMMARY);
627 printf(" - %s [%s]\n", pool_solvable2str(pool, s), s->repo->name);
629 printf(" %s\n", sum);
636 free_repoinfos(repoinfos, nrepoinfos);
637 solv_free(commandlinepkgs);
641 #if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
642 if (mainmode == MODE_PATCH)
643 add_patchjobs(pool, &job);
647 for (i = 0; i < job.count; i += 2)
649 job.elements[i] |= mode;
650 if (mode == SOLVER_UPDATE && pool_isemptyupdatejob(pool, job.elements[i], job.elements[i + 1]))
651 job.elements[i] ^= SOLVER_UPDATE ^ SOLVER_INSTALL;
653 job.elements[i] |= SOLVER_CLEANDEPS;
655 job.elements[i] |= SOLVER_FORCEBEST;
659 // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1));
660 // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1));
661 // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1));
663 queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
664 queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
668 solv = solver_create(pool);
669 solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1);
670 #if defined(FEDORA) || defined(MAGEIA)
671 solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1);
673 if (mainmode == MODE_ERASE)
674 solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); /* don't nag */
675 solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
679 Id problem, solution;
682 if (!solver_solve(solv, &job))
684 pcnt = solver_problem_count(solv);
685 printf("Found %d problems:\n", pcnt);
686 for (problem = 1; problem <= pcnt; problem++)
689 printf("Problem %d/%d:\n", problem, pcnt);
690 solver_printprobleminfo(solv, problem);
692 scnt = solver_solution_count(solv, problem);
693 for (solution = 1; solution <= scnt; solution++)
695 printf("Solution %d:\n", solution);
696 solver_printsolution(solv, problem, solution);
701 char inbuf[128], *ip;
702 printf("Please choose a solution: ");
705 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
710 while (*ip == ' ' || *ip == '\t')
712 if (*ip >= '0' && *ip <= '9')
715 if (take >= 1 && take <= scnt)
731 solver_take_solution(solv, problem, take, &job);
735 trans = solver_create_transaction(solv);
736 if (!trans->steps.count)
738 printf("Nothing to do.\n");
739 transaction_free(trans);
743 free_repoinfos(repoinfos, nrepoinfos);
744 solv_free(commandlinepkgs);
748 /* display transaction to the user and ask for confirmation */
750 printf("Transaction summary:\n\n");
751 transaction_print(trans);
753 showdiskusagechanges(trans);
755 printf("install size change: %d K\n", transaction_calc_installsizechange(trans));
758 acnt = solver_alternatives_count(solv);
762 printf("Have one alternative:\n");
764 printf("Have %d alternatives:\n", acnt);
765 for (i = 1; i <= acnt; i++)
768 int atype = solver_get_alternative(solv, i, &id, &from, 0, 0, 0);
769 printf(" - %s\n", solver_alternative2str(solv, atype, id, from));
772 answer = yesno("OK to continue (y/n/a)? ", 'a');
775 answer = yesno("OK to continue (y/n)? ", 0);
783 queue_init(&choicesq);
784 queue_init(&answerq);
785 for (i = 1; i <= acnt; i++)
787 int atype = solver_get_alternative(solv, i, &id, &from, &chosen, &choicesq, 0);
788 printf("\n%s\n", solver_alternative2str(solv, atype, id, from));
789 for (j = 0; j < choicesq.count; j++)
791 Id p = choicesq.elements[j];
794 queue_push(&answerq, p);
795 printf("%6d: %s\n", answerq.count, pool_solvid2str(pool, p));
798 queue_free(&choicesq);
802 char inbuf[128], *ip;
804 printf("OK to continue (y/n), or number to change alternative: ");
807 if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
812 while (*ip == ' ' || *ip == '\t')
814 if (*ip == '-' && ip[1] >= '0' && ip[1] <= '9')
819 if (*ip >= '0' && *ip <= '9')
822 if (take > 0 && take <= answerq.count)
824 Id p = answerq.elements[take - 1];
825 queue_free(&answerq);
826 queue_push2(&job, (neg ? SOLVER_DISFAVOR : SOLVER_FAVOR) | SOLVER_SOLVABLE_NAME, pool->solvables[p].name);
833 if (*ip == 'n' || *ip == 'y')
835 answer = *ip == 'n' ? 0 : *ip;
839 queue_free(&answerq);
844 transaction_free(trans);
848 free_repoinfos(repoinfos, nrepoinfos);
849 solv_free(commandlinepkgs);
853 /* download all new packages */
855 newpkgs = transaction_installedresult(trans, &checkq);
859 int downloadsize = 0;
860 for (i = 0; i < newpkgs; i++)
864 p = checkq.elements[i];
865 s = pool_id2solvable(pool, p);
866 downloadsize += solvable_lookup_sizek(s, SOLVABLE_DOWNLOADSIZE, 0);
868 printf("Downloading %d packages, %d K\n", newpkgs, downloadsize);
869 newpkgsfps = solv_calloc(newpkgs, sizeof(*newpkgsfps));
870 for (i = 0; i < newpkgs; i++)
874 struct repoinfo *cinfo;
876 p = checkq.elements[i];
877 s = pool_id2solvable(pool, p);
878 if (s->repo == commandlinerepo)
880 loc = solvable_lookup_location(s, 0);
883 if (!(newpkgsfps[i] = fopen(loc, "r")))
891 cinfo = s->repo->appdata;
892 if (!cinfo || cinfo->type == TYPE_INSTALLED)
894 printf("%s: no repository information\n", s->repo->name);
897 loc = solvable_lookup_location(s, 0);
899 continue; /* pseudo package? */
900 #if defined(ENABLE_RPMDB)
901 if (pool->installed && pool->installed->nsolvables)
903 if ((newpkgsfps[i] = trydeltadownload(s, loc)) != 0)
907 continue; /* delta worked! */
911 if ((newpkgsfps[i] = downloadpackage(s, loc)) == 0)
913 printf("\n%s: %s not found in repository\n", s->repo->name, loc);
922 #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
923 /* check for file conflicts */
927 queue_init(&conflicts);
928 if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts))
930 if (yesno("Re-run solver (y/n/q)? ", 0))
932 for (i = 0; i < newpkgs; i++)
934 fclose(newpkgsfps[i]);
935 newpkgsfps = solv_free(newpkgsfps);
938 pool_add_fileconflicts_deps(pool, &conflicts);
939 queue_free(&conflicts);
943 queue_free(&conflicts);
947 /* and finally commit the transaction */
948 printf("Committing transaction:\n\n");
949 transaction_order(trans, 0);
950 for (i = 0; i < trans->steps.count; i++)
956 p = trans->steps.elements[i];
957 type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY);
960 case SOLVER_TRANSACTION_ERASE:
961 printf("erase %s\n", pool_solvid2str(pool, p));
962 commit_transactionelement(pool, type, p, 0);
964 case SOLVER_TRANSACTION_INSTALL:
965 case SOLVER_TRANSACTION_MULTIINSTALL:
966 printf("install %s\n", pool_solvid2str(pool, p));
967 for (j = 0; j < newpkgs; j++)
968 if (checkq.elements[j] == p)
970 fp = j < newpkgs ? newpkgsfps[j] : 0;
973 commit_transactionelement(pool, type, p, fp);
982 for (i = 0; i < newpkgs; i++)
984 fclose(newpkgsfps[i]);
985 solv_free(newpkgsfps);
987 transaction_free(trans);
991 free_repoinfos(repoinfos, nrepoinfos);
992 solv_free(commandlinepkgs);