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

Internals mkroot #207

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions Makefile-rpm-ostree.am
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ rpm_ostree_SOURCES = src/app/main.c \
src/app/rpmostree-dbus-helpers.c \
src/app/rpmostree-dbus-helpers.h \
src/app/rpmostree-internals-builtin-unpack.c \
src/app/rpmostree-internals-builtin-mkroot.c \
src/app/rpmostree-libbuiltin.c \
src/app/rpmostree-libbuiltin.h \
$(NULL)
Expand Down
1 change: 1 addition & 0 deletions src/app/rpmostree-builtin-internals.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct {

static RpmOstreeInternalsCommand internals_subcommands[] = {
{ "unpack", rpmostree_internals_builtin_unpack },
{ "mkroot", rpmostree_internals_builtin_mkroot },
{ NULL, NULL }
};

Expand Down
52 changes: 7 additions & 45 deletions src/app/rpmostree-compose-builtin-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,20 +274,8 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
}

/* --- Downloading metadata --- */
{ g_auto(GLnxConsoleRef) console = { 0, };
gs_unref_object HifState *hifstate = hif_state_new ();

progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Downloading metadata:");

glnx_console_lock (&console);

if (!hif_context_setup_sack (hifctx, hifstate, error))
goto out;

g_signal_handler_disconnect (hifstate, progress_sigid);
}
if (!_rpmostree_libhif_console_download_metadata (hifctx, cancellable, error))
goto out;

for (strviter = packages; strviter && *strviter; strviter++)
{
Expand All @@ -296,22 +284,8 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
}

/* --- Resolving dependencies --- */
{ g_auto(GLnxConsoleRef) console = { 0, };
gs_unref_object HifState *hifstate = hif_state_new ();

progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Resolving dependencies:");

glnx_console_lock (&console);

if (!hif_transaction_depsolve (hif_context_get_transaction (hifctx),
hif_context_get_goal (hifctx),
hifstate, error))
goto out;

g_signal_handler_disconnect (hifstate, progress_sigid);
}
if (!_rpmostree_libhif_console_depsolve (hifctx, cancellable, error))
goto out;

if (!compute_checksum_from_treefile_and_goal (self, hif_context_get_goal (hifctx),
&ret_new_inputhash, error))
Expand Down Expand Up @@ -346,21 +320,9 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
rpmostree_print_transaction (hifctx);

/* --- Downloading packages --- */
{ g_auto(GLnxConsoleRef) console = { 0, };
gs_unref_object HifState *hifstate = hif_state_new ();

progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Downloading packages:");

glnx_console_lock (&console);

if (!hif_transaction_download (hif_context_get_transaction (hifctx), hifstate, error))
goto out;

g_signal_handler_disconnect (hifstate, progress_sigid);
}

if (!_rpmostree_libhif_console_download_content (hifctx, cancellable, error))
goto out;

