1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2012-2015 Red Hat, Inc.
4 * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
5 *
6 * Licensed under the GNU Lesser General Public License Version 2.1
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or(at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * SECTION:dnf-sack
25 * @short_description: A package sack
26 * @include: libdnf.h
27 * @stability: Unstable
28 *
29 * Sacks are repositories of packages.
30 *
31 * See also: #DnfContext
32 */
33
34
35 #include <algorithm>
36 #include <assert.h>
37 #include <errno.h>
38 #include <functional>
39 #include <unistd.h>
40 #include <iostream>
41 #include <list>
42 #include <set>
43
44 extern "C" {
45 #include <solv/evr.h>
46 #include <solv/pool.h>
47 #include <solv/poolarch.h>
48 #include <solv/repo.h>
49 #include <solv/repo_deltainfoxml.h>
50 #include <solv/repo_repomdxml.h>
51 #include <solv/repo_updateinfoxml.h>
52 #include <solv/repo_rpmmd.h>
53 #include <solv/repo_rpmdb.h>
54 #include <solv/repo_solv.h>
55 #include <solv/repo_write.h>
56 #include <solv/solv_xfopen.h>
57 #include <solv/solver.h>
58 }
59
60 #include <cstring>
61 #include <sstream>
62
63 #include "catch-error.hpp"
64 #include "dnf-context.hpp"
65 #include "dnf-types.h"
66 #include "dnf-package.h"
67 #include "hy-iutil-private.hpp"
68 #include "hy-query.h"
69 #include "hy-repo-private.hpp"
70 #include "dnf-sack-private.hpp"
71 #include "hy-util.h"
72
73 #include "utils/bgettext/bgettext-lib.h"
74
75 #include "sack/query.hpp"
76 #include "nevra.hpp"
77 #include "conf/ConfigParser.hpp"
78 #include "conf/OptionBool.hpp"
79 #include "module/ModulePackageContainer.hpp"
80 #include "module/ModulePackage.hpp"
81 #include "repo/Repo-private.hpp"
82 #include "repo/solvable/DependencyContainer.hpp"
83 #include "utils/crypto/sha1.hpp"
84 #include "utils/File.hpp"
85 #include "utils/utils.hpp"
86 #include "log.hpp"
87 #include "tinyformat/tinyformat.hpp"
88
89
90 #define DEFAULT_CACHE_ROOT "/var/cache/hawkey"
91 #define DEFAULT_CACHE_USER "/var/tmp/hawkey"
92
93 typedef struct
94 {
95 Id running_kernel_id;
96 Map *pkg_excludes;
97 Map *pkg_includes;
98 Map *repo_excludes;
99 Map *module_excludes;
100 Map *module_includes; /* To fast identify enabled modular packages */
101 Map *pkg_solvables; /* Map representing only solvable pkgs of query */
102 int pool_nsolvables; /* Number of nsolvables for creation of pkg_solvables*/
103 Pool *pool;
104 Queue installonly;
105 Repo *cmdline_repo;
106 gboolean considered_uptodate;
107 gboolean have_set_arch;
108 gboolean all_arch;
109 gboolean provides_ready;
110 gboolean allow_vendor_change;
111 gchar *cache_dir;
112 char *arch;
113 dnf_sack_running_kernel_fn_t running_kernel_fn;
114 guint installonly_limit;
115 libdnf::ModulePackageContainer * moduleContainer;
116 } DnfSackPrivate;
117
G_DEFINE_TYPE_WITH_PRIVATE(DnfSack,dnf_sack,G_TYPE_OBJECT)118 G_DEFINE_TYPE_WITH_PRIVATE(DnfSack, dnf_sack, G_TYPE_OBJECT)
119 #define GET_PRIVATE(o) (static_cast<DnfSackPrivate *>(dnf_sack_get_instance_private (o)))
120
121
122 /**
123 * dnf_sack_finalize:
124 **/
125 static void
126 dnf_sack_finalize(GObject *object)
127 {
128 DnfSack *sack = DNF_SACK(object);
129 DnfSackPrivate *priv = GET_PRIVATE(sack);
130 Pool *pool = priv->pool;
131 Repo *repo;
132 int i;
133
134 FOR_REPOS(i, repo) {
135 auto hrepo = static_cast<HyRepo>(repo->appdata);
136 if (!hrepo)
137 continue;
138 libdnf::repoGetImpl(hrepo)->detachLibsolvRepo();
139 }
140 g_free(priv->cache_dir);
141 g_free(priv->arch);
142 queue_free(&priv->installonly);
143
144 free_map_fully(priv->pkg_excludes);
145 free_map_fully(priv->pkg_includes);
146 free_map_fully(priv->repo_excludes);
147 free_map_fully(priv->module_excludes);
148 free_map_fully(priv->module_includes);
149 free_map_fully(pool->considered);
150 free_map_fully(priv->pkg_solvables);
151 pool_free(priv->pool);
152 if (priv->moduleContainer) {
153 delete priv->moduleContainer;
154 }
155
156 G_OBJECT_CLASS(dnf_sack_parent_class)->finalize(object);
157 }
158
159 // log levels (see also SOLV_ERROR etc. in <solv/pool.h>)
160 #define HY_LL_INFO (1 << 20)
161 #define HY_LL_ERROR (1 << 21)
162
163 static void
log_cb(Pool * pool,void * cb_data,int level,const char * buf)164 log_cb(Pool *pool, void *cb_data, int level, const char *buf)
165 {
166 /* just proxy this to the GLib logging handler */
167 switch(level) {
168 case HY_LL_INFO:
169 g_debug ("%s", buf);
170 break;
171 case HY_LL_ERROR:
172 g_warning ("%s", buf);
173 break;
174 default:
175 g_info ("%s", buf);
176 break;
177 }
178 }
179
180 /**
181 * dnf_sack_init:
182 **/
183 static void
dnf_sack_init(DnfSack * sack)184 dnf_sack_init(DnfSack *sack)
185 {
186 DnfSackPrivate *priv = GET_PRIVATE(sack);
187 priv->pool = pool_create();
188 pool_set_flag(priv->pool, POOL_FLAG_WHATPROVIDESWITHDISABLED, 1);
189 priv->running_kernel_id = -1;
190 priv->running_kernel_fn = running_kernel;
191 priv->considered_uptodate = TRUE;
192 priv->cmdline_repo = NULL;
193 priv->allow_vendor_change = TRUE;
194 queue_init(&priv->installonly);
195
196 /* logging up after this*/
197 pool_setdebugcallback(priv->pool, log_cb, sack);
198 pool_setdebugmask(priv->pool,
199 SOLV_ERROR | SOLV_FATAL | SOLV_WARN | SOLV_DEBUG_RESULT |
200 HY_LL_INFO | HY_LL_ERROR);
201 }
202
203 /**
204 * dnf_sack_class_init:
205 **/
206 static void
dnf_sack_class_init(DnfSackClass * klass)207 dnf_sack_class_init(DnfSackClass *klass)
208 {
209 GObjectClass *object_class = G_OBJECT_CLASS(klass);
210 object_class->finalize = dnf_sack_finalize;
211 }
212
213 /**
214 * dnf_sack_new:
215 *
216 * Creates a new #DnfSack.
217 *
218 * Returns:(transfer full): a #DnfSack
219 *
220 * Since: 0.7.0
221 **/
222 DnfSack *
dnf_sack_new(void)223 dnf_sack_new(void)
224 {
225 return DNF_SACK(g_object_new(DNF_TYPE_SACK, NULL));
226 }
227
228 static int
can_use_repomd_cache(FILE * fp_solv,unsigned char cs_repomd[CHKSUM_BYTES])229 can_use_repomd_cache(FILE *fp_solv, unsigned char cs_repomd[CHKSUM_BYTES])
230 {
231 unsigned char cs_cache[CHKSUM_BYTES];
232
233 if (fp_solv &&
234 !checksum_read(cs_cache, fp_solv) &&
235 !checksum_cmp(cs_cache, cs_repomd))
236 return 1;
237
238 return 0;
239 }
240
241 void
dnf_sack_set_running_kernel_fn(DnfSack * sack,dnf_sack_running_kernel_fn_t fn)242 dnf_sack_set_running_kernel_fn (DnfSack *sack, dnf_sack_running_kernel_fn_t fn)
243 {
244 DnfSackPrivate *priv = GET_PRIVATE(sack);
245 priv->running_kernel_fn = fn;
246 }
247
248 void
dnf_sack_set_pkg_solvables(DnfSack * sack,Map * pkg_solvables,int pool_nsolvables)249 dnf_sack_set_pkg_solvables(DnfSack *sack, Map *pkg_solvables, int pool_nsolvables)
250 {
251 DnfSackPrivate *priv = GET_PRIVATE(sack);
252
253 auto pkg_solvables_tmp = static_cast<Map *>(g_malloc(sizeof(Map)));
254 if (priv->pkg_solvables)
255 free_map_fully(priv->pkg_solvables);
256 map_init_clone(pkg_solvables_tmp, pkg_solvables);
257 priv->pkg_solvables = pkg_solvables_tmp;
258 priv->pool_nsolvables = pool_nsolvables;
259 }
260
261 int
dnf_sack_get_pool_nsolvables(DnfSack * sack)262 dnf_sack_get_pool_nsolvables(DnfSack *sack)
263 {
264 DnfSackPrivate *priv = GET_PRIVATE(sack);
265 return priv->pool_nsolvables;
266 }
267
268 libdnf::PackageSet *
dnf_sack_get_pkg_solvables(DnfSack * sack)269 dnf_sack_get_pkg_solvables(DnfSack *sack)
270 {
271 DnfSackPrivate *priv = GET_PRIVATE(sack);
272 return new libdnf::PackageSet(sack, priv->pkg_solvables);
273 }
274
275 /**
276 * dnf_sack_last_solvable: (skip)
277 * @sack: a #DnfSack instance.
278 *
279 * Returns an ID of last solvable in sack
280 *
281 * Returns: an #Id
282 *
283 * Since: 0.7.0
284 */
285 Id
dnf_sack_last_solvable(DnfSack * sack)286 dnf_sack_last_solvable(DnfSack *sack)
287 {
288 return dnf_sack_get_pool(sack)->nsolvables - 1;
289 }
290
291 void
dnf_sack_recompute_considered_map(DnfSack * sack,Map ** considered,libdnf::Query::ExcludeFlags flags)292 dnf_sack_recompute_considered_map(DnfSack * sack, Map ** considered, libdnf::Query::ExcludeFlags flags)
293 {
294 DnfSackPrivate *priv = GET_PRIVATE(sack);
295 Pool *pool = dnf_sack_get_pool(sack);
296 if (!*considered) {
297 if ((static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES) ||
298 (!priv->repo_excludes && !priv->pkg_excludes && !priv->pkg_includes))
299 && (static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES)
300 || !priv->module_excludes)) {
301 return;
302 }
303 *considered = static_cast<Map *>(g_malloc0(sizeof(Map)));
304 map_init(*considered, pool->nsolvables);
305 } else
306 map_grow(*considered, pool->nsolvables);
307
308 // considered = (all - repo_excludes - pkg_excludes) and
309 // (pkg_includes + all_from_repos_not_using_includes)
310 map_setall(*considered);
311 dnf_sack_make_provides_ready(sack);
312 if (!static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES)
313 && priv->module_excludes)
314 map_subtract(*considered, priv->module_excludes);
315 if (!static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES)) {
316 if (priv->repo_excludes)
317 map_subtract(*considered, priv->repo_excludes);
318 if (priv->pkg_excludes)
319 map_subtract(*considered, priv->pkg_excludes);
320 if (priv->pkg_includes) {
321 map_grow(priv->pkg_includes, pool->nsolvables);
322 Map pkg_includes_tmp;
323 map_init_clone(&pkg_includes_tmp, priv->pkg_includes);
324
325 // Add all solvables from repositories which do not use "includes"
326 Id repoid;
327 Repo *repo;
328 FOR_REPOS(repoid, repo) {
329 auto hyrepo = static_cast<HyRepo>(repo->appdata);
330 if (!hyrepo->getUseIncludes()) {
331 Id solvableid;
332 Solvable *solvable;
333 FOR_REPO_SOLVABLES(repo, solvableid, solvable)
334 MAPSET(&pkg_includes_tmp, solvableid);
335 }
336 }
337
338 map_and(*considered, &pkg_includes_tmp);
339 map_free(&pkg_includes_tmp);
340 }
341 }
342 }
343
344 /**
345 * dnf_sack_recompute_considered:
346 * @sack: a #DnfSack instance.
347 *
348 * Recompute considered packages for libsolv and queries.
349 *
350 * Since: 0.7.0
351 */
352 void
dnf_sack_recompute_considered(DnfSack * sack)353 dnf_sack_recompute_considered(DnfSack *sack)
354 {
355 DnfSackPrivate *priv = GET_PRIVATE(sack);
356 Pool *pool = dnf_sack_get_pool(sack);
357 if (priv->considered_uptodate)
358 return;
359 dnf_sack_recompute_considered_map(
360 sack, &pool->considered, libdnf::Query::ExcludeFlags::APPLY_EXCLUDES);
361 priv->considered_uptodate = TRUE;
362 }
363
364 static gboolean
load_ext(DnfSack * sack,HyRepo hrepo,_hy_repo_repodata which_repodata,const char * suffix,const char * which_filename,int (* cb)(Repo *,FILE *),GError ** error)365 load_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
366 const char *suffix, const char * which_filename,
367 int (*cb)(Repo *, FILE *), GError **error)
368 {
369 DnfSackPrivate *priv = GET_PRIVATE(sack);
370 int ret = 0;
371 auto repoImpl = libdnf::repoGetImpl(hrepo);
372 Repo *repo = repoImpl->libsolvRepo;
373 const char *name = repo->name;
374 FILE *fp;
375 gboolean done = FALSE;
376
377 char *fn_cache = dnf_sack_give_cache_fn(sack, name, suffix);
378 fp = fopen(fn_cache, "r");
379 assert(libdnf::repoGetImpl(hrepo)->checksum);
380 if (can_use_repomd_cache(fp, libdnf::repoGetImpl(hrepo)->checksum)) {
381 int flags = 0;
382 /* the updateinfo is not a real extension */
383 if (which_repodata != _HY_REPODATA_UPDATEINFO)
384 flags |= REPO_EXTEND_SOLVABLES;
385 /* do not pollute the main pool with directory component ids */
386 if (which_repodata == _HY_REPODATA_FILENAMES || which_repodata == _HY_REPODATA_OTHER)
387 flags |= REPO_LOCALPOOL;
388 done = TRUE;
389 g_debug("%s: using cache file: %s", __func__, fn_cache);
390 ret = repo_add_solv(repo, fp, flags);
391 if (ret) {
392 g_set_error_literal (error,
393 DNF_ERROR,
394 DNF_ERROR_INTERNAL_ERROR,
395 _("failed to add solv"));
396 return FALSE;
397 } else {
398 repo_update_state(hrepo, which_repodata, _HY_LOADED_CACHE);
399 repo_set_repodata(hrepo, which_repodata, repo->nrepodata - 1);
400 }
401 }
402 g_free(fn_cache);
403 if (fp)
404 fclose(fp);
405 if (done)
406 return TRUE;
407
408 auto fn = hrepo->getMetadataPath(which_filename);
409 /* nothing set */
410 if (fn.empty()) {
411 g_set_error (error,
412 DNF_ERROR,
413 DNF_ERROR_NO_CAPABILITY,
414 _("no %1$s string for %2$s"),
415 which_filename, name);
416 return FALSE;
417 }
418
419 fp = solv_xfopen(fn.c_str(), "r");
420 if (fp == NULL) {
421 g_set_error (error,
422 DNF_ERROR,
423 DNF_ERROR_FILE_INVALID,
424 _("failed to open: %s"), fn.c_str());
425 return FALSE;
426 }
427 g_debug("%s: loading: %s", __func__, fn.c_str());
428
429 int previous_last = repo->nrepodata - 1;
430 ret = cb(repo, fp);
431 fclose(fp);
432 if (ret == 0) {
433 repo_update_state(hrepo, which_repodata, _HY_LOADED_FETCH);
434 assert(previous_last == repo->nrepodata - 2); (void)previous_last;
435 repo_set_repodata(hrepo, which_repodata, repo->nrepodata - 1);
436 }
437 priv->provides_ready = 0;
438 return TRUE;
439 }
440
441 static int
load_filelists_cb(Repo * repo,FILE * fp)442 load_filelists_cb(Repo *repo, FILE *fp)
443 {
444 if (repo_add_rpmmd(repo, fp, "FL", REPO_EXTEND_SOLVABLES))
445 return DNF_ERROR_INTERNAL_ERROR;
446 return 0;
447 }
448
449 static int
load_presto_cb(Repo * repo,FILE * fp)450 load_presto_cb(Repo *repo, FILE *fp)
451 {
452 if (repo_add_deltainfoxml(repo, fp, 0))
453 return DNF_ERROR_INTERNAL_ERROR;
454 return 0;
455 }
456
457 static int
load_updateinfo_cb(Repo * repo,FILE * fp)458 load_updateinfo_cb(Repo *repo, FILE *fp)
459 {
460 if (repo_add_updateinfoxml(repo, fp, 0))
461 return DNF_ERROR_INTERNAL_ERROR;
462 return 0;
463 }
464
465 static int
load_other_cb(Repo * repo,FILE * fp)466 load_other_cb(Repo *repo, FILE *fp)
467 {
468 if (repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES))
469 return DNF_ERROR_INTERNAL_ERROR;
470 return 0;
471 }
472
473 static int
repo_is_one_piece(Repo * repo)474 repo_is_one_piece(Repo *repo)
475 {
476 int i;
477 for (i = repo->start; i < repo->end; i++)
478 if (repo->pool->solvables[i].repo != repo)
479 return 0;
480 return 1;
481 }
482
483 static gboolean
write_main(DnfSack * sack,HyRepo hrepo,int switchtosolv,GError ** error)484 write_main(DnfSack *sack, HyRepo hrepo, int switchtosolv, GError **error)
485 {
486 auto repoImpl = libdnf::repoGetImpl(hrepo);
487 Repo *repo = repoImpl->libsolvRepo;
488 const char *name = repo->name;
489 const char *chksum = pool_checksum_str(dnf_sack_get_pool(sack), repoImpl->checksum);
490 char *fn = dnf_sack_give_cache_fn(sack, name, NULL);
491 char *tmp_fn_templ = solv_dupjoin(fn, ".XXXXXX", NULL);
492 int tmp_fd = mkstemp(tmp_fn_templ);
493 gboolean ret = TRUE;
494 gint rc;
495
496 g_debug("caching repo: %s (0x%s)", name, chksum);
497
498 if (tmp_fd < 0) {
499 ret = FALSE;
500 g_set_error (error,
501 DNF_ERROR,
502 DNF_ERROR_FILE_INVALID,
503 _("cannot create temporary file: %s"),
504 tmp_fn_templ);
505 goto done;
506 } else {
507 FILE *fp = fdopen(tmp_fd, "w+");
508 if (!fp) {
509 ret = FALSE;
510 g_set_error (error,
511 DNF_ERROR,
512 DNF_ERROR_FILE_INVALID,
513 _("failed opening tmp file: %s"),
514 strerror(errno));
515 goto done;
516 }
517 rc = repo_write(repo, fp);
518 rc |= checksum_write(repoImpl->checksum, fp);
519 rc |= fclose(fp);
520 if (rc) {
521 ret = FALSE;
522 g_set_error (error,
523 DNF_ERROR,
524 DNF_ERROR_FILE_INVALID,
525 _("write_main() failed writing data: %i"), rc);
526 goto done;
527 }
528 }
529 if (switchtosolv && repo_is_one_piece(repo)) {
530 /* switch over to written solv file activate paging */
531 FILE *fp = fopen(tmp_fn_templ, "r");
532 if (fp) {
533 repo_empty(repo, 1);
534 rc = repo_add_solv(repo, fp, 0);
535 fclose(fp);
536 if (rc) {
537 /* this is pretty fatal */
538 ret = FALSE;
539 g_set_error_literal (error,
540 DNF_ERROR,
541 DNF_ERROR_FILE_INVALID,
542 _("write_main() failed to re-load "
543 "written solv file"));
544 goto done;
545 }
546 }
547 }
548
549 ret = mv(tmp_fn_templ, fn, error);
550 if (!ret)
551 goto done;
552 repoImpl->state_main = _HY_WRITTEN;
553
554 done:
555 if (!ret && tmp_fd >= 0)
556 unlink(tmp_fn_templ);
557 g_free(tmp_fn_templ);
558 g_free(fn);
559 return ret;
560 }
561
562 /* this filter makes sure only the updateinfo repodata is written */
563 static int
write_ext_updateinfo_filter(Repo * repo,Repokey * key,void * kfdata)564 write_ext_updateinfo_filter(Repo *repo, Repokey *key, void *kfdata)
565 {
566 auto data = static_cast<Repodata *>(kfdata);
567 if (key->name == 1 && (int) key->size != data->repodataid)
568 return -1;
569 return repo_write_stdkeyfilter(repo, key, 0);
570 }
571
572 static int
write_ext_updateinfo(HyRepo hrepo,Repodata * data,FILE * fp)573 write_ext_updateinfo(HyRepo hrepo, Repodata *data, FILE *fp)
574 {
575 auto repoImpl = libdnf::repoGetImpl(hrepo);
576 Repo *repo = repoImpl->libsolvRepo;
577 int oldstart = repo->start;
578 repo->start = repoImpl->main_end;
579 repo->nsolvables -= repoImpl->main_nsolvables;
580 int res = repo_write_filtered(repo, fp, write_ext_updateinfo_filter, data, 0);
581 repo->start = oldstart;
582 repo->nsolvables += repoImpl->main_nsolvables;
583 return res;
584 }
585
586 static gboolean
write_ext(DnfSack * sack,HyRepo hrepo,_hy_repo_repodata which_repodata,const char * suffix,GError ** error)587 write_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
588 const char *suffix, GError **error)
589 {
590 auto repoImpl = libdnf::repoGetImpl(hrepo);
591 Repo *repo = repoImpl->libsolvRepo;
592 int ret = 0;
593 const char *name = repo->name;
594
595 Id repodata = repo_get_repodata(hrepo, which_repodata);
596 assert(repodata);
597 Repodata *data = repo_id2repodata(repo, repodata);
598 char *fn = dnf_sack_give_cache_fn(sack, name, suffix);
599 char *tmp_fn_templ = solv_dupjoin(fn, ".XXXXXX", NULL);
600 int tmp_fd = mkstemp(tmp_fn_templ);
601 gboolean success;
602 if (tmp_fd < 0) {
603 success = FALSE;
604 g_set_error (error,
605 DNF_ERROR,
606 DNF_ERROR_FILE_INVALID,
607 _("can not create temporary file %s"),
608 tmp_fn_templ);
609 goto done;
610 } else {
611 FILE *fp = fdopen(tmp_fd, "w+");
612
613 g_debug("%s: storing %s to: %s", __func__, repo->name, tmp_fn_templ);
614 if (which_repodata != _HY_REPODATA_UPDATEINFO)
615 ret |= repodata_write(data, fp);
616 else
617 ret |= write_ext_updateinfo(hrepo, data, fp);
618 ret |= checksum_write(repoImpl->checksum, fp);
619 ret |= fclose(fp);
620 if (ret) {
621 success = FALSE;
622 g_set_error (error,
623 DNF_ERROR,
624 DNF_ERROR_FAILED,
625 _("write_ext(%1$d) has failed: %2$d"),
626 which_repodata, ret);
627 goto done;
628 }
629 }
630
631 if (repo_is_one_piece(repo) && which_repodata != _HY_REPODATA_UPDATEINFO) {
632 /* switch over to written solv file activate paging */
633 FILE *fp = fopen(tmp_fn_templ, "r");
634 if (fp) {
635 int flags = REPO_USE_LOADING | REPO_EXTEND_SOLVABLES;
636 /* do not pollute the main pool with directory component ids */
637 if (which_repodata == _HY_REPODATA_FILENAMES || which_repodata == _HY_REPODATA_OTHER)
638 flags |= REPO_LOCALPOOL;
639 repodata_extend_block(data, repo->start, repo->end - repo->start);
640 data->state = REPODATA_LOADING;
641 repo_add_solv(repo, fp, flags);
642 data->state = REPODATA_AVAILABLE;
643 fclose(fp);
644 }
645 }
646
647 if (!mv(tmp_fn_templ, fn, error)) {
648 success = FALSE;
649 goto done;
650 }
651 repo_update_state(hrepo, which_repodata, _HY_WRITTEN);
652 success = TRUE;
653 done:
654 if (ret && tmp_fd >=0 )
655 unlink(tmp_fn_templ);
656 g_free(tmp_fn_templ);
657 g_free(fn);
658 return success;
659 }
660
661 static gboolean
load_yum_repo(DnfSack * sack,HyRepo hrepo,GError ** error)662 load_yum_repo(DnfSack *sack, HyRepo hrepo, GError **error)
663 {
664 auto repoImpl = libdnf::repoGetImpl(hrepo);
665 DnfSackPrivate *priv = GET_PRIVATE(sack);
666 gboolean retval = TRUE;
667 Pool *pool = priv->pool;
668 const char *name = hrepo->getId().c_str();
669 Repo *repo = repo_create(pool, name);
670 const char *fn_repomd = repoImpl->repomdFn.c_str();
671 char *fn_cache = dnf_sack_give_cache_fn(sack, name, NULL);
672
673 FILE *fp_primary = NULL;
674 FILE *fp_repomd = NULL;
675 FILE *fp_cache = fopen(fn_cache, "r");
676 if (!fn_repomd) {
677 g_set_error (error,
678 DNF_ERROR,
679 DNF_ERROR_FILE_INVALID,
680 _("null repo md file"));
681 retval = FALSE;
682 goto out;
683 }
684 fp_repomd = fopen(fn_repomd, "r");
685 if (fp_repomd == NULL) {
686 g_set_error (error,
687 DNF_ERROR,
688 DNF_ERROR_FILE_INVALID,
689 _("can not read file %1$s: %2$s"),
690 fn_repomd, strerror(errno));
691 retval = FALSE;
692 goto out;
693 }
694 checksum_fp(repoImpl->checksum, fp_repomd);
695
696 if (can_use_repomd_cache(fp_cache, repoImpl->checksum)) {
697 const char *chksum = pool_checksum_str(pool, repoImpl->checksum);
698 g_debug("using cached %s (0x%s)", name, chksum);
699 if (repo_add_solv(repo, fp_cache, 0)) {
700 g_set_error (error,
701 DNF_ERROR,
702 DNF_ERROR_INTERNAL_ERROR,
703 _("repo_add_solv() has failed."));
704 retval = FALSE;
705 goto out;
706 }
707 repoImpl->state_main = _HY_LOADED_CACHE;
708 } else {
709 auto primary = hrepo->getMetadataPath(MD_TYPE_PRIMARY);
710 if (primary.empty()) {
711 // It could happen when repomd file has no "primary" data or they are in unsupported
712 // format like zchunk
713 g_set_error (error,
714 DNF_ERROR,
715 DNF_ERROR_INTERNAL_ERROR,
716 _("loading of MD_TYPE_PRIMARY has failed."));
717 retval = FALSE;
718 goto out;
719 }
720 fp_primary = solv_xfopen(primary.c_str(), "r");
721 assert(fp_primary);
722
723 g_debug("fetching %s", name);
724 if (repo_add_repomdxml(repo, fp_repomd, 0) || \
725 repo_add_rpmmd(repo, fp_primary, 0, 0)) {
726 g_set_error (error,
727 DNF_ERROR,
728 DNF_ERROR_INTERNAL_ERROR,
729 _("repo_add_repomdxml/rpmmd() has failed."));
730 retval = FALSE;
731 goto out;
732 }
733 repoImpl->state_main = _HY_LOADED_FETCH;
734 }
735 out:
736 if (fp_cache)
737 fclose(fp_cache);
738 if (fp_repomd)
739 fclose(fp_repomd);
740 if (fp_primary)
741 fclose(fp_primary);
742 g_free(fn_cache);
743
744 if (retval) {
745 libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(repo);
746 priv->provides_ready = 0;
747 } else
748 repo_free(repo, 1);
749 return retval;
750 }
751
752 /**
753 * dnf_sack_set_cachedir:
754 * @sack: a #DnfSack instance.
755 * @value: a a filesystem path.
756 *
757 * Sets the location to store the metadata cache files.
758 *
759 * Since: 0.7.0
760 */
761 void
dnf_sack_set_cachedir(DnfSack * sack,const gchar * value)762 dnf_sack_set_cachedir (DnfSack *sack, const gchar *value)
763 {
764 DnfSackPrivate *priv = GET_PRIVATE(sack);
765 g_free (priv->cache_dir);
766 priv->cache_dir = g_strdup(value);
767 }
768
769 /**
770 * dnf_sack_set_arch:
771 * @sack: a #DnfSack instance.
772 * @value: an architecture, e.g. "i386", or %NULL for autodetection.
773 * @error: a #GError or %NULL.
774 *
775 * Sets the system architecture to use for the sack. Calling this
776 * function is optional before a dnf_sack_setup() call.
777 *
778 * Returns: %TRUE for success
779 *
780 * Since: 0.7.0
781 */
782 gboolean
dnf_sack_set_arch(DnfSack * sack,const gchar * value,GError ** error)783 dnf_sack_set_arch (DnfSack *sack, const gchar *value, GError **error) try
784 {
785 DnfSackPrivate *priv = GET_PRIVATE(sack);
786 Pool *pool = dnf_sack_get_pool(sack);
787 const char *arch = value;
788 g_autofree gchar *detected = NULL;
789
790 /* autodetect */
791 if (arch == NULL) {
792 if (hy_detect_arch(&detected)) {
793 g_set_error (error,
794 DNF_ERROR,
795 DNF_ERROR_INTERNAL_ERROR,
796 _("failed to auto-detect architecture"));
797 return FALSE;
798 }
799 arch = detected;
800 }
801
802 g_debug("Architecture is: %s", arch);
803 g_free (priv->arch);
804 priv->arch = g_strdup(arch);
805 pool_setdisttype(pool, DISTTYPE_RPM);
806 pool_setarch(pool, arch);
807
808 /* Since one of commits after 0.6.20 libsolv allowes custom arches
809 * which means it will be 'newcoolarch' and 'noarch' always. */
810 priv->have_set_arch = TRUE;
811 return TRUE;
812 } CATCH_TO_GERROR(FALSE)
813
814 /**
815 * dnf_sack_set_all_arch:
816 * @sack: a #DnfSack instance.
817 * @all_arch: new value for all_arch property.
818 *
819 * This is used for controlling whether an arch needs to
820 * be set within libsolv or not.
821 *
822 * Returns: Nothing.
823 *
824 * Since: 0.7.0
825 */
826 void
827 dnf_sack_set_all_arch (DnfSack *sack, gboolean all_arch)
828 {
829 DnfSackPrivate *priv = GET_PRIVATE(sack);
830 priv->all_arch = all_arch;
831 }
832
833 /**
834 * dnf_sack_get_all_arch
835 * @sack: a #DnfSack instance.
836 *
837 * Returns: the state of all_arch.
838 *
839 * Since: 0.7.0
840 */
841 gboolean
dnf_sack_get_all_arch(DnfSack * sack)842 dnf_sack_get_all_arch (DnfSack *sack)
843 {
844 DnfSackPrivate *priv = GET_PRIVATE(sack);
845 return priv->all_arch;
846 }
847
848 /*
849 * dnf_sack_set_allow_vendor_change:
850 * @sack: a #DnfSack instance.
851 * @allow_vendor_change is a boolean.
852 *
853 * Sets the value of allow vendor change to use for
854 * SOLVER_FLAG_ALLOW_VENDORCHANGE flag
855 *
856 * Returns: Nothing.
857 *
858 * Since: 0.54.3
859 *
860 * */
861 void
dnf_sack_set_allow_vendor_change(DnfSack * sack,gboolean allow_vendor_change)862 dnf_sack_set_allow_vendor_change(DnfSack *sack, gboolean allow_vendor_change)
863 {
864 DnfSackPrivate *priv = GET_PRIVATE(sack);
865 priv->allow_vendor_change = allow_vendor_change;
866 }
867
868 /*
869 * dnf_sack_get_allow_vendor_change:
870 * @sack: a #DnfSack instance.
871 * @allow_vendor_change is a boolean.
872 *
873 * Gets the value of allow vendor change to use for
874 * SOLVER_FLAG_ALLOW_VENDORCHANGE flag
875 *
876 * Returns: True if flag set to 1, False if set to 0
877 *
878 * Since: 0.54.3
879 *
880 * */
881 gboolean
dnf_sack_get_allow_vendor_change(DnfSack * sack)882 dnf_sack_get_allow_vendor_change(DnfSack *sack)
883 {
884 DnfSackPrivate *priv = GET_PRIVATE(sack);
885 return priv->allow_vendor_change;
886 }
887
888 /**
889 * dnf_sack_get_arch
890 * @sack: a #DnfSack instance.
891 *
892 * Returns: the state of all_arch.
893 *
894 * Since: 0.16.2
895 */
896 const char *
dnf_sack_get_arch(DnfSack * sack)897 dnf_sack_get_arch (DnfSack *sack)
898 {
899 DnfSackPrivate *priv = GET_PRIVATE(sack);
900 return priv->arch;
901 }
902
903 /**
904 * dnf_sack_set_rootdir:
905 * @sack: a #DnfSack instance.
906 * @value: a directory path, or %NULL.
907 *
908 * Sets the install root location.
909 *
910 * Since: 0.7.0
911 */
912 void
dnf_sack_set_rootdir(DnfSack * sack,const gchar * value)913 dnf_sack_set_rootdir (DnfSack *sack, const gchar *value)
914 {
915 DnfSackPrivate *priv = GET_PRIVATE(sack);
916 pool_set_rootdir(priv->pool, value);
917 /* Don't look for running kernels if we're not operating live on
918 * the current system.
919 */
920 if (g_strcmp0(value, "/") != 0)
921 priv->running_kernel_fn = NULL;
922 }
923
924 /**
925 * dnf_sack_setup:
926 * @sack: a #DnfSack instance.
927 * @flags: optional flags, e.g. %DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR.
928 * @error: a #GError or %NULL.
929 *
930 * Sets up a new package sack, the fundamental hawkey structure.
931 *
932 * Returns: %TRUE for success
933 *
934 * Since: 0.7.0
935 */
936 gboolean
dnf_sack_setup(DnfSack * sack,int flags,GError ** error)937 dnf_sack_setup(DnfSack *sack, int flags, GError **error) try
938 {
939 DnfSackPrivate *priv = GET_PRIVATE(sack);
940 Pool *pool = dnf_sack_get_pool(sack);
941
942 /* we never called dnf_sack_set_cachedir() */
943 if (priv->cache_dir == NULL) {
944 if (geteuid() != 0) {
945 char *username = this_username();
946 char *path = pool_tmpjoin(pool, DEFAULT_CACHE_USER, "-", username);
947 path = pool_tmpappend(pool, path, "-", "XXXXXX");
948 priv->cache_dir = g_strdup(path);
949 g_free(username);
950 } else {
951 priv->cache_dir = g_strdup(DEFAULT_CACHE_ROOT);
952 }
953 }
954
955 /* create the directory */
956 if (flags & DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR) {
957 if (mkcachedir(priv->cache_dir)) {
958 g_set_error (error,
959 DNF_ERROR,
960 DNF_ERROR_FILE_INVALID,
961 _("failed creating cachedir %s"),
962 priv->cache_dir);
963 return FALSE;
964 }
965 }
966
967 /* never called dnf_sack_set_arch(), so autodetect */
968 if (!priv->have_set_arch && !priv->all_arch) {
969 if (!dnf_sack_set_arch (sack, NULL, error))
970 return FALSE;
971 }
972 return TRUE;
973 } CATCH_TO_GERROR(FALSE)
974
975 /**
976 * dnf_sack_evr_cmp:
977 * @sack: a #DnfSack instance.
978 * @evr1: an EVR string.
979 * @evr2: another EVR string.
980 *
981 * Compares one EVR with another using the sack.
982 *
983 * Returns: 0 for equality
984 *
985 * Since: 0.7.0
986 */
987 int
988 dnf_sack_evr_cmp(DnfSack *sack, const char *evr1, const char *evr2)
989 {
990 g_autoptr(DnfSack) _sack = NULL;
991 if (!sack)
992 _sack = dnf_sack_new ();
993 else
994 _sack = static_cast<DnfSack *>(g_object_ref(sack));
995 return pool_evrcmp_str(dnf_sack_get_pool(_sack), evr1, evr2, EVRCMP_COMPARE);
996 }
997
998 /**
999 * dnf_sack_get_cache_dir:
1000 * @sack: a #DnfSack instance.
1001 *
1002 * Gets the cache directory.
1003 *
1004 * Returns: The user-set cache-dir, or %NULL for not set
1005 *
1006 * Since: 0.7.0
1007 */
1008 const char *
dnf_sack_get_cache_dir(DnfSack * sack)1009 dnf_sack_get_cache_dir(DnfSack *sack)
1010 {
1011 DnfSackPrivate *priv = GET_PRIVATE(sack);
1012 return priv->cache_dir;
1013 }
1014
1015 /**
1016 * dnf_sack_get_running_kernel:
1017 * @sack: a #DnfSack instance.
1018 *
1019 * Gets the running kernel.
1020 *
1021 * Returns: a #DnfPackage, or %NULL
1022 *
1023 * Since: 0.7.0
1024 */
1025 DnfPackage *
dnf_sack_get_running_kernel(DnfSack * sack)1026 dnf_sack_get_running_kernel(DnfSack *sack)
1027 {
1028 Id id = dnf_sack_running_kernel(sack);
1029 if (id < 0)
1030 return NULL;
1031 return dnf_package_new(sack, id);
1032 }
1033
1034 /**
1035 * dnf_sack_give_cache_fn:
1036 * @sack: a #DnfSack instance.
1037 * @reponame: a repo name.
1038 * @ext: a file extension
1039 *
1040 * Gets a cache filename.
1041 *
1042 * Returns: a filename
1043 *
1044 * Since: 0.7.0
1045 */
1046 char *
dnf_sack_give_cache_fn(DnfSack * sack,const char * reponame,const char * ext)1047 dnf_sack_give_cache_fn(DnfSack *sack, const char *reponame, const char *ext)
1048 {
1049 DnfSackPrivate *priv = GET_PRIVATE(sack);
1050 assert(reponame);
1051 char *fn = solv_dupjoin(priv->cache_dir, "/", reponame);
1052 if (ext)
1053 return solv_dupappend(fn, ext, ".solvx");
1054 return solv_dupappend(fn, ".solv", NULL);
1055 }
1056
1057 /**
1058 * dnf_sack_list_arches:
1059 * @sack: a #DnfSack instance.
1060 *
1061 * Creates list of architectures
1062 *
1063 * Returns: a list of architectures
1064 *
1065 * Since: 0.7.0
1066 */
1067 const char **
dnf_sack_list_arches(DnfSack * sack)1068 dnf_sack_list_arches(DnfSack *sack)
1069 {
1070 Pool *pool = dnf_sack_get_pool(sack);
1071 const int BLOCK_SIZE = 31;
1072 int c = 0;
1073 const char **ss = NULL;
1074
1075 if (!(pool->id2arch && pool->lastarch))
1076 return NULL;
1077
1078 for (Id id = 0; id <= pool->lastarch; ++id) {
1079 if (!pool->id2arch[id])
1080 continue;
1081 ss = static_cast<const char **>(solv_extend(ss, c, 1, sizeof(char*), BLOCK_SIZE));
1082 ss[c++] = pool_id2str(pool, id);
1083 }
1084 ss = static_cast<const char **>(solv_extend(ss, c, 1, sizeof(char*), BLOCK_SIZE));
1085 ss[c++] = NULL;
1086 return ss;
1087 }
1088
1089 /**
1090 * dnf_sack_set_installonly:
1091 * @sack: a #DnfSack instance.
1092 * @installonly: an array of package names.
1093 *
1094 * Sets the packages to use for installonlyn.
1095 *
1096 * Since: 0.7.0
1097 */
1098 void
dnf_sack_set_installonly(DnfSack * sack,const char ** installonly)1099 dnf_sack_set_installonly(DnfSack *sack, const char **installonly)
1100 {
1101 DnfSackPrivate *priv = GET_PRIVATE(sack);
1102 const char *name;
1103
1104 queue_empty(&priv->installonly);
1105 if (installonly == NULL)
1106 return;
1107 while ((name = *installonly++) != NULL)
1108 queue_pushunique(&priv->installonly, pool_str2id(priv->pool, name, 1));
1109 }
1110
1111 /**
1112 * dnf_sack_get_installonly: (skip)
1113 * @sack: a #DnfSack instance.
1114 *
1115 * Gets the installonlyn packages.
1116 *
1117 * Returns: a Queue
1118 *
1119 * Since: 0.7.0
1120 */
1121 Queue *
dnf_sack_get_installonly(DnfSack * sack)1122 dnf_sack_get_installonly(DnfSack *sack)
1123 {
1124 DnfSackPrivate *priv = GET_PRIVATE(sack);
1125 return &priv->installonly;
1126 }
1127
1128 /**
1129 * dnf_sack_set_installonly_limit:
1130 * @sack: a #DnfSack instance.
1131 * @limit: a the number of packages.
1132 *
1133 * Sets the installonly limit.
1134 *
1135 * Since: 0.7.0
1136 */
1137 void
dnf_sack_set_installonly_limit(DnfSack * sack,guint limit)1138 dnf_sack_set_installonly_limit(DnfSack *sack, guint limit)
1139 {
1140 DnfSackPrivate *priv = GET_PRIVATE(sack);
1141 priv->installonly_limit = limit;
1142 }
1143
1144 /**
1145 * dnf_sack_get_installonly_limit:
1146 * @sack: a #DnfSack instance.
1147 *
1148 * Gets the installonly limit.
1149 *
1150 * Returns: integer value
1151 *
1152 * Since: 0.7.0
1153 */
1154 guint
dnf_sack_get_installonly_limit(DnfSack * sack)1155 dnf_sack_get_installonly_limit(DnfSack *sack)
1156 {
1157 DnfSackPrivate *priv = GET_PRIVATE(sack);
1158 return priv->installonly_limit;
1159 }
1160
1161 static Repo *
dnf_sack_setup_cmdline_repo(DnfSack * sack)1162 dnf_sack_setup_cmdline_repo(DnfSack *sack)
1163 {
1164 DnfSackPrivate *priv = GET_PRIVATE(sack);
1165 if (!priv->cmdline_repo) {
1166 HyRepo hrepo = hy_repo_create(HY_CMDLINE_REPO_NAME);
1167 auto repoImpl = libdnf::repoGetImpl(hrepo);
1168 Repo *repo = repo_create(dnf_sack_get_pool(sack), HY_CMDLINE_REPO_NAME);
1169 repo->appdata = hrepo;
1170 repoImpl->libsolvRepo = repo;
1171 repoImpl->needs_internalizing = 1;
1172 priv->cmdline_repo = repo;
1173 }
1174 return priv->cmdline_repo;
1175 }
1176
1177 DnfPackage *
dnf_sack_add_cmdline_package_flags(DnfSack * sack,const char * fn,const int flags)1178 dnf_sack_add_cmdline_package_flags(DnfSack *sack, const char *fn, const int flags)
1179 {
1180 if (!is_readable_rpm(fn)) {
1181 g_warning("not a readable RPM file: %s, skipping", fn);
1182 return NULL;
1183 }
1184 DnfSackPrivate *priv = GET_PRIVATE(sack);
1185 Repo *repo = dnf_sack_setup_cmdline_repo(sack);
1186 Id p;
1187 priv->provides_ready = 0; /* triggers internalizing later */
1188 p = repo_add_rpm(repo, fn, flags);
1189 if (p == 0) {
1190 g_warning ("failed to read RPM: %s, skipping",
1191 pool_errstr (dnf_sack_get_pool (sack)));
1192 return NULL;
1193 }
1194 auto hrepo = static_cast<HyRepo>(repo->appdata);
1195 libdnf::repoGetImpl(hrepo)->needs_internalizing = 1;
1196 priv->considered_uptodate = FALSE; /* triggers recompute_considered later */
1197 return dnf_package_new(sack, p);
1198 }
1199
1200 /**
1201 * dnf_sack_add_cmdline_package:
1202 * @sack: a #DnfSack instance.
1203 * @fn: a filename.
1204 *
1205 * Adds the given .rpm file to the command line repo.
1206 *
1207 * Returns: a #DnfPackage, or %NULL
1208 *
1209 * Since: 0.7.0
1210 */
1211 DnfPackage *
dnf_sack_add_cmdline_package(DnfSack * sack,const char * fn)1212 dnf_sack_add_cmdline_package(DnfSack *sack, const char *fn)
1213 {
1214 return dnf_sack_add_cmdline_package_flags(sack, fn,
1215 REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|
1216 RPM_ADD_WITH_HDRID|RPM_ADD_WITH_SHA256SUM);
1217 }
1218
1219 DnfPackage *
dnf_sack_add_cmdline_package_nochecksum(DnfSack * sack,const char * fn)1220 dnf_sack_add_cmdline_package_nochecksum(DnfSack *sack, const char *fn)
1221 {
1222 return dnf_sack_add_cmdline_package_flags(sack, fn,
1223 REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
1224 }
1225
1226 /**
1227 * dnf_sack_count:
1228 * @sack: a #DnfSack instance.
1229 *
1230 * Gets the number of items in the sack.
1231 *
1232 * Returns: number of solvables.
1233 *
1234 * Since: 0.7.0
1235 */
1236 int
dnf_sack_count(DnfSack * sack)1237 dnf_sack_count(DnfSack *sack)
1238 {
1239 int cnt = 0;
1240 Id p;
1241 Pool *pool = dnf_sack_get_pool(sack);
1242
1243 FOR_PKG_SOLVABLES(p)
1244 cnt++;
1245 return cnt;
1246 }
1247
1248 static void
dnf_sack_add_excludes_or_includes(DnfSack * sack,Map ** dest,const DnfPackageSet * pkgset)1249 dnf_sack_add_excludes_or_includes(DnfSack *sack, Map **dest, const DnfPackageSet *pkgset)
1250 {
1251 Map *destmap = *dest;
1252 if (destmap == NULL) {
1253 destmap = static_cast<Map *>(g_malloc0(sizeof(Map)));
1254 Pool *pool = dnf_sack_get_pool(sack);
1255 map_init(destmap, pool->nsolvables);
1256 *dest = destmap;
1257 }
1258
1259 auto pkgmap = pkgset->getMap();
1260 map_or(destmap, pkgmap);
1261 DnfSackPrivate *priv = GET_PRIVATE(sack);
1262 priv->considered_uptodate = FALSE;
1263 }
1264
1265 /**
1266 * dnf_sack_add_excludes:
1267 * @sack: a #DnfSack instance.
1268 * @pset: a #DnfPackageSet or %NULL.
1269 *
1270 * Adds excludes to the sack.
1271 *
1272 * Since: 0.7.0
1273 */
1274 void
dnf_sack_add_excludes(DnfSack * sack,const DnfPackageSet * pset)1275 dnf_sack_add_excludes(DnfSack *sack, const DnfPackageSet *pset)
1276 {
1277 DnfSackPrivate *priv = GET_PRIVATE(sack);
1278 dnf_sack_add_excludes_or_includes(sack, &priv->pkg_excludes, pset);
1279 }
1280
1281 /**
1282 * dnf_sack_add_module_excludes:
1283 * @sack: a #DnfSack instance.
1284 * @pset: a #DnfPackageSet or %NULL.
1285 *
1286 * Adds excludes to the sack.
1287 *
1288 * Since: 0.13.4
1289 */
1290 void
dnf_sack_add_module_excludes(DnfSack * sack,const DnfPackageSet * pset)1291 dnf_sack_add_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
1292 {
1293 DnfSackPrivate *priv = GET_PRIVATE(sack);
1294 dnf_sack_add_excludes_or_includes(sack, &priv->module_excludes, pset);
1295 }
1296
1297 /**
1298 * dnf_sack_add_includes:
1299 * @sack: a #DnfSack instance.
1300 * @pset: a #DnfPackageSet or %NULL.
1301 *
1302 * Add includes to the sack.
1303 *
1304 * Since: 0.7.0
1305 */
1306 void
dnf_sack_add_includes(DnfSack * sack,const DnfPackageSet * pset)1307 dnf_sack_add_includes(DnfSack *sack, const DnfPackageSet *pset)
1308 {
1309 DnfSackPrivate *priv = GET_PRIVATE(sack);
1310 dnf_sack_add_excludes_or_includes(sack, &priv->pkg_includes, pset);
1311 }
1312
1313 static void
dnf_sack_remove_excludes_or_includes(DnfSack * sack,Map * from,const DnfPackageSet * pkgset)1314 dnf_sack_remove_excludes_or_includes(DnfSack *sack, Map *from, const DnfPackageSet *pkgset)
1315 {
1316 if (from == NULL)
1317 return;
1318 auto pkgmap = pkgset->getMap();
1319 map_subtract(from, pkgmap);
1320 DnfSackPrivate *priv = GET_PRIVATE(sack);
1321 priv->considered_uptodate = FALSE;
1322 }
1323
1324 /**
1325 * dnf_sack_remove_excludes:
1326 * @sack: a #DnfSack instance.
1327 * @pset: a #DnfPackageSet or %NULL.
1328 *
1329 * Removes excludes from the sack.
1330 *
1331 * Since: 0.9.4
1332 */
1333 void
dnf_sack_remove_excludes(DnfSack * sack,const DnfPackageSet * pset)1334 dnf_sack_remove_excludes(DnfSack *sack, const DnfPackageSet *pset)
1335 {
1336 DnfSackPrivate *priv = GET_PRIVATE(sack);
1337 dnf_sack_remove_excludes_or_includes(sack, priv->pkg_excludes, pset);
1338 }
1339
1340 /**
1341 * dnf_sack_remove_module_excludes:
1342 * @sack: a #DnfSack instance.
1343 * @pset: a #DnfPackageSet or %NULL.
1344 *
1345 * Removes excludes from the sack.
1346 *
1347 * Since: 0.13.4
1348 */
1349 void
dnf_sack_remove_module_excludes(DnfSack * sack,const DnfPackageSet * pset)1350 dnf_sack_remove_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
1351 {
1352 DnfSackPrivate *priv = GET_PRIVATE(sack);
1353 dnf_sack_remove_excludes_or_includes(sack, priv->module_excludes, pset);
1354 }
1355
1356 /**
1357 * dnf_sack_remove_includes:
1358 * @sack: a #DnfSack instance.
1359 * @pset: a #DnfPackageSet or %NULL.
1360 *
1361 * Removes includes from the sack.
1362 *
1363 * Since: 0.9.4
1364 */
1365 void
dnf_sack_remove_includes(DnfSack * sack,const DnfPackageSet * pset)1366 dnf_sack_remove_includes(DnfSack *sack, const DnfPackageSet *pset)
1367 {
1368 DnfSackPrivate *priv = GET_PRIVATE(sack);
1369 dnf_sack_remove_excludes_or_includes(sack, priv->pkg_includes, pset);
1370 }
1371
1372 static void
dnf_sack_set_excludes_or_includes(DnfSack * sack,Map ** dest,const DnfPackageSet * pkgset)1373 dnf_sack_set_excludes_or_includes(DnfSack *sack, Map **dest, const DnfPackageSet *pkgset)
1374 {
1375 if (*dest == NULL && pkgset == NULL)
1376 return;
1377
1378 *dest = free_map_fully(*dest);
1379 if (pkgset) {
1380 *dest = static_cast<Map *>(g_malloc0(sizeof(Map)));
1381 auto pkgmap = pkgset->getMap();
1382 map_init_clone(*dest, pkgmap);
1383 }
1384 DnfSackPrivate *priv = GET_PRIVATE(sack);
1385 priv->considered_uptodate = FALSE;
1386 }
1387
1388 void
dnf_sack_set_module_includes(DnfSack * sack,const DnfPackageSet * pset)1389 dnf_sack_set_module_includes(DnfSack *sack, const DnfPackageSet *pset)
1390 {
1391 if (!pset) {
1392 return;
1393 }
1394 DnfSackPrivate *priv = GET_PRIVATE(sack);
1395 free_map_fully(priv->module_includes);
1396 priv->module_includes = static_cast<Map *>(g_malloc0(sizeof(Map)));
1397 auto pkgmap = pset->getMap();
1398 map_init_clone(priv->module_includes, pkgmap);
1399 }
1400
1401 /**
1402 * dnf_sack_set_excludes:
1403 * @sack: a #DnfSack instance.
1404 * @pset: a #DnfPackageSet or %NULL.
1405 *
1406 * Set excludes for the sack.
1407 *
1408 * Since: 0.7.0
1409 */
1410 void
dnf_sack_set_excludes(DnfSack * sack,const DnfPackageSet * pset)1411 dnf_sack_set_excludes(DnfSack *sack, const DnfPackageSet *pset)
1412 {
1413 DnfSackPrivate *priv = GET_PRIVATE(sack);
1414 dnf_sack_set_excludes_or_includes(sack, &priv->pkg_excludes, pset);
1415 }
1416
1417 /**
1418 * dnf_sack_set_module_excludes:
1419 * @sack: a #DnfSack instance.
1420 * @pset: a #DnfPackageSet or %NULL.
1421 *
1422 * Set excludes for the sack.
1423 *
1424 * Since: 0.13.4
1425 */
1426 void
dnf_sack_set_module_excludes(DnfSack * sack,const DnfPackageSet * pset)1427 dnf_sack_set_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
1428 {
1429 DnfSackPrivate *priv = GET_PRIVATE(sack);
1430 dnf_sack_set_excludes_or_includes(sack, &priv->module_excludes, pset);
1431 }
1432
1433 /**
1434 * dnf_sack_set_includes:
1435 * @sack: a #DnfSack instance.
1436 * @pset: a #DnfPackageSet or %NULL.
1437 *
1438 * Set any sack includes.
1439 *
1440 * Since: 0.7.0
1441 */
1442 void
dnf_sack_set_includes(DnfSack * sack,const DnfPackageSet * pset)1443 dnf_sack_set_includes(DnfSack *sack, const DnfPackageSet *pset)
1444 {
1445 DnfSackPrivate *priv = GET_PRIVATE(sack);
1446 dnf_sack_set_excludes_or_includes(sack, &priv->pkg_includes, pset);
1447 }
1448
1449 /**
1450 * dnf_sack_reset_excludes:
1451 * @sack: a #DnfSack instance.
1452 *
1453 * Reset excludes (remove excludes map from memory).
1454 *
1455 * Since: 0.9.4
1456 */
1457 void
dnf_sack_reset_excludes(DnfSack * sack)1458 dnf_sack_reset_excludes(DnfSack *sack)
1459 {
1460 dnf_sack_set_excludes(sack, NULL);
1461 }
1462
1463 /**
1464 * dnf_sack_reset_module_excludes:
1465 * @sack: a #DnfSack instance.
1466 *
1467 * Reset excludes (remove excludes map from memory).
1468 *
1469 * Since: 0.13.4
1470 */
1471 void
dnf_sack_reset_module_excludes(DnfSack * sack)1472 dnf_sack_reset_module_excludes(DnfSack *sack)
1473 {
1474 dnf_sack_set_module_excludes(sack, NULL);
1475 }
1476
1477 /**
1478 * dnf_sack_reset_includes:
1479 * @sack: a #DnfSack instance.
1480 *
1481 * Reset includes (remove includes map from memory).
1482 *
1483 * Since: 0.9.4
1484 */
1485 void
dnf_sack_reset_includes(DnfSack * sack)1486 dnf_sack_reset_includes(DnfSack *sack)
1487 {
1488 dnf_sack_set_includes(sack, NULL);
1489 }
1490
1491 /**
1492 * dnf_sack_get_excludes:
1493 * @sack: a #DnfSack instance.
1494 * @pset: a #DnfPackageSet or %NULL.
1495 *
1496 * Gets sack excludes.
1497 *
1498 * Since: 0.9.4
1499 */
1500 DnfPackageSet *
dnf_sack_get_excludes(DnfSack * sack)1501 dnf_sack_get_excludes(DnfSack *sack)
1502 {
1503 DnfSackPrivate *priv = GET_PRIVATE(sack);
1504 Map *excl = priv->pkg_excludes;
1505 return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
1506 }
1507
1508 /**
1509 * dnf_sack_get_module_excludes:
1510 * @sack: a #DnfSack instance.
1511 * @pset: a #DnfPackageSet or %NULL.
1512 *
1513 * Gets sack excludes.
1514 *
1515 * Since: 0.13.4
1516 */
1517 DnfPackageSet *
dnf_sack_get_module_excludes(DnfSack * sack)1518 dnf_sack_get_module_excludes(DnfSack *sack)
1519 {
1520 DnfSackPrivate *priv = GET_PRIVATE(sack);
1521 Map *excl = priv->module_excludes;
1522 return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
1523 }
1524
1525 /**
1526 * dnf_sack_get_module_includes:
1527 * @sack: a #DnfSack instance.
1528 * @pset: a #DnfPackageSet or %NULL.
1529 *
1530 * Since: 0.16.1
1531 */
1532 DnfPackageSet *
dnf_sack_get_module_includes(DnfSack * sack)1533 dnf_sack_get_module_includes(DnfSack *sack)
1534 {
1535 DnfSackPrivate *priv = GET_PRIVATE(sack);
1536 Map *excl = priv->module_includes;
1537 return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
1538 }
1539
1540 /**
1541 * dnf_sack_get_includes:
1542 * @sack: a #DnfSack instance.
1543 *
1544 * Gets sack includes.
1545 *
1546 * Since: 0.9.4
1547 */
1548 DnfPackageSet *
dnf_sack_get_includes(DnfSack * sack)1549 dnf_sack_get_includes(DnfSack *sack)
1550 {
1551 DnfSackPrivate *priv = GET_PRIVATE(sack);
1552 Map *incl = priv->pkg_includes;
1553 return incl ? dnf_packageset_from_bitmap(sack, incl) : NULL;
1554 }
1555
1556 /**
1557 * dnf_sack_set_use_includes:
1558 * @sack: a #DnfSack instance.
1559 * @repo_name: a name of repo or %NULL for all repos.
1560 * @enabled: a use includes for a repo or all repos.
1561 *
1562 * Enable/disable usage of includes for repo/all-repos.
1563 *
1564 * Returns: FALSE if error occurred (unknown reponame) else TRUE.
1565 *
1566 * Since: 0.9.4
1567 */
1568 gboolean
dnf_sack_set_use_includes(DnfSack * sack,const char * reponame,gboolean enabled)1569 dnf_sack_set_use_includes(DnfSack *sack, const char *reponame, gboolean enabled)
1570 {
1571 DnfSackPrivate *priv = GET_PRIVATE(sack);
1572 Pool *pool = dnf_sack_get_pool(sack);
1573
1574 if (reponame) {
1575 HyRepo hyrepo = hrepo_by_name(sack, reponame);
1576 if (!hyrepo)
1577 return FALSE;
1578 if (hyrepo->getUseIncludes() != enabled)
1579 {
1580 hyrepo->setUseIncludes(enabled);
1581 priv->considered_uptodate = FALSE;
1582 }
1583 } else {
1584 Id repoid;
1585 Repo *repo;
1586 FOR_REPOS(repoid, repo) {
1587 auto hyrepo = static_cast<HyRepo>(pool->repos[repoid]->appdata);
1588 if (hyrepo->getUseIncludes() != enabled)
1589 {
1590 hyrepo->setUseIncludes(enabled);
1591 priv->considered_uptodate = FALSE;
1592 }
1593 }
1594 }
1595 return TRUE;
1596 }
1597
1598 /**
1599 * dnf_sack_set_provides_not_ready:
1600 * @sack: a #DnfSack instance.
1601 *
1602 * Mark sack to recompute provides
1603 *
1604 * Since: 0.16.3
1605 */
1606 void
dnf_sack_set_provides_not_ready(DnfSack * sack)1607 dnf_sack_set_provides_not_ready(DnfSack *sack)
1608 {
1609 DnfSackPrivate *priv = GET_PRIVATE(sack);
1610 priv->provides_ready = FALSE;
1611 }
1612
1613 /**
1614 * dnf_sack_set_considered_to_update:
1615 * @sack: a #DnfSack instance.
1616 *
1617 * Mark sack to recompute considered
1618 *
1619 * Since: 0.16.3
1620 */
1621 void
dnf_sack_set_considered_to_update(DnfSack * sack)1622 dnf_sack_set_considered_to_update(DnfSack *sack)
1623 {
1624 DnfSackPrivate *priv = GET_PRIVATE(sack);
1625 priv->considered_uptodate = FALSE;
1626 }
1627
1628 /**
1629 * dnf_sack_get_use_includes:
1630 * @sack: a #DnfSack instance.
1631 * @repo_name: a name of repo or %NULL for all repos.
1632 * @enabled: a returned state of includes for repo
1633 *
1634 * Enable/disable usage of includes for repo/all-repos.
1635 *
1636 * Returns: FALSE if error occurred (unknown reponame) else TRUE.
1637 *
1638 * Since: 0.9.4
1639 */
1640 gboolean
dnf_sack_get_use_includes(DnfSack * sack,const char * reponame,gboolean * enabled)1641 dnf_sack_get_use_includes(DnfSack *sack, const char *reponame, gboolean *enabled)
1642 {
1643 assert(reponame);
1644 HyRepo hyrepo = hrepo_by_name(sack, reponame);
1645 if (!hyrepo)
1646 return FALSE;
1647 *enabled = hyrepo->getUseIncludes();
1648 return TRUE;
1649 }
1650
1651 /**
1652 * dnf_sack_repo_enabled:
1653 * @sack: a #DnfSack instance.
1654 * @reponame: a repo name.
1655 * @enabled: the enabled state.
1656 *
1657 * Enable repository
1658 *
1659 * Returns: %TRUE for success
1660 *
1661 * Since: 0.7.0
1662 */
1663 int
dnf_sack_repo_enabled(DnfSack * sack,const char * reponame,int enabled)1664 dnf_sack_repo_enabled(DnfSack *sack, const char *reponame, int enabled)
1665 {
1666 DnfSackPrivate *priv = GET_PRIVATE(sack);
1667 Pool *pool = dnf_sack_get_pool(sack);
1668 Repo *repo = repo_by_name(sack, reponame);
1669 Map *excl = priv->repo_excludes;
1670
1671 if (repo == NULL)
1672 return DNF_ERROR_INTERNAL_ERROR;
1673 if (excl == NULL) {
1674 excl = static_cast<Map *>(g_malloc0(sizeof(Map)));
1675 map_init(excl, pool->nsolvables);
1676 priv->repo_excludes = excl;
1677 }
1678 repo->disabled = !enabled;
1679 priv->provides_ready = 0;
1680
1681 Id p;
1682 Solvable *s;
1683 if (repo->disabled)
1684 FOR_REPO_SOLVABLES(repo, p, s)
1685 MAPSET(priv->repo_excludes, p);
1686 else
1687 FOR_REPO_SOLVABLES(repo, p, s)
1688 MAPCLR(priv->repo_excludes, p);
1689 priv->considered_uptodate = FALSE;
1690 return 0;
1691 }
1692
1693 /**
1694 * dnf_sack_load_system_repo:
1695 * @sack: a #DnfSack instance.
1696 * @a_hrepo: a rpmdb repo.
1697 * @flags: what to load into the sack, e.g. %DNF_SACK_LOAD_FLAG_USE_FILELISTS.
1698 * @error: a #GError or %NULL.
1699 *
1700 * Loads the rpmdb into the sack.
1701 *
1702 * Returns: %TRUE for success
1703 *
1704 * Since: 0.7.0
1705 */
1706 gboolean
dnf_sack_load_system_repo(DnfSack * sack,HyRepo a_hrepo,int flags,GError ** error)1707 dnf_sack_load_system_repo(DnfSack *sack, HyRepo a_hrepo, int flags, GError **error) try
1708 {
1709 DnfSackPrivate *priv = GET_PRIVATE(sack);
1710 Pool *pool = dnf_sack_get_pool(sack);
1711 gboolean ret = TRUE;
1712 HyRepo hrepo = a_hrepo;
1713 Repo *repo;
1714
1715 if (hrepo) {
1716 auto repoImpl = libdnf::repoGetImpl(hrepo);
1717 repoImpl->id = HY_SYSTEM_REPO_NAME;
1718 repoImpl->conf->name().set(libdnf::Option::Priority::RUNTIME, HY_SYSTEM_REPO_NAME);
1719 } else
1720 hrepo = hy_repo_create(HY_SYSTEM_REPO_NAME);
1721 auto repoImpl = libdnf::repoGetImpl(hrepo);
1722
1723 repoImpl->load_flags = flags &= ~DNF_SACK_LOAD_FLAG_BUILD_CACHE;
1724
1725 repo = repo_create(pool, HY_SYSTEM_REPO_NAME);
1726
1727 g_debug("fetching rpmdb");
1728 int flagsrpm = REPO_REUSE_REPODATA | RPM_ADD_WITH_HDRID | REPO_USE_ROOTDIR;
1729 int rc = repo_add_rpmdb_reffp(repo, NULL, flagsrpm);
1730 if (!rc) {
1731 repoImpl->state_main = _HY_LOADED_FETCH;
1732 } else {
1733 repo_free(repo, 1);
1734 ret = FALSE;
1735 g_set_error (error,
1736 DNF_ERROR,
1737 DNF_ERROR_FILE_INVALID,
1738 _("failed loading RPMDB"));
1739 goto finish;
1740 }
1741
1742 libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(repo);
1743 pool_set_installed(pool, repo);
1744 priv->provides_ready = 0;
1745
1746 repoImpl->main_nsolvables = repo->nsolvables;
1747 repoImpl->main_nrepodata = repo->nrepodata;
1748 repoImpl->main_end = repo->end;
1749 priv->considered_uptodate = FALSE;
1750
1751 finish:
1752 if (a_hrepo == NULL)
1753 hy_repo_free(hrepo);
1754 return ret;
1755 } CATCH_TO_GERROR(FALSE)
1756
1757 /**
1758 * dnf_sack_load_repo:
1759 * @sack: a #DnfSack instance.
1760 * @repo: a #HyRepo.
1761 * @flags: what to load into the sack, e.g. %DNF_SACK_LOAD_FLAG_USE_FILELISTS.
1762 * @error: a #GError, or %NULL.
1763 *
1764 * Loads a remote repo into the sack.
1765 *
1766 * Returns: %TRUE for success
1767 *
1768 * Since: 0.7.0
1769 */
1770 gboolean
1771 dnf_sack_load_repo(DnfSack *sack, HyRepo repo, int flags, GError **error) try
1772 {
1773 DnfSackPrivate *priv = GET_PRIVATE(sack);
1774 auto repoImpl = libdnf::repoGetImpl(repo);
1775 GError *error_local = NULL;
1776 const int build_cache = flags & DNF_SACK_LOAD_FLAG_BUILD_CACHE;
1777 gboolean retval;
1778 if (!load_yum_repo(sack, repo, error))
1779 return FALSE;
1780 repoImpl->load_flags = flags;
1781 if (repoImpl->state_main == _HY_LOADED_FETCH && build_cache) {
1782 if (!write_main(sack, repo, 1, error))
1783 return FALSE;
1784 }
1785 repoImpl->main_nsolvables = repoImpl->libsolvRepo->nsolvables;
1786 repoImpl->main_nrepodata = repoImpl->libsolvRepo->nrepodata;
1787 repoImpl->main_end = repoImpl->libsolvRepo->end;
1788 if (flags & DNF_SACK_LOAD_FLAG_USE_FILELISTS) {
1789 retval = load_ext(sack, repo, _HY_REPODATA_FILENAMES,
1790 HY_EXT_FILENAMES, MD_TYPE_FILELISTS,
1791 load_filelists_cb, &error_local);
1792 /* allow missing files */
1793 if (!retval) {
1794 if (g_error_matches (error_local,
1795 DNF_ERROR,
1796 DNF_ERROR_NO_CAPABILITY)) {
1797 g_debug("no filelists metadata available for %s", repoImpl->conf->name().getValue().c_str());
1798 g_clear_error (&error_local);
1799 } else {
1800 g_propagate_error (error, error_local);
1801 return FALSE;
1802 }
1803 }
1804 if (repoImpl->state_filelists == _HY_LOADED_FETCH && build_cache) {
1805 if (!write_ext(sack, repo,
1806 _HY_REPODATA_FILENAMES,
1807 HY_EXT_FILENAMES, error))
1808 return FALSE;
1809 }
1810 }
1811 if (flags & DNF_SACK_LOAD_FLAG_USE_OTHER) {
1812 retval = load_ext(sack, repo, _HY_REPODATA_OTHER,
1813 HY_EXT_OTHER, MD_TYPE_OTHER,
1814 load_other_cb, &error_local);
1815 /* allow missing files */
1816 if (!retval) {
1817 if (g_error_matches (error_local,
1818 DNF_ERROR,
1819 DNF_ERROR_NO_CAPABILITY)) {
1820 g_debug("no other metadata available for %s", repoImpl->conf->name().getValue().c_str());
1821 g_clear_error (&error_local);
1822 } else {
1823 g_propagate_error (error, error_local);
1824 return FALSE;
1825 }
1826 }
1827 if (repoImpl->state_other == _HY_LOADED_FETCH && build_cache) {
1828 if (!write_ext(sack, repo,
1829 _HY_REPODATA_OTHER,
1830 HY_EXT_OTHER, error))
1831 return FALSE;
1832 }
1833 }
1834 if (flags & DNF_SACK_LOAD_FLAG_USE_PRESTO) {
1835 retval = load_ext(sack, repo, _HY_REPODATA_PRESTO,
1836 HY_EXT_PRESTO, MD_TYPE_PRESTODELTA,
1837 load_presto_cb, &error_local);
1838 if (!retval) {
1839 if (g_error_matches (error_local,
1840 DNF_ERROR,
1841 DNF_ERROR_NO_CAPABILITY)) {
1842 g_debug("no presto metadata available for %s", repoImpl->conf->name().getValue().c_str());
1843 g_clear_error (&error_local);
1844 } else {
1845 g_propagate_error (error, error_local);
1846 return FALSE;
1847 }
1848 }
1849 if (repoImpl->state_presto == _HY_LOADED_FETCH && build_cache)
1850 if (!write_ext(sack, repo, _HY_REPODATA_PRESTO, HY_EXT_PRESTO, error))
1851 return FALSE;
1852 }
1853 /* updateinfo must come *after* all other extensions, as it is not a real
1854 extension, but contains a new set of packages */
1855 if (flags & DNF_SACK_LOAD_FLAG_USE_UPDATEINFO) {
1856 retval = load_ext(sack, repo, _HY_REPODATA_UPDATEINFO,
1857 HY_EXT_UPDATEINFO, MD_TYPE_UPDATEINFO,
1858 load_updateinfo_cb, &error_local);
1859 /* allow missing files */
1860 if (!retval) {
1861 if (g_error_matches (error_local,
1862 DNF_ERROR,
1863 DNF_ERROR_NO_CAPABILITY)) {
1864 g_debug("no updateinfo available for %s", repoImpl->conf->name().getValue().c_str());
1865 g_clear_error (&error_local);
1866 } else {
1867 g_propagate_error (error, error_local);
1868 return FALSE;
1869 }
1870 }
1871 if (repoImpl->state_updateinfo == _HY_LOADED_FETCH && build_cache)
1872 if (!write_ext(sack, repo, _HY_REPODATA_UPDATEINFO, HY_EXT_UPDATEINFO, error))
1873 return FALSE;
1874 }
1875 priv->considered_uptodate = FALSE;
1876 return TRUE;
CATCH_TO_GERROR(FALSE)1877 } CATCH_TO_GERROR(FALSE)
1878
1879 // internal to hawkey
1880
1881 // return true if q1 is a superset of q2
1882 // only works if there are no duplicates both in q1 and q2
1883 // the map parameter must point to an empty map that can hold all ids
1884 // (it is also returned empty)
1885 static int
1886 is_superset(Queue *q1, Queue *q2, Map *m)
1887 {
1888 int i, cnt = 0;
1889 for (i = 0; i < q2->count; i++)
1890 MAPSET(m, q2->elements[i]);
1891 for (i = 0; i < q1->count; i++)
1892 if (MAPTST(m, q1->elements[i]))
1893 cnt++;
1894 for (i = 0; i < q2->count; i++)
1895 MAPCLR(m, q2->elements[i]);
1896 return cnt == q2->count;
1897 }
1898
1899
1900 static void
rewrite_repos(DnfSack * sack,Queue * addedfileprovides,Queue * addedfileprovides_inst)1901 rewrite_repos(DnfSack *sack, Queue *addedfileprovides,
1902 Queue *addedfileprovides_inst)
1903 {
1904 Pool *pool = dnf_sack_get_pool(sack);
1905 int i;
1906
1907 Map providedids;
1908 map_init(&providedids, pool->ss.nstrings);
1909
1910 Queue fileprovidesq;
1911 queue_init(&fileprovidesq);
1912
1913 Repo *repo;
1914 FOR_REPOS(i, repo) {
1915 auto hrepo = static_cast<HyRepo>(repo->appdata);
1916 if (!hrepo)
1917 continue;
1918 auto repoImpl = libdnf::repoGetImpl(hrepo);
1919 if (!(repoImpl->load_flags & DNF_SACK_LOAD_FLAG_BUILD_CACHE))
1920 continue;
1921 if (repoImpl->main_nrepodata < 2)
1922 continue;
1923 /* now check if the repo already contains all of our file provides */
1924 Queue *addedq = repo == pool->installed && addedfileprovides_inst ?
1925 addedfileprovides_inst : addedfileprovides;
1926 if (!addedq->count)
1927 continue;
1928 Repodata *data = repo_id2repodata(repo, 1);
1929 queue_empty(&fileprovidesq);
1930 if (repodata_lookup_idarray(data, SOLVID_META,
1931 REPOSITORY_ADDEDFILEPROVIDES,
1932 &fileprovidesq)) {
1933 if (is_superset(&fileprovidesq, addedq, &providedids))
1934 continue;
1935 }
1936 repodata_set_idarray(data, SOLVID_META,
1937 REPOSITORY_ADDEDFILEPROVIDES, addedq);
1938 repodata_internalize(data);
1939 /* re-write main data only */
1940 int oldnrepodata = repo->nrepodata;
1941 int oldnsolvables = repo->nsolvables;
1942 int oldend = repo->end;
1943 repo->nrepodata = repoImpl->main_nrepodata;
1944 repo->nsolvables = repoImpl->main_nsolvables;
1945 repo->end = repoImpl->main_end;
1946 g_debug("rewriting repo: %s", repo->name);
1947 write_main(sack, hrepo, 0, NULL);
1948 repo->nrepodata = oldnrepodata;
1949 repo->nsolvables = oldnsolvables;
1950 repo->end = oldend;
1951 }
1952 queue_free(&fileprovidesq);
1953 map_free(&providedids);
1954 }
1955
1956 /**
1957 * dnf_sack_make_provides_ready:
1958 * @sack: a #DnfSack instance.
1959 *
1960 * Gets the sack ready for depsolving.
1961 *
1962 * Since: 0.7.0
1963 */
1964 void
dnf_sack_make_provides_ready(DnfSack * sack)1965 dnf_sack_make_provides_ready(DnfSack *sack)
1966 {
1967 DnfSackPrivate *priv = GET_PRIVATE(sack);
1968
1969 if (priv->provides_ready)
1970 return;
1971 repo_internalize_all_trigger(priv->pool);
1972 Queue addedfileprovides;
1973 Queue addedfileprovides_inst;
1974 queue_init(&addedfileprovides);
1975 queue_init(&addedfileprovides_inst);
1976 pool_addfileprovides_queue(priv->pool, &addedfileprovides,
1977 &addedfileprovides_inst);
1978 if (addedfileprovides.count || addedfileprovides_inst.count)
1979 rewrite_repos(sack, &addedfileprovides, &addedfileprovides_inst);
1980 queue_free(&addedfileprovides);
1981 queue_free(&addedfileprovides_inst);
1982 pool_createwhatprovides(priv->pool);
1983 priv->provides_ready = 1;
1984 }
1985
1986 /**
1987 * dnf_sack_running_kernel: (skip)
1988 * @sack: a #DnfSack instance.
1989 *
1990 * Returns the ID of the running kernel.
1991 *
1992 * Returns: an #Id or 0
1993 *
1994 * Since: 0.7.0
1995 */
1996 Id
dnf_sack_running_kernel(DnfSack * sack)1997 dnf_sack_running_kernel(DnfSack *sack)
1998 {
1999 DnfSackPrivate *priv = GET_PRIVATE(sack);
2000 if (priv->running_kernel_id >= 0)
2001 return priv->running_kernel_id;
2002 if (priv->running_kernel_fn)
2003 priv->running_kernel_id = priv->running_kernel_fn(sack);
2004 return priv->running_kernel_id;
2005 }
2006
2007 /**
2008 * dnf_sack_get_pool: (skip)
2009 * @sack: a #DnfSack instance.
2010 *
2011 * Gets the internal pool for the sack.
2012 *
2013 * Returns: The pool, which is always set
2014 *
2015 * Since: 0.7.0
2016 */
2017 Pool *
dnf_sack_get_pool(DnfSack * sack)2018 dnf_sack_get_pool(DnfSack *sack)
2019 {
2020 DnfSackPrivate *priv = GET_PRIVATE(sack);
2021 return priv->pool;
2022 }
2023
2024 /**
2025 * dnf_sack_set_module_container: (skip)
2026 * @sack: a #DnfSack instance.
2027 *
2028 * Sets the internal ModulePackageContainer.
2029 *
2030 * Returns: The old ModulePackageContainer, that has to be freed manually.
2031 *
2032 * Since: 0.31.0
2033 */
2034 libdnf::ModulePackageContainer *
dnf_sack_set_module_container(DnfSack * sack,libdnf::ModulePackageContainer * newConteiner)2035 dnf_sack_set_module_container(DnfSack *sack, libdnf::ModulePackageContainer * newConteiner)
2036 {
2037 DnfSackPrivate *priv = GET_PRIVATE(sack);
2038 auto oldConteiner = priv->moduleContainer;
2039 priv->moduleContainer = newConteiner;
2040 return oldConteiner;
2041 }
2042
2043 /**
2044 * dnf_sack_get_module_container: (skip)
2045 * @sack: a #DnfSack instance.
2046 *
2047 * Gets the internal ModulePackageContainer.
2048 *
2049 * Returns: The ModulePackageContainer, that can be not set
2050 *
2051 * Since: 0.16.3
2052 */
2053 libdnf::ModulePackageContainer *
dnf_sack_get_module_container(DnfSack * sack)2054 dnf_sack_get_module_container(DnfSack *sack)
2055 {
2056 DnfSackPrivate *priv = GET_PRIVATE(sack);
2057 return priv->moduleContainer;
2058 }
2059
2060 /**********************************************************************/
2061
2062 static void
process_excludes(DnfSack * sack,GPtrArray * enabled_repos)2063 process_excludes(DnfSack *sack, GPtrArray *enabled_repos)
2064 {
2065 auto & mainConf = libdnf::getGlobalMainConfig();
2066 auto & disabled = mainConf.disable_excludes().getValue();
2067
2068 if (std::find(disabled.begin(), disabled.end(), "all") != disabled.end()) {
2069 return;
2070 }
2071
2072 libdnf::PackageSet repoIncludes(sack);
2073 libdnf::PackageSet repoExcludes(sack);
2074 bool includesExist = false;
2075
2076 for (guint i = 0; i < enabled_repos->len; i++) {
2077 auto dnfRepo = static_cast<DnfRepo *>(enabled_repos->pdata[i]);
2078 auto repo = dnf_repo_get_repo(dnfRepo);
2079 if (std::find(disabled.begin(), disabled.end(), repo->getId()) != disabled.end()) {
2080 continue;
2081 }
2082
2083 libdnf::Query repoQuery(sack);
2084 repoQuery.addFilter(HY_PKG_REPONAME, HY_EQ, repo->getId().c_str());
2085 repoQuery.apply();
2086
2087 for (const auto & name : repo->getConfig()->includepkgs().getValue()) {
2088 libdnf::Query query(repoQuery);
2089 auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2090 if (ret.first) {
2091 repoIncludes += *query.runSet();
2092 includesExist = true;
2093 repo->setUseIncludes(true);
2094 }
2095 }
2096
2097 for (const auto & name : repo->getConfig()->excludepkgs().getValue()) {
2098 libdnf::Query query(repoQuery);
2099 auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2100 if (ret.first) {
2101 repoExcludes += *query.runSet();
2102 }
2103 }
2104 }
2105
2106 if (std::find(disabled.begin(), disabled.end(), "main") == disabled.end()) {
2107 bool useGlobalIncludes = false;
2108 for (const auto & name : mainConf.includepkgs().getValue()) {
2109 libdnf::Query query(sack);
2110 auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2111 if (ret.first) {
2112 repoIncludes += *query.runSet();
2113 includesExist = true;
2114 useGlobalIncludes = true;
2115 }
2116 }
2117
2118 for (const auto & name : mainConf.excludepkgs().getValue()) {
2119 libdnf::Query query(sack);
2120 auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2121 if (ret.first) {
2122 repoExcludes += *query.runSet();
2123 }
2124 }
2125
2126 if (useGlobalIncludes) {
2127 dnf_sack_set_use_includes(sack, nullptr, true);
2128 }
2129 }
2130
2131 if (includesExist) {
2132 dnf_sack_add_includes(sack, &repoIncludes);
2133 }
2134 dnf_sack_add_excludes(sack, &repoExcludes);
2135 }
2136
2137 /**
2138 * dnf_sack_add_repo:
2139 */
2140 gboolean
dnf_sack_add_repo(DnfSack * sack,DnfRepo * repo,guint permissible_cache_age,DnfSackAddFlags flags,DnfState * state,GError ** error)2141 dnf_sack_add_repo(DnfSack *sack,
2142 DnfRepo *repo,
2143 guint permissible_cache_age,
2144 DnfSackAddFlags flags,
2145 DnfState *state,
2146 GError **error) try
2147 {
2148 gboolean ret = TRUE;
2149 GError *error_local = NULL;
2150 DnfState *state_local;
2151 int flags_hy = DNF_SACK_LOAD_FLAG_BUILD_CACHE;
2152
2153 /* set state */
2154 ret = dnf_state_set_steps(state, error,
2155 5, /* check repo */
2156 95, /* load solv */
2157 -1);
2158 if (!ret)
2159 return FALSE;
2160
2161 /* check repo */
2162 state_local = dnf_state_get_child(state);
2163 ret = dnf_repo_check(repo,
2164 permissible_cache_age,
2165 state_local,
2166 &error_local);
2167 if (!ret) {
2168 g_debug("failed to check, attempting update: %s",
2169 error_local->message);
2170 g_clear_error(&error_local);
2171 dnf_state_reset(state_local);
2172 ret = dnf_repo_update(repo,
2173 DNF_REPO_UPDATE_FLAG_FORCE,
2174 state_local,
2175 &error_local);
2176 if (!ret) {
2177 if (!dnf_repo_get_required(repo) &&
2178 (g_error_matches(error_local,
2179 DNF_ERROR,
2180 DNF_ERROR_CANNOT_FETCH_SOURCE) ||
2181 g_error_matches(error_local,
2182 DNF_ERROR,
2183 DNF_ERROR_REPO_NOT_AVAILABLE))) {
2184 g_warning("Skipping refresh of %s: %s",
2185 dnf_repo_get_id(repo),
2186 error_local->message);
2187 g_error_free(error_local);
2188 return dnf_state_finished(state, error);
2189 }
2190 g_propagate_error(error, error_local);
2191 return FALSE;
2192 }
2193 }
2194
2195 /* checking disabled the repo */
2196 if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE) {
2197 g_debug("Skipping %s as repo no longer enabled",
2198 dnf_repo_get_id(repo));
2199 return dnf_state_finished(state, error);
2200 }
2201
2202 /* done */
2203 if (!dnf_state_done(state, error))
2204 return FALSE;
2205
2206 /* only load what's required */
2207 if ((flags & DNF_SACK_ADD_FLAG_FILELISTS) > 0)
2208 flags_hy |= DNF_SACK_LOAD_FLAG_USE_FILELISTS;
2209 if ((flags & DNF_SACK_ADD_FLAG_OTHER) > 0)
2210 flags_hy |= DNF_SACK_LOAD_FLAG_USE_OTHER;
2211 if ((flags & DNF_SACK_ADD_FLAG_UPDATEINFO) > 0)
2212 flags_hy |= DNF_SACK_LOAD_FLAG_USE_UPDATEINFO;
2213
2214 /* load solv */
2215 g_debug("Loading repo %s", dnf_repo_get_id(repo));
2216 dnf_state_action_start(state, DNF_STATE_ACTION_LOADING_CACHE, NULL);
2217 if (!dnf_sack_load_repo(sack, dnf_repo_get_repo(repo), flags_hy, error))
2218 return FALSE;
2219
2220 /* done */
2221 return dnf_state_done(state, error);
2222 } CATCH_TO_GERROR(FALSE)
2223
2224 /**
2225 * dnf_sack_add_repos:
2226 */
2227 gboolean
2228 dnf_sack_add_repos(DnfSack *sack,
2229 GPtrArray *repos,
2230 guint permissible_cache_age,
2231 DnfSackAddFlags flags,
2232 DnfState *state,
2233 GError **error) try
2234 {
2235 gboolean ret;
2236 guint cnt = 0;
2237 guint i;
2238 DnfRepo *repo;
2239 DnfState *state_local;
2240 g_autoptr(GPtrArray) enabled_repos = g_ptr_array_new();
2241
2242 /* count the enabled repos */
2243 for (i = 0; i < repos->len; i++) {
2244 repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
2245 if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
2246 continue;
2247
2248 /* only allow metadata-only repos if FLAG_UNAVAILABLE is set */
2249 if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_METADATA) {
2250 if ((flags & DNF_SACK_ADD_FLAG_UNAVAILABLE) == 0)
2251 continue;
2252 }
2253
2254 cnt++;
2255 }
2256
2257 /* add each repo */
2258 dnf_state_set_number_steps(state, cnt);
2259 for (i = 0; i < repos->len; i++) {
2260 repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
2261 if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
2262 continue;
2263
2264 /* only allow metadata-only repos if FLAG_UNAVAILABLE is set */
2265 if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_METADATA) {
2266 if ((flags & DNF_SACK_ADD_FLAG_UNAVAILABLE) == 0)
2267 continue;
2268 }
2269
2270 state_local = dnf_state_get_child(state);
2271 ret = dnf_sack_add_repo(sack,
2272 repo,
2273 permissible_cache_age,
2274 flags,
2275 state_local,
2276 error);
2277 if (!ret)
2278 return FALSE;
2279
2280 g_ptr_array_add(enabled_repos, repo);
2281
2282 /* done */
2283 if (!dnf_state_done(state, error))
2284 return FALSE;
2285 }
2286
2287 process_excludes(sack, enabled_repos);
2288
2289 /* success */
2290 return TRUE;
2291 } CATCH_TO_GERROR(FALSE)
2292
2293 namespace {
readModuleMetadataFromRepo(DnfSack * sack,libdnf::ModulePackageContainer * modulePackages,const char * platformModule)2294 void readModuleMetadataFromRepo(DnfSack * sack, libdnf::ModulePackageContainer * modulePackages,
2295 const char * platformModule)
2296 {
2297 modulePackages->add(sack);
2298 modulePackages->loadFailSafeData();
2299 if (!modulePackages->empty()) {
2300 // TODO remove hard-coded path
2301 try {
2302 std::vector<std::string> paths{"/etc/os-release", "/usr/lib/os-release"};
2303 modulePackages->addPlatformPackage(sack, paths, platformModule);
2304 } catch (const std::exception & except) {
2305 auto logger(libdnf::Log::getLogger());
2306 logger->critical("Detection of Platform Module failed: " + std::string(except.what()));
2307 }
2308 }
2309 }
2310
2311 /// @return std::map<name:stream.arch, std::vector<std::string>>
getDemodularizedRpms(libdnf::ModulePackageContainer & moduleContainer,const std::vector<libdnf::ModulePackage * > & allPackages)2312 static std::map<std::string, std::vector<std::string>> getDemodularizedRpms(
2313 libdnf::ModulePackageContainer & moduleContainer, const std::vector<libdnf::ModulePackage *> & allPackages)
2314 {
2315 std::map<std::string, std::vector<std::string>> ret;
2316 auto latest = moduleContainer.getLatestModules(allPackages, true);
2317 for (auto modulePackage : latest) {
2318 auto demodularized = modulePackage->getDemodularizedRpms();
2319 if (demodularized.empty()) {
2320 continue;
2321 }
2322 std::string packageID{modulePackage->getNameStream()};
2323 packageID.append(".");
2324 packageID.append(modulePackage->getArch());
2325 auto & data = ret[packageID];
2326 data.insert(data.end(), demodularized.begin(), demodularized.end());
2327 }
2328 return ret;
2329 }
2330
2331 /// Return <includeNEVRAs>, <excludeNEVRAs>, <names>, <srcNames>, <name dependency container>
2332 static std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, libdnf::DependencyContainer>
collectNevraForInclusionExclusion(DnfSack * sack,libdnf::ModulePackageContainer & modulePackageContainer)2333 collectNevraForInclusionExclusion(DnfSack *sack, libdnf::ModulePackageContainer &modulePackageContainer)
2334 {
2335 auto allPackages = modulePackageContainer.getModulePackages();
2336 auto demodularizedNames = getDemodularizedRpms(modulePackageContainer, allPackages);
2337
2338 std::vector<std::string> includeNEVRAs;
2339 std::vector<std::string> excludeNEVRAs;
2340 std::vector<std::string> names;
2341 std::vector<std::string> srcNames;
2342 libdnf::DependencyContainer nameDependencies{sack};
2343 libdnf::Nevra nevra;
2344 // TODO: turn into std::vector<const char *> to prevent unnecessary conversion?
2345 for (const auto & module : allPackages) {
2346 auto artifacts = module->getArtifacts();
2347 // TODO use Goal::listInstalls() to not requires filtering out Platform
2348 if (modulePackageContainer.isModuleActive(module->getId())) {
2349 std::string packageID{module->getNameStream()};
2350 packageID.append(".");
2351 packageID.append(module->getArch());
2352 auto it = demodularizedNames.find(packageID);
2353 if (it == demodularizedNames.end()) {
2354 for (const auto &rpm : artifacts) {
2355 if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) {
2356 auto arch = nevra.getArch();
2357 // source packages do not provide anything and must not cause excluding binary packages
2358 if (arch == "src" || arch == "nosrc") {
2359 srcNames.push_back(nevra.getName());
2360 } else {
2361 names.push_back(nevra.getName());
2362 nameDependencies.addReldep(nevra.getName().c_str());
2363 }
2364 }
2365 }
2366 } else {
2367 for (const auto &rpm : artifacts) {
2368 if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) {
2369 bool found = false;
2370 for ( auto & demodularized : it->second) {
2371 if (nevra.getName() == demodularized) {
2372 found = true;
2373 break;
2374 }
2375 }
2376 if (found) {
2377 continue;
2378 }
2379 auto arch = nevra.getArch();
2380 // source packages do not provide anything and must not cause excluding binary packages
2381 if (arch == "src" || arch == "nosrc") {
2382 srcNames.push_back(nevra.getName());
2383 } else {
2384 names.push_back(nevra.getName());
2385 nameDependencies.addReldep(nevra.getName().c_str());
2386 }
2387 }
2388 }
2389 }
2390 copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(includeNEVRAs));
2391 } else {
2392 copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(excludeNEVRAs));
2393 }
2394 }
2395
2396 return std::make_tuple(std::move(includeNEVRAs), std::move(excludeNEVRAs), std::move(names), std::move(srcNames),
2397 std::move(nameDependencies));
2398 }
2399
2400 void
setModuleExcludes(DnfSack * sack,const char ** hotfixRepos,libdnf::ModulePackageContainer & modulePackageContainer)2401 setModuleExcludes(DnfSack * sack, const char ** hotfixRepos, libdnf::ModulePackageContainer & modulePackageContainer)
2402 {
2403 dnf_sack_set_module_excludes(sack, nullptr);
2404
2405 auto data = collectNevraForInclusionExclusion(sack, modulePackageContainer);
2406
2407 auto & includeNEVRAs = std::get<0>(data);
2408 auto & excludeNEVRAs = std::get<1>(data);
2409 auto & names = std::get<2>(data);
2410 auto & srcNames = std::get<3>(data);
2411 auto & nameDependencies = std::get<4>(data);
2412
2413 std::vector<const char *> namesCString(names.size() + 1);
2414 std::vector<const char *> srcNamesCString(srcNames.size() + 1);
2415 std::vector<const char *> excludeNEVRAsCString(excludeNEVRAs.size() + 1);
2416 std::vector<const char *> includeNEVRAsCString(includeNEVRAs.size() + 1);
2417
2418 transform(names.begin(), names.end(), namesCString.begin(), std::mem_fn(&std::string::c_str));
2419 transform(srcNames.begin(), srcNames.end(), srcNamesCString.begin(), std::mem_fn(&std::string::c_str));
2420 transform(excludeNEVRAs.begin(), excludeNEVRAs.end(), excludeNEVRAsCString.begin(),
2421 std::mem_fn(&std::string::c_str));
2422 transform(includeNEVRAs.begin(), includeNEVRAs.end(), includeNEVRAsCString.begin(),
2423 std::mem_fn(&std::string::c_str));
2424
2425 libdnf::Query keepPackages{sack};
2426 const char *keepRepo[] = {HY_CMDLINE_REPO_NAME, HY_SYSTEM_REPO_NAME, nullptr};
2427 keepPackages.addFilter(HY_PKG_REPONAME, HY_NEQ, keepRepo);
2428 if (hotfixRepos != nullptr) {
2429 keepPackages.addFilter(HY_PKG_REPONAME, HY_NEQ, hotfixRepos);
2430 }
2431
2432 libdnf::Query includeQuery{sack};
2433 libdnf::Query excludeQuery{keepPackages};
2434 libdnf::Query excludeProvidesQuery{keepPackages};
2435 libdnf::Query excludeNamesQuery(keepPackages);
2436 libdnf::Query excludeSrcNamesQuery(keepPackages);
2437 includeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, includeNEVRAsCString.data());
2438
2439 excludeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, excludeNEVRAsCString.data());
2440 excludeQuery.queryDifference(includeQuery);
2441
2442 // Exclude packages by their Provides
2443 excludeProvidesQuery.addFilter(HY_PKG_PROVIDES, &nameDependencies);
2444 excludeProvidesQuery.queryDifference(includeQuery);
2445
2446 // Search for source packages with same names as included source artifacts
2447 excludeSrcNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, srcNamesCString.data());
2448 const char * srcArchs[] = {"src", "nosrc", nullptr};
2449 excludeSrcNamesQuery.addFilter(HY_PKG_ARCH, HY_EQ, srcArchs);
2450
2451 // Required to filtrate out source packages and packages with incompatible architectures
2452 excludeNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, namesCString.data());
2453 excludeNamesQuery.queryUnion(excludeSrcNamesQuery);
2454 excludeNamesQuery.queryDifference(includeQuery);
2455
2456 dnf_sack_set_module_excludes(sack, excludeQuery.getResultPset());
2457 dnf_sack_add_module_excludes(sack, excludeProvidesQuery.getResultPset());
2458 dnf_sack_add_module_excludes(sack, excludeNamesQuery.getResultPset());
2459 dnf_sack_set_module_includes(sack, includeQuery.getResultPset());
2460 }
2461
2462 }
2463
requiresModuleEnablement(DnfSack * sack,const libdnf::PackageSet * installSet)2464 std::vector<libdnf::ModulePackage *> requiresModuleEnablement(
2465 DnfSack * sack, const libdnf::PackageSet * installSet)
2466 {
2467 DnfSackPrivate *priv = GET_PRIVATE(sack);
2468 if (!priv->module_includes || !priv->moduleContainer) {
2469 return {};
2470 }
2471 libdnf::PackageSet tmp(sack);
2472 tmp += *const_cast<libdnf::PackageSet*>(installSet);
2473 tmp /= priv->module_includes;
2474
2475 if (tmp.empty()) {
2476 return {};
2477 }
2478 auto toEnable = priv->moduleContainer->requiresModuleEnablement(*installSet);
2479 return toEnable;
2480 }
2481
dnf_sack_filter_modules(DnfSack * sack,GPtrArray * repos,const char * install_root,const char * platformModule)2482 void dnf_sack_filter_modules(DnfSack *sack, GPtrArray *repos, const char *install_root,
2483 const char * platformModule)
2484 {
2485 std::vector<const char *> hotfixRepos;
2486 // don't filter RPMs from repos with the 'module_hotfixes' flag set
2487 for (unsigned int i = 0; i < repos->len; i++) {
2488 auto repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
2489 if (dnf_repo_get_module_hotfixes(repo)) {
2490 hotfixRepos.push_back(dnf_repo_get_id(repo));
2491 }
2492 }
2493 hotfixRepos.push_back(nullptr);
2494 dnf_sack_filter_modules_v2(sack, nullptr, hotfixRepos.data(), install_root, platformModule,
2495 false, false, false);
2496 }
2497
dnf_sack_filter_modules_v2(DnfSack * sack,DnfModulePackageContainer * moduleContainer,const char ** hotfixRepos,const char * install_root,const char * platformModule,bool updateOnly,bool debugSolver,bool applyObsoletes)2498 std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer::ModuleErrorType> dnf_sack_filter_modules_v2(
2499 DnfSack * sack, DnfModulePackageContainer * moduleContainer, const char ** hotfixRepos,
2500 const char * install_root, const char * platformModule, bool updateOnly, bool debugSolver, bool applyObsoletes)
2501 {
2502 if (!updateOnly) {
2503 if (!install_root) {
2504 throw std::runtime_error("Installroot not provided");
2505 }
2506 DnfSackPrivate *priv = GET_PRIVATE(sack);
2507 if (!moduleContainer) {
2508 if (priv->moduleContainer) {
2509 delete priv->moduleContainer;
2510 }
2511 priv->moduleContainer = new libdnf::ModulePackageContainer(dnf_sack_get_all_arch(sack),
2512 install_root, dnf_sack_get_arch(sack));
2513 moduleContainer = priv->moduleContainer;
2514 }
2515 readModuleMetadataFromRepo(sack, moduleContainer, platformModule);
2516 moduleContainer->addDefaultsFromDisk();
2517
2518 try {
2519 moduleContainer->moduleDefaultsResolve();
2520 } catch (libdnf::ModulePackageContainer::ResolveException & exception) {
2521 auto logger(libdnf::Log::getLogger());
2522 logger->debug(tfm::format(_("No module defaults found: %s"), exception.what()));
2523 }
2524 }
2525
2526 if (!moduleContainer) {
2527 throw std::runtime_error("ModuleContainer not provided");
2528 }
2529
2530 if (applyObsoletes) {
2531 moduleContainer->applyObsoletes();
2532 }
2533 auto ret = moduleContainer->resolveActiveModulePackages(debugSolver);
2534
2535 setModuleExcludes(sack, hotfixRepos, *moduleContainer);
2536 return ret;
2537 }
2538
dnf_sack_get_rpmdb_version(DnfSack * sack)2539 std::string dnf_sack_get_rpmdb_version(DnfSack *sack) {
2540 // collect all sha1hdr checksums
2541 // they are sufficiently unique IDs that represent installed RPMs
2542 std::vector<std::string> checksums;
2543
2544 // iterate all @System repo RPMs (rpmdb records)
2545 libdnf::Query query{sack, libdnf::Query::ExcludeFlags::IGNORE_EXCLUDES};
2546 query.installed();
2547
2548 auto pset = query.getResultPset();
2549 Id id = -1;
2550 while(true) {
2551 id = pset->next(id);
2552 if (id == -1) {
2553 break;
2554 }
2555 DnfPackage *pkg = dnf_package_new(sack, id);
2556 // store pkgid (equals to sha1hdr)
2557 checksums.push_back(libdnf::string::fromCstring(dnf_package_get_pkgid(pkg)));
2558 g_object_unref(pkg);
2559 }
2560
2561 // sort checksums to compute the output checksum always the same
2562 std::sort(checksums.begin(), checksums.end());
2563
2564 SHA1Hash h;
2565 for (auto & checksum : checksums) {
2566 h.update(checksum.c_str());
2567 }
2568
2569 // build <count>:<hash> output
2570 std::ostringstream result;
2571 result << checksums.size();
2572 result << ":";
2573 result << h.hexdigest();
2574
2575 return result.str();
2576 }
2577