Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libpriv/core: workaround libdnf vars path lookup #3652

Merged
merged 2 commits into from
May 3, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/libpriv/rpmostree-core.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,57 @@ core_libdnf_process_global_init ()

} /* namespace */

/* libdnf internally adds an `install_root` prefix to vars directories,
* resulting in misplaced lookups to `<install_root>/etc/dnf/vars`.
* As a workaround, this inserts a relevant amount of `..` in order to cancel
* out the path prefix.
*/
static gboolean
rpmostree_dnfcontext_fix_vars_dir (DnfContext *context, GError **error)
{
g_assert (context != NULL);

const gchar *install_root = dnf_context_get_install_root (context);

// Check whether we actually need to cancel out `install_root`.
if (install_root == NULL || strcmp (install_root, "/") == 0)
return TRUE; /* 🔚 Early return */

g_autofree char *canon_install_root = realpath (install_root, NULL);
if (canon_install_root == NULL)
return glnx_throw_errno_prefix (error, "realpath(%s)", install_root);

const gchar *const *orig_dirs = dnf_context_get_vars_dir (context);

// Check whether there are vars_dir entries to tweak.
if (orig_dirs == NULL || orig_dirs[0] == NULL)
return TRUE; /* 🔚 Early return */

// Count how many levels need to be canceled, prepare the prefix string.
g_autoptr (GString) slashdotdot_prefix = g_string_new (NULL);
for (int char_index = 0; char_index < strlen (canon_install_root); char_index++)
if (canon_install_root[char_index] == '/')
g_string_append (slashdotdot_prefix, "/..");

// Tweak each directory, prepending the relevant amount of `..`.
g_autoptr (GPtrArray) tweaked_dirs = g_ptr_array_new ();
for (int dir_index = 0; orig_dirs[dir_index] != NULL; dir_index++)
{
const gchar *dir = orig_dirs[dir_index];

g_autoptr (GString) tweaked_path = g_string_new (dir);
g_string_prepend (tweaked_path, slashdotdot_prefix->str);

g_ptr_array_add (tweaked_dirs, g_strdup (tweaked_path->str));
}
g_ptr_array_add (tweaked_dirs, NULL);

auto tweaked_vars_dir = (const gchar *const *)tweaked_dirs->pdata;
dnf_context_set_vars_dir (context, tweaked_vars_dir);

return TRUE;
}

/* Wraps `dnf_context_setup()`, and initializes state based on the treespec
* @spec. Another way to say it is we pair `DnfContext` with an
* `RpmOstreeTreespec`. For example, we handle "instlangs", set the rpmdb root
Expand Down Expand Up @@ -601,6 +652,13 @@ rpmostree_context_setup (RpmOstreeContext *self, const char *install_root, const
dnf_context_set_install_root (self->dnfctx, install_root);
dnf_context_set_source_root (self->dnfctx, source_root);

/* Hackaround libdnf logic, ensuring that `/etc/dnf/vars` gets sourced
* from the host environment instead of the install_root:
* https://github.com/rpm-software-management/libdnf/issues/1503
*/
if (!rpmostree_dnfcontext_fix_vars_dir (self->dnfctx, error))
return glnx_prefix_error (error, "Setting DNF vars directories");

/* Set the RPM _install_langs macro, which gets processed by librpm; this is
* currently only referenced in the traditional or non-"unified core" code.
*/
Expand Down