{ g_auto(GLnxConsoleRef) console = { 0, };
gs_unref_object HifState *hifstate = hif_state_new ();

Expand Down
298 changes: 298 additions & 0 deletions src/app/rpmostree-internals-builtin-mkroot.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2015 Colin Walters <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/

#include "config.h"

#include <string.h>
#include <glib-unix.h>
#include <gio/gunixoutputstream.h>
#include <libhif.h>
#include <libhif/hif-utils.h>
#include <libhif/hif-package.h>
#include <rpm/rpmts.h>
#include <stdio.h>
#include <libglnx.h>
#include <rpm/rpmmacro.h>

#include "rpmostree-internals-builtins.h"
#include "rpmostree-util.h"
#include "rpmostree-hif.h"
#include "rpmostree-cleanup.h"
#include "rpmostree-libbuiltin.h"
#include "rpmostree-rpm-util.h"
#include "rpmostree-unpacker.h"

#include "libgsystem.h"

static char *opt_ostree_repo;
static char *opt_yum_reposdir = "/etc/yum.repos.d";
static gboolean opt_suid_fcaps = FALSE;
static gboolean opt_owner = FALSE;
static char **opt_enable_yum_repos = NULL;

static GOptionEntry option_entries[] = {
{ "ostree-repo", 0, 0, G_OPTION_ARG_NONE, &opt_ostree_repo, "OSTree repo to use as cache", NULL },
{ "yum-reposdir", 0, 0, G_OPTION_ARG_STRING, &opt_yum_reposdir, "Path to yum repo configs (default: /etc/yum.repos.d)", NULL },
{ "enable-yum-repo", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_enable_yum_repos, "Enable yum repository", NULL },
{ "suid-fcaps", 0, 0, G_OPTION_ARG_NONE, &opt_suid_fcaps, "Enable setting suid/sgid and capabilities", NULL },
{ "owner", 0, 0, G_OPTION_ARG_NONE, &opt_owner, "Enable chown", NULL },
{ NULL }
};

static char *
hif_package_relpath (int rootfs_fd,
HyPackage package)
{
return g_strconcat (".meta/repocache/", hy_package_get_reponame (package),
"/packages/", glnx_basename (hy_package_get_location (package)), NULL);
}

static gboolean
unpack_one_package (int rootfs_fd,
HifContext *hifctx,
HyPackage pkg,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autofree char *package_relpath = NULL;
g_autofree char *pkg_abspath = NULL;
RpmOstreeUnpackerFlags flags = 0;
glnx_unref_object RpmOstreeUnpacker *unpacker = NULL;

package_relpath = hif_package_relpath (rootfs_fd, pkg);
pkg_abspath = glnx_fdrel_abspath (rootfs_fd, package_relpath);

/* suid implies owner too...anything else is dangerous, as we might write
* a setuid binary for the caller.
*/
if (opt_owner || opt_suid_fcaps)
flags |= RPMOSTREE_UNPACKER_FLAGS_OWNER;
if (opt_suid_fcaps)
flags |= RPMOSTREE_UNPACKER_FLAGS_SUID_FSCAPS;

unpacker = rpmostree_unpacker_new_at (rootfs_fd, package_relpath, flags, error);
if (!unpacker)
goto out;

if (!rpmostree_unpacker_unpack_to_dfd (unpacker, rootfs_fd, cancellable, error))
{
g_autofree char *nevra = hy_package_get_nevra (pkg);
g_prefix_error (error, "Unpacking %s: ", nevra);
goto out;
}

if (TEMP_FAILURE_RETRY (unlinkat (rootfs_fd, package_relpath, 0)) < 0)
{
glnx_set_error_from_errno (error);
g_prefix_error (error, "Deleting %s: ", package_relpath);
goto out;
}

ret = TRUE;
out:
return ret;
}

static gboolean
unpack_packages_in_root (int rootfs_fd,
HifContext *hifctx,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
rpmts ts = rpmtsCreate ();
guint i, nElements;
g_autoptr(GHashTable) nevra_to_pkg =
g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)hy_package_free);
HyPackage filesystem_package = NULL; /* It's special... */

/* Tell librpm about each one so it can tsort them. What we really
* want is to do this from the rpm-md metadata so that we can fully
* parallelize download + unpack.
*/
{ g_autoptr(GPtrArray) package_list = NULL;

package_list = hif_goal_get_packages (hif_context_get_goal (hifctx),
HIF_PACKAGE_INFO_INSTALL,
HIF_PACKAGE_INFO_REINSTALL,
HIF_PACKAGE_INFO_DOWNGRADE,
HIF_PACKAGE_INFO_UPDATE,
-1);

for (i = 0; i < package_list->len; i++)
{
HyPackage pkg = package_list->pdata[i];
g_autofree char *package_relpath = hif_package_relpath (rootfs_fd, pkg);
g_autofree char *pkg_abspath = glnx_fdrel_abspath (rootfs_fd, package_relpath);
glnx_unref_object RpmOstreeUnpacker *unpacker = NULL;
const gboolean allow_untrusted = TRUE;
const gboolean is_update = FALSE;

ret = hif_rpmts_add_install_filename (ts,
pkg_abspath,
allow_untrusted,
is_update,
error);
if (!ret)
goto out;

g_hash_table_insert (nevra_to_pkg, hy_package_get_nevra (pkg), hy_package_link (pkg));

if (strcmp (hy_package_get_name (pkg), "filesystem") == 0)
filesystem_package = hy_package_link (pkg);
}
}

rpmtsOrder (ts);

