# libdnf Integration in rpm-ostree: Deep Analysis ## Executive Summary rpm-ostree integrates libdnf as its core RPM package management engine, but with significant customizations and architectural adaptations to support its hybrid image/package model. The integration is sophisticated and goes far beyond simple "scripting" - it represents a deep architectural bridge between traditional RPM package management and modern image-based deployments. ## libdnf Architecture Overview ### 1. **Core C Library Foundation** libdnf is fundamentally a **C library** that provides a comprehensive C API for RPM package management: ```c // Core libdnf C API types typedef struct _DnfContext DnfContext; typedef struct _DnfPackage DnfPackage; typedef struct _DnfRepo DnfRepo; typedef struct _DnfSack DnfSack; typedef struct _DnfGoal DnfGoal; ``` ### 2. **C API Functions** The library exposes C functions for all package management operations: ```c // Context management DnfContext *dnf_context_new(void); void dnf_context_set_repo_dir(DnfContext *ctx, const char *reposdir); void dnf_context_set_cache_dir(DnfContext *ctx, const char *cachedir); // Package operations DnfPackage *dnf_sack_add_cmdline_package(DnfSack *sack, const char *filename); const char *dnf_package_get_name(DnfPackage *pkg); const char *dnf_package_get_nevra(DnfPackage *pkg); // Repository management GPtrArray *dnf_context_get_repos(DnfContext *ctx); const char *dnf_repo_get_id(DnfRepo *repo); ``` ### 3. **GObject Integration** libdnf uses GObject for object lifecycle management, which is a C-based object system: ```c // GObject-based inheritance G_DEFINE_TYPE(DnfContext, dnf_context, G_TYPE_OBJECT); G_DEFINE_TYPE(DnfPackage, dnf_package, G_TYPE_OBJECT); ``` ### 4. **Key Characteristics** - **C Foundation**: libdnf is fundamentally a C library with a C API - **GObject System**: Uses GObject for object-oriented features in C - **Multi-Language Support**: Can be wrapped for C++, Rust, Python, etc. - **RPM Integration**: Deeply integrated with the RPM package format and librpm - **Dependency Resolution**: Uses libsolv for sophisticated dependency resolution ## Core Integration Architecture ### 1. **RpmOstreeContext: The Bridge Layer** The primary integration point is the `RpmOstreeContext` structure, which wraps and customizes libdnf's `DnfContext`: ```cpp struct _RpmOstreeContext { GObject parent; DnfContext *dnfctx; // Core libdnf context // ... extensive customization fields }; ``` **Key Customizations:** - **Repository Management**: Custom repo configuration from OSTree deployments - **Package Caching**: Integration with OSTree pkgcache repository - **Transaction Control**: Disabled disk space checks, transaction validation - **Plugin System**: Disabled libdnf plugins in favor of rpm-ostree's own system ### 2. **Context Initialization Pattern** ```cpp // From rpmostree_context_new_base() self->dnfctx = dnf_context_new(); dnf_context_set_repo_dir(self->dnfctx, "/etc/yum.repos.d"); dnf_context_set_cache_dir(self->dnfctx, RPMOSTREE_CORE_CACHEDIR RPMOSTREE_DIR_CACHE_REPOMD); dnf_context_set_solv_dir(self->dnfctx, RPMOSTREE_CORE_CACHEDIR RPMOSTREE_DIR_CACHE_SOLV); dnf_context_set_lock_dir(self->dnfctx, "/run/rpm-ostree/" RPMOSTREE_DIR_LOCK); dnf_context_set_user_agent(self->dnfctx, PACKAGE_NAME "/" PACKAGE_VERSION); // Critical customizations dnf_context_set_write_history(self->dnfctx, FALSE); // No SWDB dnf_context_set_check_disk_space(self->dnfctx, FALSE); dnf_context_set_check_transaction(self->dnfctx, FALSE); dnf_context_set_plugins_dir(self->dnfctx, NULL); // No plugins ``` ## Package Management Integration ### 1. **DnfSack: Package Database** rpm-ostree uses libdnf's `DnfSack` as the primary package database, but with custom loading patterns: ```cpp // Custom sack loading for OSTree roots static gboolean get_sack_for_root(int dfd, const char *path, DnfSack **out_sack, GError **error) { g_autoptr(DnfSack) sack = dnf_sack_new(); dnf_sack_set_rootdir(sack, fullpath); if (!dnf_sack_setup(sack, 0, error)) return FALSE; if (!dnf_sack_load_system_repo(sack, NULL, 0, error)) return FALSE; *out_sack = util::move_nullify(sack); return TRUE; } ``` ### 2. **Package Querying and Resolution** rpm-ostree extensively uses libdnf's query system with custom patterns: ```cpp // Package matching with HyQuery g_autoptr(GPtrArray) matches = NULL; HySelector selector = NULL; HySubject subject = NULL; subject = hy_subject_create(pattern); selector = hy_subject_get_best_selector(subject, sack, NULL, FALSE, NULL); matches = hy_selector_matches(selector); ``` ### 3. **Dependency Resolution with HyGoal** The core dependency resolution uses libdnf's `HyGoal` system: ```cpp // From rpmostree_context_prepare() DnfSack *sack = dnf_context_get_sack(dnfctx); HyGoal goal = dnf_context_get_goal(dnfctx); // Lock existing packages to prevent unwanted changes hy_autoquery HyQuery query = hy_query_create(sack); hy_query_filter(query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME); g_autoptr(GPtrArray) pkgs = hy_query_run(query); for (guint i = 0; i < pkgs->len; i++) { auto pkg = static_cast(pkgs->pdata[i]); if (hy_goal_lock(goal, pkg, error) != 0) return glnx_prefix_error(error, "while locking pkg '%s'", pkgname); } // Perform dependency resolution auto actions = static_cast(DNF_INSTALL | DNF_ALLOW_UNINSTALL); if (!self->treefile_rs->get_recommends()) actions = static_cast(static_cast(actions) | DNF_IGNORE_WEAK_DEPS); if (!dnf_goal_depsolve(goal, actions, error)) return FALSE; ``` ## Repository Management ### 1. **OSTree-Aware Repository Configuration** rpm-ostree customizes repository management to work with OSTree deployments: ```cpp void rpmostree_context_configure_from_deployment(RpmOstreeContext *self, OstreeSysroot *sysroot, OstreeDeployment *cfg_deployment) { g_autofree char *cfg_deployment_root = rpmostree_get_deployment_root(sysroot, cfg_deployment); g_autofree char *reposdir = g_build_filename(cfg_deployment_root, "etc/yum.repos.d", NULL); // Point libdnf to the yum.repos.d of the merge deployment rpmostree_context_set_repos_dir(self, reposdir); // Point the core to the passwd & group of the merge deployment self->passwd_dir = g_build_filename(cfg_deployment_root, "etc", NULL); } ``` ### 2. **Package Cache Integration** rpm-ostree maintains a sophisticated package cache using OSTree repositories: ```cpp // Package cache operations gboolean rpmostree_pkgcache_find_pkg_header(OstreeRepo *pkgcache, const char *nevra, const char *expected_sha256, GVariant **out_header, GCancellable *cancellable, GError **error); // Cache branch naming convention char *rpmostree_get_cache_branch_for_n_evr_a(const char *name, const char *evr, const char *arch); ``` ## Multi-Language Integration Layers