/* Okay so what's going on in Fedora with incestuous relationship
* between the `filesystem`, `setup`, `libgcc` RPMs is actively
* ridiculous. If we unpack libgcc first it writes to /lib64 which
* is really /usr/lib64, then filesystem blows up since it wants to symlink
* /lib64 -> /usr/lib64.
*
* Really `filesystem` should be first but it depends on `setup` for
* stupid reasons which is hacked around in `%pretrans` which we
* don't run. Just forcibly unpack it first.
*/

if (!unpack_one_package (rootfs_fd, hifctx, filesystem_package,
cancellable, error))
goto out;

nElements = (guint)rpmtsNElements (ts);
for (i = 0; i < nElements; i++)
{
rpmte te = rpmtsElement (ts, i);
const char *nevra = rpmteNEVRA (te);
HyPackage pkg = g_hash_table_lookup (nevra_to_pkg, nevra);

g_assert (pkg);

if (pkg == filesystem_package)
continue;

if (!unpack_one_package (rootfs_fd, hifctx, pkg,
cancellable, error))
goto out;
}

ret = TRUE;
out:
if (ts)
rpmtsFree (ts);
return ret;
}

int
rpmostree_internals_builtin_mkroot (int argc,
char **argv,
GCancellable *cancellable,
GError **error)
{
int exit_status = EXIT_FAILURE;
GOptionContext *context = g_option_context_new ("ROOT PKGNAME [PKGNAME...]");
glnx_unref_object HifContext *hifctx = NULL;
const char *rootpath;
const char *const*pkgnames;
glnx_fd_close int rootfs_fd = -1;

if (!rpmostree_option_context_parse (context,
option_entries,
&argc, &argv,
RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD,
cancellable,
NULL,
error))
goto out;

if (argc < 3)
{
rpmostree_usage_error (context, "ROOT and at least one PKGNAME must be specified", error);
goto out;
}

rootpath = argv[1];
pkgnames = (const char *const*)argv + 2;

if (!glnx_opendirat (AT_FDCWD, argv[1], TRUE, &rootfs_fd, error))
goto out;

hifctx = _rpmostree_libhif_new_default ();

{ g_autofree char *cachepath = NULL;
g_autofree char *solvpath = NULL;
g_autofree char *lockpath = NULL;

hif_context_set_install_root (hifctx, rootpath);
cachepath = glnx_fdrel_abspath (rootfs_fd, ".meta/repocache");
hif_context_set_cache_dir (hifctx, cachepath);
hif_context_set_cache_age (hifctx, G_MAXUINT);
solvpath = glnx_fdrel_abspath (rootfs_fd, ".meta/solv");
hif_context_set_solv_dir (hifctx, solvpath);
lockpath = glnx_fdrel_abspath (rootfs_fd, ".meta/lock");
hif_context_set_lock_dir (hifctx, lockpath);
hif_context_set_repo_dir (hifctx, opt_yum_reposdir);
}

if (!_rpmostree_libhif_setup (hifctx, cancellable, error))
goto out;
_rpmostree_libhif_repos_disable_all (hifctx);

{ char **strviter = opt_enable_yum_repos;
for (; strviter && *strviter; strviter++)
{
const char *reponame = *strviter;
if (!_rpmostree_libhif_repos_enable_by_name (hifctx, reponame, error))
goto out;
}
}

/* --- Downloading metadata --- */
if (!_rpmostree_libhif_console_download_metadata (hifctx, cancellable, error))
goto out;

{ const char *const*strviter = pkgnames;
for (; strviter && *strviter; strviter++)
{
const char *pkgname = *strviter;
if (!hif_context_install (hifctx, pkgname, error))
goto out;
}
}

/* --- Resolving dependencies --- */
if (!_rpmostree_libhif_console_depsolve (hifctx, cancellable, error))
goto out;

rpmostree_print_transaction (hifctx);

/* --- Downloading packages --- */
if (!_rpmostree_libhif_console_download_content (hifctx, cancellable, error))
goto out;

if (!unpack_packages_in_root (rootfs_fd, hifctx, cancellable, error))
goto out;

exit_status = EXIT_SUCCESS;
out:
return exit_status;
}
1 change: 1 addition & 0 deletions src/app/rpmostree-internals-builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
G_BEGIN_DECLS

gboolean rpmostree_internals_builtin_unpack (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean rpmostree_internals_builtin_mkroot (int argc, char **argv, GCancellable *cancellable, GError **error);

G_END_DECLS

Loading