pkg-add: New builtin to layer additional packages

This builds upon the earlier prototype in
https://github.com/cgwalters/atomic-pkglayer

The `.origin` file says for a replicated installation:

    [origin]
    refspec=local:rhel-atomic-host/7/x86_64/standard

If you then run `rpm-ostree pkg-add strace`, it will result in a new tree with:

    [origin]
    baserefspec=local:rhel-atomic-host/7/x86_64/standard

    [packages]
    requested=strace;

Work still remaining here is to teach `rpm-ostree status` and
`rpm-ostree upgrade` about this.

Closes: #289
Approved by: cgwalters
This commit is contained in:
Colin Walters 2015-02-11 13:06:43 -05:00 committed by Atomic Bot
parent d9e8535bcf
commit beb026f701
22 changed files with 1650 additions and 145 deletions

View File

@ -29,6 +29,8 @@ librpmostreed_la_SOURCES = \
src/daemon/rpmostreed-utils.c \
src/daemon/rpmostreed-sysroot.h \
src/daemon/rpmostreed-sysroot.c \
src/daemon/rpmostree-sysroot-upgrader.h \
src/daemon/rpmostree-sysroot-upgrader.c \
src/daemon/rpmostreed-errors.h \
src/daemon/rpmostreed-errors.c \
src/daemon/rpmostreed-deployment-utils.h \
@ -39,6 +41,7 @@ librpmostreed_la_SOURCES = \
src/daemon/rpmostreed-transaction-monitor.c \
src/daemon/rpmostreed-transaction-types.h \
src/daemon/rpmostreed-transaction-types.c \
src/daemon/rpmostreed-transaction-pkg-add.c \
src/daemon/rpmostree-package-variants.h \
src/daemon/rpmostree-package-variants.c \
src/daemon/rpmostreed-os.h \

View File

@ -27,6 +27,7 @@ rpm_ostree_SOURCES = src/app/main.c \
src/app/rpmostree-builtin-rollback.c \
src/app/rpmostree-builtin-deploy.c \
src/app/rpmostree-builtin-rebase.c \
src/app/rpmostree-builtin-pkgadd.c \
src/app/rpmostree-builtin-status.c \
src/app/rpmostree-builtin-internals.c \
src/app/rpmostree-builtin-container.c \

View File

@ -39,6 +39,7 @@ static RpmOstreeCommand commands[] = {
#endif
{ "db", rpmostree_builtin_db },
{ "deploy", rpmostree_builtin_deploy },
{ "pkg-add", rpmostree_builtin_pkg_add },
{ "rebase", rpmostree_builtin_rebase },
{ "rollback", rpmostree_builtin_rollback },
{ "status", rpmostree_builtin_status },

View File

@ -0,0 +1,123 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2015 Colin Walters <walters@verbum.org>
*
* 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 "rpmostree-builtins.h"
#include "rpmostree-libbuiltin.h"
#include "rpmostree-rpm-util.h"
#include "rpmostree-dbus-helpers.h"
#include <libglnx.h>
static char *opt_osname;
static gboolean opt_reboot;
static GOptionEntry option_entries[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after upgrade is prepared", NULL },
{ NULL }
};
static GVariant *
new_floating_empty_gvariant_dict (void)
{
GVariantDict dict;
g_variant_dict_init (&dict, NULL);
return g_variant_dict_end (&dict);
}
int
rpmostree_builtin_pkg_add (int argc,
char **argv,
GCancellable *cancellable,
GError **error)
{
int exit_status = EXIT_FAILURE;
GOptionContext *context;
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
g_autoptr(GVariant) default_deployment = NULL;
g_autofree char *transaction_address = NULL;
int i;
g_autoptr(GPtrArray) argv_and_null = g_ptr_array_new ();
context = g_option_context_new ("PACKAGE [PACKAGE...] - Download and install layered RPM packages");
if (!rpmostree_option_context_parse (context,
option_entries,
&argc, &argv,
RPM_OSTREE_BUILTIN_FLAG_NONE,
cancellable,
&sysroot_proxy,
error))
goto out;
if (argc < 2)
{
rpmostree_usage_error (context, "At least one PACKAGE must be specified", error);
goto out;
}
for (i = 1; i < argc; i++)
g_ptr_array_add (argv_and_null, argv[i]);
g_ptr_array_add (argv_and_null, NULL);
if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname,
cancellable, &os_proxy, error))
goto out;
if (!rpmostree_os_call_pkg_add_sync (os_proxy,
new_floating_empty_gvariant_dict (),
(const char * const*)argv_and_null->pdata,
&transaction_address,
cancellable,
error))
goto out;
if (!rpmostree_transaction_get_response_sync (sysroot_proxy,
transaction_address,
cancellable,
error))
goto out;
if (!opt_reboot)
{
const char *sysroot_path;
sysroot_path = rpmostree_sysroot_get_path (sysroot_proxy);
if (!rpmostree_print_treepkg_diff_from_sysroot_path (sysroot_path,
cancellable,
error))
goto out;
g_print ("Run \"systemctl reboot\" to start a reboot\n");
}
exit_status = EXIT_SUCCESS;
out:
/* Does nothing if using the message bus. */
rpmostree_cleanup_peer ();
return exit_status;
}

View File

@ -50,6 +50,16 @@ printchar (char *s, int n)
g_print ("\n");
}
static char *
format_layered_packages_plus (char **packages)
{
guint len = g_strv_length (packages);
if (len > 0)
return g_strdup_printf (" (+%u)", len);
else
return g_strdup ("");
}
int
rpmostree_builtin_status (int argc,
char **argv,
@ -126,6 +136,7 @@ rpmostree_builtin_status (int argc,
if (!opt_pretty)
{
gchar *origin_refspec = NULL; /* borrowed */
gchar **origin_packages = NULL; /* borrowed */
gchar *os_name = NULL; /* borrowed */
gchar *version_string = NULL; /* borrowed */
@ -143,7 +154,17 @@ rpmostree_builtin_status (int argc,
max_version_len = MAX (max_version_len, strlen (version_string));
if (g_variant_dict_lookup (dict, "origin", "&s", &origin_refspec))
max_refspec_len = MAX (max_refspec_len, strlen (origin_refspec));
{
if (g_variant_dict_lookup (dict, "packages", "^a&s", &origin_packages))
{
g_autofree gchar *origin_packages_plus =
format_layered_packages_plus (origin_packages);
max_refspec_len = MAX (max_refspec_len, strlen (origin_refspec) + strlen (origin_packages_plus));
}
else
max_refspec_len = MAX (max_refspec_len, strlen (origin_refspec));
}
}
g_variant_unref (child);
@ -177,9 +198,11 @@ rpmostree_builtin_status (int argc,
gchar *id = NULL; /* borrowed */
gchar *origin_refspec = NULL; /* borrowed */
gchar **origin_packages = NULL; /* borrowed */
gchar *os_name = NULL; /* borrowed */
gchar *version_string = NULL; /* borrowed */
gchar *checksum = NULL; /* borrowed */
g_autofree gchar *origin_refspec_description = NULL;
guint64 t = 0;
gint serial;
@ -194,9 +217,21 @@ rpmostree_builtin_status (int argc,
g_variant_dict_lookup (dict, "version", "s", &version_string);
g_variant_dict_lookup (dict, "timestamp", "t", &t);
g_variant_dict_lookup (dict, "origin", "s", &origin_refspec);
g_variant_dict_lookup (dict, "packages", "^a&s", &origin_packages);
signatures = g_variant_dict_lookup_value (dict, "signatures",
G_VARIANT_TYPE ("av"));
if (origin_packages)
{
g_autofree gchar *origin_packages_plus =
format_layered_packages_plus (origin_packages);
origin_refspec_description = g_strconcat (origin_refspec, origin_packages_plus, NULL);
}
else
{
origin_refspec_description = g_strdup (origin_refspec);
}
is_booted = g_strcmp0 (booted_id, id) == 0;
timestamp = g_date_time_new_from_unix_utc (t);
@ -221,7 +256,7 @@ rpmostree_builtin_status (int argc,
g_print ("%-*s%-*s%-*s\n",
max_id_len+buffer, truncated_csum,
max_osname_len+buffer, os_name,
max_refspec_len, origin_refspec);
max_refspec_len, origin_refspec_description);
}
/* print "pretty" row info */
@ -229,6 +264,8 @@ rpmostree_builtin_status (int argc,
{
guint tab = 11;
char *title = NULL;
g_autofree char *packages_joined = g_strjoinv (" ", origin_packages);
if (i==0)
title = "DEFAULT ON BOOT";
else if (is_booted || n <= 2)
@ -243,11 +280,12 @@ rpmostree_builtin_status (int argc,
if (version_string)
g_print (" %-*s%-*s\n", tab, "version", tab, version_string);
g_print (" %-*s%-*s\n %-*s%-*s.%d\n %-*s%-*s\n %-*s%-*s\n",
g_print (" %-*s%-*s\n %-*s%-*s.%d\n %-*s%-*s\n %-*s%-*s\n %-*s%-*s\n",
tab, "timestamp", tab, timestamp_string,
tab, "id", tab, checksum, serial,
tab, "osname", tab, os_name,
tab, "refspec", tab, origin_refspec);
tab, "refspec", tab, origin_refspec,
tab, "packages", tab, packages_joined);
if (signatures != NULL)
rpmostree_print_signatures (signatures, " GPG: ");

View File

@ -50,6 +50,7 @@ BUILTINPROTO(status);
BUILTINPROTO(db);
BUILTINPROTO(internals);
BUILTINPROTO(container);
BUILTINPROTO(pkg_add);
#undef BUILTINPROTO

View File

@ -883,9 +883,27 @@ rpmostree_compose_builtin_tree (int argc,
error))
goto out;
if (!rpmostree_commit (yumroot, repo, self->ref, metadata, gpgkey, selinux,
cancellable, error))
goto out;
{ g_autofree char *new_revision = NULL;
glnx_fd_close int rootfs_fd = -1;
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (yumroot), TRUE,
&rootfs_fd, error))
goto out;
g_print ("Committing...\n");
if (!rpmostree_commit (rootfs_fd, repo, self->ref, metadata, gpgkey, selinux, NULL,
&new_revision,
cancellable, error))
goto out;
g_print ("%s => %s\n", ref, new_revision);
if (!g_getenv ("RPM_OSTREE_PRESERVE_ROOTFS"))
(void) glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (yumroot), cancellable, NULL);
else
g_print ("Preserved %s\n", gs_file_get_path_cached (yumroot));
}
}
if (opt_touch_if_changed)

View File

@ -12,6 +12,7 @@
'timestamp' (type 't')
'origin' (type 's')
'signatures' (type 'av')
'packages' (type 'as')
-->
<interface name="org.projectatomic.rpmostree1.Sysroot">
@ -171,6 +172,12 @@
<arg type="s" name="transaction_address" direction="out"/>
</method>
<method name="PkgAdd">
<arg type="a{sv}" name="options" direction="in"/>
<arg type="as" name="packages"/>
<arg type="s" name="transaction_address" direction="out"/>
</method>
</interface>
<interface name="org.projectatomic.rpmostree1.Transaction">

View File

@ -0,0 +1,564 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2015 Colin Walters <walters@verbum.org>
*
* This library 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 License, 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 <libglnx.h>
#include "rpmostreed-utils.h"
#include "rpmostree-util.h"
#include "rpmostree-sysroot-upgrader.h"
/**
* SECTION:rpmostree-sysroot-upgrader
* @title: Simple upgrade class
* @short_description: Upgrade RPM+OSTree systems
*
* The #RpmOstreeSysrootUpgrader class models a `baserefspec` OSTree branch
* in an origin file, along with a set of layered RPM packages.
*
* It also supports the plain-ostree "refspec" model.
*/
typedef struct {
GObjectClass parent_class;
} RpmOstreeSysrootUpgraderClass;
struct RpmOstreeSysrootUpgrader {
GObject parent;
OstreeSysroot *sysroot;
char *osname;
RpmOstreeSysrootUpgraderFlags flags;
OstreeDeployment *merge_deployment;
GKeyFile *origin;
char *origin_refspec;
char **requested_packages;
char *override_csum;
char *new_revision;
};
enum {
PROP_0,
PROP_SYSROOT,
PROP_OSNAME,
PROP_FLAGS
};
static void rpmostree_sysroot_upgrader_initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_WITH_CODE (RpmOstreeSysrootUpgrader, ostree_sysroot_upgrader, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, rpmostree_sysroot_upgrader_initable_iface_init))
static gboolean
parse_refspec (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autofree char *unconfigured_state = NULL;
g_autofree char *csum = NULL;
if ((self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED) == 0)
{
/* If explicit action by the OS creator is requried to upgrade, print their text as an error */
unconfigured_state = g_key_file_get_string (self->origin, "origin", "unconfigured-state", NULL);
if (unconfigured_state)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"origin unconfigured-state: %s", unconfigured_state);
goto out;
}
}
if (!_rpmostree_util_parse_origin (self->origin, &self->origin_refspec, &self->requested_packages, error))
goto out;
csum = g_key_file_get_string (self->origin, "origin", "override-commit", NULL);
if (csum != NULL && !ostree_validate_checksum_string (csum, error))
goto out;
self->override_csum = g_steal_pointer (&csum);
ret = TRUE;
out:
return ret;
}
static gboolean
rpmostree_sysroot_upgrader_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
RpmOstreeSysrootUpgrader *self = (RpmOstreeSysrootUpgrader*)initable;
OstreeDeployment *booted_deployment =
ostree_sysroot_get_booted_deployment (self->sysroot);
if (booted_deployment == NULL && self->osname == NULL)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Not currently booted into an OSTree system and no OS specified");
goto out;
}
if (self->osname == NULL)
{
g_assert (booted_deployment);
self->osname = g_strdup (ostree_deployment_get_osname (booted_deployment));
}
else if (self->osname[0] == '\0')
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid empty osname");
goto out;
}
self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname);
if (self->merge_deployment == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No previous deployment for OS '%s'", self->osname);
goto out;
}
self->origin = ostree_deployment_get_origin (self->merge_deployment);
if (!self->origin)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No origin known for deployment %s.%d",
ostree_deployment_get_csum (self->merge_deployment),
ostree_deployment_get_deployserial (self->merge_deployment));
goto out;
}
g_key_file_ref (self->origin);
if (!parse_refspec (self, cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
static void
rpmostree_sysroot_upgrader_initable_iface_init (GInitableIface *iface)
{
iface->init = rpmostree_sysroot_upgrader_initable_init;
}
static void
ostree_sysroot_upgrader_finalize (GObject *object)
{
RpmOstreeSysrootUpgrader *self = RPMOSTREE_SYSROOT_UPGRADER (object);
g_clear_object (&self->sysroot);
g_free (self->osname);
g_clear_object (&self->merge_deployment);
if (self->origin)
g_key_file_unref (self->origin);
g_free (self->origin_refspec);
g_strfreev (self->requested_packages);
g_free (self->override_csum);
G_OBJECT_CLASS (ostree_sysroot_upgrader_parent_class)->finalize (object);
}
static void
ostree_sysroot_upgrader_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
RpmOstreeSysrootUpgrader *self = RPMOSTREE_SYSROOT_UPGRADER (object);
switch (prop_id)
{
case PROP_SYSROOT:
self->sysroot = g_value_dup_object (value);
break;
case PROP_OSNAME:
self->osname = g_value_dup_string (value);
break;
case PROP_FLAGS:
self->flags = g_value_get_flags (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
ostree_sysroot_upgrader_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
RpmOstreeSysrootUpgrader *self = RPMOSTREE_SYSROOT_UPGRADER (object);
switch (prop_id)
{
case PROP_SYSROOT:
g_value_set_object (value, self->sysroot);
break;
case PROP_OSNAME:
g_value_set_string (value, self->osname);
break;
case PROP_FLAGS:
g_value_set_flags (value, self->flags);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
ostree_sysroot_upgrader_constructed (GObject *object)
{
RpmOstreeSysrootUpgrader *self = RPMOSTREE_SYSROOT_UPGRADER (object);
g_assert (self->sysroot != NULL);
G_OBJECT_CLASS (ostree_sysroot_upgrader_parent_class)->constructed (object);
}
static void
ostree_sysroot_upgrader_class_init (RpmOstreeSysrootUpgraderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = ostree_sysroot_upgrader_constructed;
object_class->get_property = ostree_sysroot_upgrader_get_property;
object_class->set_property = ostree_sysroot_upgrader_set_property;
object_class->finalize = ostree_sysroot_upgrader_finalize;
g_object_class_install_property (object_class,
PROP_SYSROOT,
g_param_spec_object ("sysroot", "", "",
OSTREE_TYPE_SYSROOT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_OSNAME,
g_param_spec_string ("osname", "", "", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_FLAGS,
g_param_spec_flags ("flags", "", "",
rpmostree_sysroot_upgrader_flags_get_type (),
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
ostree_sysroot_upgrader_init (RpmOstreeSysrootUpgrader *self)
{
}
/**
* rpmostree_sysroot_upgrader_new_for_os_with_flags:
* @sysroot: An #OstreeSysroot
* @osname: (allow-none): Operating system name
* @flags: Flags
*
* Returns: (transfer full): An upgrader
*/
RpmOstreeSysrootUpgrader *
rpmostree_sysroot_upgrader_new (OstreeSysroot *sysroot,
const char *osname,
RpmOstreeSysrootUpgraderFlags flags,
GCancellable *cancellable,
GError **error)
{
return g_initable_new (RPMOSTREE_TYPE_SYSROOT_UPGRADER, cancellable, error,
"sysroot", sysroot, "osname", osname, "flags", flags, NULL);
}
/**
* rpmostree_sysroot_upgrader_get_origin:
* @self: Sysroot
*
* Returns: (transfer none): The origin file, or %NULL if unknown
*/
GKeyFile *
rpmostree_sysroot_upgrader_get_origin (RpmOstreeSysrootUpgrader *self)
{
return self->origin;
}
/**
* ostree_sysroot_upgrader_dup_origin:
* @self: Sysroot
*
* Returns: (transfer full): A copy of the origin file, or %NULL if unknown
*/
GKeyFile *
rpmostree_sysroot_upgrader_dup_origin (RpmOstreeSysrootUpgrader *self)
{
GKeyFile *copy = NULL;
g_return_val_if_fail (OSTREE_IS_SYSROOT_UPGRADER (self), NULL);
if (self->origin != NULL)
{
g_autofree char *data = NULL;
gsize length = 0;
copy = g_key_file_new ();
data = g_key_file_to_data (self->origin, &length, NULL);
g_key_file_load_from_data (copy, data, length,
G_KEY_FILE_KEEP_COMMENTS, NULL);
}
return copy;
}
/**
* ostree_sysroot_upgrader_set_origin:
* @self: Sysroot
* @origin: (allow-none): The new origin
* @cancellable: Cancellable
* @error: Error
*
* Replace the origin with @origin.
*/
gboolean
rpmostree_sysroot_upgrader_set_origin (RpmOstreeSysrootUpgrader *self,
GKeyFile *origin,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_clear_pointer (&self->origin, g_key_file_unref);
if (origin)
{
self->origin = g_key_file_ref (origin);
if (!parse_refspec (self, cancellable, error))
goto out;
}
ret = TRUE;
out:
return ret;
}
gboolean
rpmostree_sysroot_upgrader_set_origin_rebase (RpmOstreeSysrootUpgrader *self, const char *new_refspec, GError **error)
{
g_free (self->origin_refspec);
self->origin_refspec = g_strdup (new_refspec);
return TRUE;
}
void
rpmostree_sysroot_upgrader_set_origin_override (RpmOstreeSysrootUpgrader *self, const char *override_commit)
{
if (override_commit != NULL)
g_key_file_set_string (self->origin, "origin", "override-commit", override_commit);
else
g_key_file_remove_key (self->origin, "origin", "override_commit", NULL);
}
void
rpmostree_sysroot_upgrader_set_origin_baseref_local (RpmOstreeSysrootUpgrader *self, const char *local_commit)
{
self->new_revision = g_strdup (local_commit);
}
const char *
rpmostree_sysroot_upgrader_get_refspec (RpmOstreeSysrootUpgrader *self)
{
return self->origin_refspec;
}
const char *const*
rpmostree_sysroot_upgrader_get_packages (RpmOstreeSysrootUpgrader *self)
{
return (const char * const *)self->requested_packages;
}
/**
* rpmostree_sysroot_upgrader_get_origin_description:
* @self: Upgrader
*
* Returns: A one-line descriptive summary of the origin, or %NULL if unknown
*/
char *
rpmostree_sysroot_upgrader_get_origin_description (RpmOstreeSysrootUpgrader *self)
{
return g_strdup (rpmostree_sysroot_upgrader_get_refspec (self));
}
/*
* Like ostree_sysroot_upgrader_pull(), but will modify to include
* layered packages.
*/
gboolean
rpmostree_sysroot_upgrader_pull (RpmOstreeSysrootUpgrader *self,
const char *dir_to_pull,
OstreeRepoPullFlags flags,
OstreeAsyncProgress *progress,
gboolean *out_changed,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
glnx_unref_object OstreeRepo *repo = NULL;
char *refs_to_fetch[] = { NULL, NULL };
const char *from_revision = NULL;
g_autofree char *new_revision = NULL;
g_autofree char *origin_remote = NULL;
g_autofree char *origin_ref = NULL;
if (!ostree_parse_refspec (self->origin_refspec,
&origin_remote,
&origin_ref,
error))
goto out;
if (self->override_csum != NULL)
refs_to_fetch[0] = self->override_csum;
else
refs_to_fetch[0] = origin_ref;
if (!ostree_sysroot_get_repo (self->sysroot, &repo, cancellable, error))
goto out;
g_assert (self->merge_deployment);
from_revision = ostree_deployment_get_csum (self->merge_deployment);
if (origin_remote)
{
if (!ostree_repo_pull_one_dir (repo, origin_remote, dir_to_pull, refs_to_fetch,
flags, progress,
cancellable, error))
goto out;
if (progress)
ostree_async_progress_finish (progress);
}
if (self->override_csum != NULL)
{
if (!ostree_repo_set_ref_immediate (repo,
origin_remote,
origin_ref,
self->override_csum,
cancellable,
error))
goto out;
self->new_revision = g_strdup (self->override_csum);
}
else
{
if (!ostree_repo_resolve_rev (repo, self->origin_refspec, FALSE,
&self->new_revision, error))
goto out;
}
if (g_strcmp0 (from_revision, self->new_revision) == 0)
{
*out_changed = FALSE;
}
else
{
gboolean allow_older = (self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER) > 0;
*out_changed = TRUE;
if (from_revision && !allow_older)
{
if (!ostree_sysroot_upgrader_check_timestamps (repo, from_revision,
self->new_revision,
error))
goto out;
}
}
ret = TRUE;
out:
return ret;
}
/**
* rpmostree_sysroot_upgrader_deploy:
* @self: Self
* @cancellable: Cancellable
* @error: Error
*
* Write the new deployment to disk, perform a configuration merge
* with /etc, and update the bootloader configuration.
*/
gboolean
rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
glnx_unref_object OstreeDeployment *new_deployment = NULL;
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
self->new_revision,
self->origin,
self->merge_deployment,
NULL,
&new_deployment,
cancellable, error))
goto out;
if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
new_deployment,
self->merge_deployment,
0,
cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
GType
rpmostree_sysroot_upgrader_flags_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const GFlagsValue values[] = {
{ RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, "RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED", "ignore-unconfigured" },
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_flags_register_static (g_intern_static_string ("RpmOstreeSysrootUpgraderFlags"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}

View File

@ -0,0 +1,92 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
*
* This library 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 License, 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.
*/
#pragma once
#include <ostree.h>
G_BEGIN_DECLS
#define RPMOSTREE_TYPE_SYSROOT_UPGRADER ostree_sysroot_upgrader_get_type()
#define RPMOSTREE_SYSROOT_UPGRADER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), RPMOSTREE_TYPE_SYSROOT_UPGRADER, RpmOstreeSysrootUpgrader))
#define RPMOSTREE_IS_SYSROOT_UPGRADER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), RPMOSTREE_TYPE_SYSROOT_UPGRADER))
typedef struct RpmOstreeSysrootUpgrader RpmOstreeSysrootUpgrader;
/**
* RpmOstreeSysrootUpgraderPullFlags:
* @RPMOSTREE_SYSROOT_UPGRADER_PULL_FLAGS_NONE: No options
* @RPMOSTREE_SYSROOT_UPGRADER_PULL_FLAGS_IGNORE_UNCONFIGURED: Do not error if the origin has an unconfigured-state key
*
* Flags controlling operation of an #RpmOstreeSysrootUpgrader.
*/
typedef enum {
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_NONE = (1 << 0),
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED = (1 << 1),
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER = (1 << 2)
} RpmOstreeSysrootUpgraderFlags;
GType rpmostree_sysroot_upgrader_get_type (void);
GType rpmostree_sysroot_upgrader_flags_get_type (void);
RpmOstreeSysrootUpgrader *rpmostree_sysroot_upgrader_new (OstreeSysroot *sysroot,
const char *osname,
RpmOstreeSysrootUpgraderFlags flags,
GCancellable *cancellable,
GError **error);
const char *rpmostree_sysroot_upgrader_get_refspec (RpmOstreeSysrootUpgrader *self);
const char *const*rpmostree_sysroot_upgrader_get_packages (RpmOstreeSysrootUpgrader *self);
char * rpmostree_sysroot_upgrader_get_origin_description (RpmOstreeSysrootUpgrader *self);
GKeyFile *rpmostree_sysroot_upgrader_get_origin (RpmOstreeSysrootUpgrader *self);
GKeyFile *rpmostree_sysroot_upgrader_dup_origin (RpmOstreeSysrootUpgrader *self);
gboolean rpmostree_sysroot_upgrader_set_origin (RpmOstreeSysrootUpgrader *self, GKeyFile *origin,
GCancellable *cancellable, GError **error);
gboolean
rpmostree_sysroot_upgrader_pull (RpmOstreeSysrootUpgrader *self,
const char *dir_to_pull,
OstreeRepoPullFlags flags,
OstreeAsyncProgress *progress,
gboolean *out_changed,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);
gboolean rpmostree_sysroot_upgrader_set_origin_rebase (RpmOstreeSysrootUpgrader *self, const char *new_refspec, GError **error);
void rpmostree_sysroot_upgrader_set_origin_override (RpmOstreeSysrootUpgrader *self, const char *override_commit);
void rpmostree_sysroot_upgrader_set_origin_baseref_local (RpmOstreeSysrootUpgrader *self, const char *local_commit);
G_END_DECLS

View File

@ -125,17 +125,36 @@ out:
char *
rpmostreed_deployment_get_refspec (OstreeDeployment *deployment)
{
GKeyFile *origin = NULL; /* owned by deployment */
char *origin_refspec = NULL;
rpmostreed_deployment_get_refspec_packages (deployment, &origin_refspec, NULL);
return origin_refspec;
}
void
rpmostreed_deployment_get_refspec_packages (OstreeDeployment *deployment,
char **out_refspec,
char ***out_packages)
{
GKeyFile *origin = NULL; /* owned by deployment */
gsize len;
g_return_if_fail (out_refspec != NULL);
origin = ostree_deployment_get_origin (deployment);
if (!origin)
goto out;
{
*out_refspec = NULL;
*out_packages = NULL;
return;
}
origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
*out_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
if (!*out_refspec)
*out_refspec = g_key_file_get_string (origin, "origin", "baserefspec", NULL);
out:
return origin_refspec;
if (out_packages)
*out_packages = g_key_file_get_string_list (origin, "packages", "requested", &len, NULL);
}
GVariant *
@ -192,6 +211,7 @@ rpmostreed_deployment_generate_variant (OstreeDeployment *deployment,
g_autoptr(GVariant) commit = NULL;
g_autofree gchar *origin_refspec = NULL;
g_auto(GStrv) origin_packages = NULL;
g_autofree gchar *id = NULL;
GVariant *sigs = NULL; /* floating variant */
@ -203,7 +223,7 @@ rpmostreed_deployment_generate_variant (OstreeDeployment *deployment,
gint serial = ostree_deployment_get_deployserial (deployment);
id = rpmostreed_deployment_generate_id (deployment);
origin_refspec = rpmostreed_deployment_get_refspec (deployment);
rpmostreed_deployment_get_refspec_packages (deployment, &origin_refspec, &origin_packages);
if (origin_refspec)
sigs = rpmostreed_deployment_gpg_results (repo, origin_refspec, csum);
@ -218,6 +238,8 @@ rpmostreed_deployment_generate_variant (OstreeDeployment *deployment,
variant_add_commit_details (&dict, repo, csum);
if (origin_refspec != NULL)
g_variant_dict_insert (&dict, "origin", "s", origin_refspec);
if (origin_packages != NULL)
g_variant_dict_insert (&dict, "packages", "^as", origin_packages);
if (sigs != NULL)
g_variant_dict_insert_value (&dict, "signatures", sigs);

View File

@ -30,6 +30,10 @@ OstreeDeployment *
char * rpmostreed_deployment_get_refspec (OstreeDeployment *deployment);
void rpmostreed_deployment_get_refspec_packages (OstreeDeployment *deployment,
char **out_refspec,
char ***out_packages);
GVariant * rpmostreed_deployment_generate_blank_variant (void);
GVariant * rpmostreed_deployment_generate_variant (OstreeDeployment *deployment,

View File

@ -705,6 +705,79 @@ out:
return TRUE;
}
static gboolean
os_handle_pkg_add (RPMOSTreeOS *interface,
GDBusMethodInvocation *invocation,
GVariant *arg_options,
const char * const *arg_packages)
{
/* TODO: Totally ignoring arg_packages for now */
RpmostreedOS *self = RPMOSTREED_OS (interface);
glnx_unref_object RpmostreedTransaction *transaction = NULL;
glnx_unref_object OstreeSysroot *ot_sysroot = NULL;
glnx_unref_object GCancellable *cancellable = NULL;
GVariantDict options_dict;
const char *osname;
gboolean opt_reboot = FALSE;
GError *local_error = NULL;
/* If a compatible transaction is in progress, share its bus address. */
transaction = rpmostreed_transaction_monitor_ref_active_transaction (self->transaction_monitor);
if (transaction != NULL)
{
if (rpmostreed_transaction_is_compatible (transaction, invocation))
goto out;
g_clear_object (&transaction);
}
cancellable = g_cancellable_new ();
if (!rpmostreed_sysroot_load_state (rpmostreed_sysroot_get (),
cancellable,
&ot_sysroot,
NULL,
&local_error))
goto out;
osname = rpmostree_os_get_name (interface);
/* XXX Fail if option type is wrong? */
g_variant_dict_init (&options_dict, arg_options);
g_variant_dict_lookup (&options_dict,
"reboot", "b",
&opt_reboot);
g_variant_dict_clear (&options_dict);
transaction = rpmostreed_transaction_new_pkg_add (invocation,
ot_sysroot,
osname,
arg_packages,
opt_reboot,
cancellable,
&local_error);
if (transaction == NULL)
goto out;
rpmostreed_transaction_monitor_add (self->transaction_monitor, transaction);
out:
if (local_error != NULL)
{
g_dbus_method_invocation_take_error (invocation, local_error);
}
else
{
const char *client_address;
client_address = rpmostreed_transaction_get_client_address (transaction);
rpmostree_os_complete_pkg_add (interface, invocation, client_address);
}
return TRUE;
}
static gboolean
os_handle_get_cached_rebase_rpm_diff (RPMOSTreeOS *interface,
GDBusMethodInvocation *invocation,
@ -1078,6 +1151,7 @@ rpmostreed_os_iface_init (RPMOSTreeOSIface *iface)
iface->handle_rollback = os_handle_rollback;
iface->handle_clear_rollback_target = os_handle_clear_rollback_target;
iface->handle_rebase = os_handle_rebase;
iface->handle_pkg_add = os_handle_pkg_add;
iface->handle_get_cached_rebase_rpm_diff = os_handle_get_cached_rebase_rpm_diff;
iface->handle_download_rebase_rpm_diff = os_handle_download_rebase_rpm_diff;
iface->handle_get_cached_deploy_rpm_diff = os_handle_get_cached_deploy_rpm_diff;

View File

@ -0,0 +1,525 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "ostree.h"
#include <libglnx.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmdb.h>
#include <libhif.h>
#include <libhif/hif-utils.h>
#include <libgsystem.h>
#include "rpmostreed-transaction-types.h"
#include "rpmostreed-transaction-types.h"
#include "rpmostreed-transaction.h"
#include "rpmostreed-deployment-utils.h"
#include "rpmostreed-sysroot.h"
#include "rpmostree-sysroot-upgrader.h"
#include "rpmostreed-utils.h"
#include "rpmostree-hif.h"
#include "rpmostree-postprocess.h"
#include "rpmostree-rpm-util.h"
typedef struct {
RpmostreedTransaction parent;
char *osname;
char **packages;
gboolean reboot;
} PkgAddTransaction;
typedef RpmostreedTransactionClass PkgAddTransactionClass;
GType pkg_add_transaction_get_type (void);
G_DEFINE_TYPE (PkgAddTransaction,
pkg_add_transaction,
RPMOSTREED_TYPE_TRANSACTION)
static void
pkg_add_transaction_finalize (GObject *object)
{
PkgAddTransaction *self;
self = (PkgAddTransaction *) object;
g_free (self->osname);
g_strfreev (self->packages);
G_OBJECT_CLASS (pkg_add_transaction_parent_class)->finalize (object);
}
static gboolean
copy_dir_contents_nonrecurse_at (int src_dfd,
const char *srcpath,
int dest_dfd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_auto(GLnxDirFdIterator) dfd_iter = { FALSE, };
struct dirent *dent = NULL;
if (!glnx_dirfd_iterator_init_at (src_dfd, srcpath, TRUE,
&dfd_iter, error))
goto out;
while (glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
{
if (dent == NULL)
break;
if (!glnx_file_copy_at (dfd_iter.fd, dent->d_name, NULL, dest_dfd, dent->d_name, 0,
cancellable, error))
{
goto out;
}
}
ret = TRUE;
out:
return ret;
}
/* Given a directory referred to by @dfd and @dirpath, ensure that
* physical (or reflink'd) copies of all files are done.
*/
static gboolean
break_hardlinks_at (int dfd,
const char *dirpath,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
glnx_fd_close int dest_dfd = -1;
g_autofree char *dirpath_tmp = g_strconcat (dirpath, ".tmp", NULL);
if (TEMP_FAILURE_RETRY (renameat (dfd, dirpath, dfd, dirpath_tmp)) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
/* We're not accurately copying the mode, but in reality modes don't
* matter since it's all immutable anyways.
*/
if (TEMP_FAILURE_RETRY (mkdirat (dfd, dirpath, 0755)) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!glnx_opendirat (dfd, dirpath, TRUE, &dest_dfd, error))
goto out;
if (!copy_dir_contents_nonrecurse_at (dfd, dirpath_tmp, dest_dfd, cancellable, error))
goto out;
if (!glnx_shutil_rm_rf_at (dfd, dirpath_tmp, cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
static void
on_hifstate_percentage_changed (HifState *hifstate,
guint percentage,
gpointer user_data)
{
const char *text = user_data;
glnx_console_progress_text_percent (text, percentage);
}
static gboolean
overlay_packages_in_deploydir (HifContext *hifctx,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
/* --- Run transaction --- */
{ g_auto(GLnxConsoleRef) console = { 0, };
glnx_unref_object HifState *hifstate = hif_state_new ();
guint progress_sigid;
progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Installing: ");
glnx_console_lock (&console);
if (!hif_context_commit (hifctx, hifstate, error))
goto out;
g_signal_handler_disconnect (hifstate, progress_sigid);
}
ret = TRUE;
out:
return ret;
}
static gboolean
pkg_add_transaction_execute (RpmostreedTransaction *transaction,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
PkgAddTransaction *self;
OstreeSysroot *sysroot;
int sysroot_fd; /* Borrowed */
OstreeRepoCheckoutOptions checkout_options = { 0, };
glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
glnx_unref_object OstreeAsyncProgress *progress = NULL;
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
glnx_unref_object OstreeDeployment *new_deployment = NULL;
g_autofree char *merge_deployment_dirpath = NULL;
g_autofree char *tmp_deploy_workdir_name = NULL;
gboolean tmp_deploy_workdir_created = FALSE;
g_autofree char *tmp_deploy_root_path = NULL;
g_autofree char *new_revision = NULL;
glnx_fd_close int merge_deployment_dirfd = -1;
glnx_fd_close int ostree_repo_tmp_dirfd = -1;
glnx_fd_close int deploy_tmp_dirfd = -1;
g_autoptr(GKeyFile) origin = NULL;
gs_unref_object HifContext *hifctx = NULL;
g_autoptr(GHashTable) cur_origin_pkgrequests = g_hash_table_new (g_str_hash, g_str_equal);
g_autoptr(GHashTable) new_pkgrequests = g_hash_table_new (g_str_hash, g_str_equal);
g_autoptr(GHashTable) layer_new_packages = g_hash_table_new (g_str_hash, g_str_equal);
self = (PkgAddTransaction *) transaction;
sysroot = rpmostreed_transaction_get_sysroot (transaction);
sysroot_fd = ostree_sysroot_get_fd (sysroot);
merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, self->osname);
if (merge_deployment == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No deployments found for osname %s", self->osname);
goto out;
}
merge_deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, merge_deployment);
if (!glnx_opendirat (sysroot_fd, merge_deployment_dirpath, TRUE,
&merge_deployment_dirfd, error))
goto out;
if (!glnx_opendirat (sysroot_fd, "ostree/repo/tmp", TRUE,
&ostree_repo_tmp_dirfd, error))
goto out;
upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname, 0,
cancellable, error);
if (upgrader == NULL)
goto out;
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
goto out;
origin = rpmostree_sysroot_upgrader_dup_origin (upgrader);
if (origin == NULL)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Booted deployment has no origin");
goto out;
}
{
const char *cur_origin_refspec =
rpmostree_sysroot_upgrader_get_refspec (upgrader);
const char *const *cur_origin_packages =
rpmostree_sysroot_upgrader_get_packages (upgrader);
const char *const*strviter;
g_assert (cur_origin_refspec);
for (strviter = cur_origin_packages; strviter && *strviter; strviter++)
{
const char *pkg = *strviter;
g_hash_table_add (cur_origin_pkgrequests, (char*)pkg);
g_hash_table_add (new_pkgrequests, (char*)pkg);
}
(void) g_key_file_remove_key (origin, "origin", "refspec", NULL);
g_key_file_set_value (origin, "origin", "baserefspec", cur_origin_refspec);
}
if (!rpmostree_sysroot_upgrader_set_origin (upgrader, origin, cancellable, error))
goto out;
{
char **iter = self->packages;
g_autoptr(RpmOstreeRefSack) rsack = NULL;
rsack = rpmostree_get_refsack_for_root (sysroot_fd,
merge_deployment_dirpath,
cancellable, error);
if (!rsack)
goto out;
for (; iter && *iter; iter++)
{
const char *desired_pkg = *iter;
_cleanup_hyquery_ HyQuery query = NULL;
_cleanup_hypackagelist_ HyPackageList pkglist = NULL;
if (g_hash_table_contains (cur_origin_pkgrequests, desired_pkg))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Package '%s' is already requested", desired_pkg);
goto out;
}
/* It's now requested */
g_hash_table_add (new_pkgrequests, (char*)desired_pkg);
query = hy_query_create (rsack->sack);
hy_query_filter (query, HY_PKG_NAME, HY_EQ, desired_pkg);
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
pkglist = hy_query_run (query);
/* This one tracks whether it actually needs to be installed */
if (hy_packagelist_count (pkglist) == 0)
g_hash_table_add (layer_new_packages, (char*)desired_pkg);
}
}
hifctx = _rpmostree_libhif_new_default ();
{
g_autofree char *reposdir =
g_build_filename (merge_deployment_dirpath, "etc/yum.repos.d", NULL);
hif_context_set_repo_dir (hifctx, reposdir);
}
tmp_deploy_workdir_name = g_strdup ("rpmostree-deploy-XXXXXX");
if (!glnx_mkdtempat (ostree_repo_tmp_dirfd, tmp_deploy_workdir_name, 0755, error))
goto out;
tmp_deploy_workdir_created = TRUE;
tmp_deploy_root_path = g_strconcat (tmp_deploy_workdir_name, "root", NULL);
checkout_options.devino_to_csum_cache = ostree_repo_devino_cache_new ();
if (!ostree_repo_checkout_tree_at (repo, &checkout_options, ostree_repo_tmp_dirfd, tmp_deploy_root_path,
ostree_deployment_get_csum (merge_deployment),
cancellable, error))
goto out;
if (!glnx_opendirat (ostree_repo_tmp_dirfd, tmp_deploy_root_path, TRUE,
&deploy_tmp_dirfd, error))
goto out;
/* Convert usr/share/rpm into physical copies, as librpm mutates it in place */
if (!break_hardlinks_at (deploy_tmp_dirfd, "usr/share/rpm", cancellable, error))
goto out;
/* Temporarily rename /usr/etc to /etc so that RPMs can drop new files there */
if (TEMP_FAILURE_RETRY (renameat (deploy_tmp_dirfd, "usr/etc",
deploy_tmp_dirfd, "etc")) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
{ g_autofree char *tmp_deploy_abspath = glnx_fdrel_abspath (deploy_tmp_dirfd, ".");
hif_context_set_install_root (hifctx, tmp_deploy_abspath);
}
/* Note this path is relative to the install root */
hif_context_set_rpm_macro (hifctx, "_dbpath", "/usr/share/rpm");
if (!_rpmostree_libhif_setup (hifctx, cancellable, error))
goto out;
if (g_hash_table_size (layer_new_packages) > 0)
{
HifTransaction *hiftx;
HyGoal goal;
GHashTableIter hashiter;
gpointer hkey, hvalue;
/* --- Downloading metadata --- */
{ g_auto(GLnxConsoleRef) console = { 0, };
glnx_unref_object HifState *hifstate = hif_state_new ();
guint progress_sigid;
progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Downloading: ");
glnx_console_lock (&console);
if (!hif_context_setup_sack (hifctx, hifstate, error))
goto out;
g_signal_handler_disconnect (hifstate, progress_sigid);
}
hiftx = hif_context_get_transaction (hifctx);
g_hash_table_iter_init (&hashiter, layer_new_packages);
while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue))
{
const char *pkg = hkey;
if (!hif_context_install (hifctx, pkg, error))
goto out;
}
goal = hif_context_get_goal (hifctx);
if (!hif_transaction_depsolve (hiftx, goal, NULL, error))
goto out;
/* --- Downloading packages --- */
{ g_auto(GLnxConsoleRef) console = { 0, };
glnx_unref_object HifState *hifstate = hif_state_new ();
guint progress_sigid;
progress_sigid = g_signal_connect (hifstate, "percentage-changed",
G_CALLBACK (on_hifstate_percentage_changed),
"Downloading: ");
glnx_console_lock (&console);
if (!hif_transaction_download (hiftx, hifstate, error))
goto out;
g_signal_handler_disconnect (hifstate, progress_sigid);
}
/* find any packages without valid GPG signatures */
#if 0
if (!hif_transaction_check_untrusted (hiftx, goal, error))
goto out;
#endif
}
/* Add previous package requests with newly requested packages */
{ gs_unref_ptrarray GPtrArray *new_requested_pkglist = g_ptr_array_new ();
GHashTableIter hashiter;
gpointer hkey, hvalue;
g_hash_table_iter_init (&hashiter, cur_origin_pkgrequests);
while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue))
g_ptr_array_add (new_requested_pkglist, hkey);
g_hash_table_iter_init (&hashiter, layer_new_packages);
while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue))
g_ptr_array_add (new_requested_pkglist, hkey);
g_key_file_set_string_list (origin, "packages", "requested",
(const char*const*)new_requested_pkglist->pdata,
new_requested_pkglist->len);
}
if (!overlay_packages_in_deploydir (hifctx, cancellable, error))
goto out;
/* Clear out any references to the rpmdb, etc. */
g_clear_object (&hifctx);
/* Rename /usr/etc back to /etc */
if (TEMP_FAILURE_RETRY (renameat (deploy_tmp_dirfd, "etc", deploy_tmp_dirfd, "usr/etc")) != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!rpmostree_commit (deploy_tmp_dirfd, repo, NULL, NULL, NULL, TRUE,
checkout_options.devino_to_csum_cache,
&new_revision, cancellable, error))
goto out;
(void) close (deploy_tmp_dirfd);
deploy_tmp_dirfd = -1;
if (!glnx_shutil_rm_rf_at (ostree_repo_tmp_dirfd, tmp_deploy_workdir_name, cancellable, error))
goto out;
tmp_deploy_workdir_created = FALSE;
rpmostree_sysroot_upgrader_set_origin_baseref_local (upgrader, new_revision);
if (!rpmostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (self->reboot)
rpmostreed_reboot (cancellable, error);
ret = TRUE;
out:
if (tmp_deploy_workdir_created)
(void) glnx_shutil_rm_rf_at (ostree_repo_tmp_dirfd, tmp_deploy_workdir_name, NULL, NULL);
if (checkout_options.devino_to_csum_cache)
ostree_repo_devino_cache_unref (checkout_options.devino_to_csum_cache);
return ret;
}
static void
pkg_add_transaction_class_init (PkgAddTransactionClass *class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (class);
object_class->finalize = pkg_add_transaction_finalize;
class->execute = pkg_add_transaction_execute;
}
static void
pkg_add_transaction_init (PkgAddTransaction *self)
{
}
RpmostreedTransaction *
rpmostreed_transaction_new_pkg_add (GDBusMethodInvocation *invocation,
OstreeSysroot *sysroot,
const char *osname,
const char * const *packages,
gboolean reboot,
GCancellable *cancellable,
GError **error)
{
PkgAddTransaction *self;
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
g_return_val_if_fail (OSTREE_IS_SYSROOT (sysroot), NULL);
g_return_val_if_fail (osname != NULL, NULL);
g_return_val_if_fail (packages != NULL, NULL);
self = g_initable_new (pkg_add_transaction_get_type (),
cancellable, error,
"invocation", invocation,
"sysroot", sysroot,
NULL);
if (self != NULL)
{
self->osname = g_strdup (osname);
self->packages = g_strdupv ((char**)packages);
self->reboot = reboot;
}
return (RpmostreedTransaction *) self;
}

View File

@ -26,11 +26,12 @@
#include "rpmostreed-transaction.h"
#include "rpmostreed-deployment-utils.h"
#include "rpmostreed-sysroot.h"
#include "rpmostree-sysroot-upgrader.h"
#include "rpmostreed-utils.h"
static gboolean
change_upgrader_refspec (OstreeSysroot *sysroot,
OstreeSysrootUpgrader *upgrader,
RpmOstreeSysrootUpgrader *upgrader,
const gchar *refspec,
GCancellable *cancellable,
gchar **out_old_refspec,
@ -38,40 +39,30 @@ change_upgrader_refspec (OstreeSysroot *sysroot,
GError **error)
{
gboolean ret = FALSE;
g_autofree gchar *old_refspec = NULL;
const char *current_refspec = rpmostree_sysroot_upgrader_get_refspec (upgrader);
g_autofree gchar *new_refspec = NULL;
g_autoptr(GKeyFile) new_origin = NULL;
GKeyFile *old_origin = NULL; /* owned by deployment */
old_origin = ostree_sysroot_upgrader_get_origin (upgrader);
old_refspec = g_key_file_get_string (old_origin, "origin",
"refspec", NULL);
if (!rpmostreed_refspec_parse_partial (refspec,
old_refspec,
current_refspec,
&new_refspec,
error))
goto out;
if (strcmp (old_refspec, new_refspec) == 0)
if (strcmp (current_refspec, new_refspec) == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Old and new refs are equal: %s", new_refspec);
goto out;
}
new_origin = ostree_sysroot_origin_new_from_refspec (sysroot,
new_refspec);
if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin,
cancellable, error))
if (!rpmostree_sysroot_upgrader_set_origin_rebase (upgrader, new_refspec, error))
goto out;
if (out_new_refspec != NULL)
*out_new_refspec = g_steal_pointer (&new_refspec);
if (out_old_refspec != NULL)
*out_old_refspec = g_steal_pointer (&old_refspec);
*out_old_refspec = g_strdup (current_refspec);
ret = TRUE;
@ -117,30 +108,37 @@ package_diff_transaction_execute (RpmostreedTransaction *transaction,
PackageDiffTransaction *self;
OstreeSysroot *sysroot;
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object OstreeAsyncProgress *progress = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
g_autoptr(GKeyFile) origin = NULL;
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
g_autofree gchar *origin_description = NULL;
OstreeSysrootUpgraderPullFlags upgrader_flags = 0;
RpmOstreeSysrootUpgraderFlags upgrader_flags = 0;
gboolean upgrading = FALSE;
gboolean changed = FALSE;
gboolean ret = FALSE;
self = (PackageDiffTransaction *) transaction;
if (self->revision != NULL)
upgrader_flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER;
sysroot = rpmostreed_transaction_get_sysroot (transaction);
upgrader = ostree_sysroot_upgrader_new_for_os (sysroot,
self->osname,
cancellable,
error);
upgrader = rpmostree_sysroot_upgrader_new (sysroot,
self->osname,
upgrader_flags,
cancellable,
error);
if (upgrader == NULL)
goto out;
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
goto out;
origin = ostree_sysroot_upgrader_dup_origin (upgrader);
merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, self->osname);
self->refspec = g_strdup (rpmostree_sysroot_upgrader_get_refspec (upgrader));
/* Determine if we're upgrading before we set the refspec. */
upgrading = (self->refspec == NULL && self->revision == NULL);
@ -152,15 +150,6 @@ package_diff_transaction_execute (RpmostreedTransaction *transaction,
NULL, NULL, error))
goto out;
}
else if (origin != NULL)
{
self->refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
if (self->refspec == NULL)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not find refspec for booted deployment");
}
}
else
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -177,8 +166,6 @@ package_diff_transaction_execute (RpmostreedTransaction *transaction,
g_autofree char *checksum = NULL;
g_autofree char *version = NULL;
upgrader_flags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER;
if (!rpmostreed_parse_revision (self->revision,
&checksum,
&version,
@ -201,35 +188,26 @@ package_diff_transaction_execute (RpmostreedTransaction *transaction,
goto out;
}
g_key_file_set_string (origin, "origin", "override-commit", checksum);
if (!ostree_sysroot_upgrader_set_origin (upgrader, origin,
cancellable, error))
goto out;
rpmostree_sysroot_upgrader_set_origin_override (upgrader, checksum);
}
else if (upgrading)
{
if (g_key_file_remove_key (origin, "origin", "override-commit", NULL))
{
if (!ostree_sysroot_upgrader_set_origin (upgrader, origin,
cancellable, error))
goto out;
}
rpmostree_sysroot_upgrader_set_origin_override (upgrader, NULL);
}
origin_description = ostree_sysroot_upgrader_get_origin_description (upgrader);
origin_description = rpmostree_sysroot_upgrader_get_origin_description (upgrader);
if (origin_description != NULL)
rpmostreed_transaction_emit_message_printf (transaction,
"Updating from: %s",
origin_description);
if (!ostree_sysroot_upgrader_pull_one_dir (upgrader,
"/usr/share/rpm",
0, upgrader_flags,
progress,
&changed,
cancellable,
error))
if (!rpmostree_sysroot_upgrader_pull (upgrader,
"/usr/share/rpm",
0,
progress,
&changed,
cancellable,
error))
goto out;
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
@ -584,50 +562,36 @@ upgrade_transaction_execute (RpmostreedTransaction *transaction,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
UpgradeTransaction *self;
OstreeSysroot *sysroot;
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
glnx_unref_object OstreeAsyncProgress *progress = NULL;
g_autoptr(GKeyFile) origin = NULL;
g_autofree gchar *origin_description = NULL;
OstreeSysrootUpgraderPullFlags upgrader_pull_flags = 0;
RpmOstreeSysrootUpgraderFlags upgrader_flags = 0;
gboolean changed = FALSE;
gboolean ret = FALSE;
self = (UpgradeTransaction *) transaction;
sysroot = rpmostreed_transaction_get_sysroot (transaction);
upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, self->osname,
cancellable, error);
if (self->allow_downgrade)
upgrader_flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER;
upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname, upgrader_flags,
cancellable, error);
if (upgrader == NULL)
goto out;
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
goto out;
origin = ostree_sysroot_upgrader_dup_origin (upgrader);
if (origin != NULL)
{
/* Strip any override-commit from the origin file so
* we always upgrade to the latest available commit. */
if (g_key_file_remove_key (origin, "origin", "override-commit", NULL))
{
/* XXX GCancellable parameter is not used. */
if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, NULL, error))
goto out;
}
}
rpmostree_sysroot_upgrader_set_origin_override (upgrader, NULL);
if (self->allow_downgrade)
upgrader_pull_flags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER;
origin_description = ostree_sysroot_upgrader_get_origin_description (upgrader);
origin_description = rpmostree_sysroot_upgrader_get_origin_description (upgrader);
if (origin_description != NULL)
rpmostreed_transaction_emit_message_printf (transaction,
"Updating from: %s",
@ -637,16 +601,16 @@ upgrade_transaction_execute (RpmostreedTransaction *transaction,
rpmostreed_transaction_connect_download_progress (transaction, progress);
rpmostreed_transaction_connect_signature_progress (transaction, repo);
if (!ostree_sysroot_upgrader_pull (upgrader, 0, upgrader_pull_flags,
progress, &changed,
cancellable, error))
if (!rpmostree_sysroot_upgrader_pull (upgrader, NULL, 0,
progress, &changed,
cancellable, error))
goto out;
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
if (changed)
{
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
if (!rpmostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (self->reboot)
@ -747,7 +711,7 @@ rebase_transaction_execute (RpmostreedTransaction *transaction,
RebaseTransaction *self;
OstreeSysroot *sysroot;
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
glnx_unref_object OstreeAsyncProgress *progress = NULL;
@ -758,13 +722,22 @@ rebase_transaction_execute (RpmostreedTransaction *transaction,
gboolean changed = FALSE;
gboolean ret = FALSE;
RpmOstreeSysrootUpgraderFlags flags = 0;
self = (RebaseTransaction *) transaction;
sysroot = rpmostreed_transaction_get_sysroot (transaction);
upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, self->osname,
OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED,
cancellable, error);
/* Always allow older; there's not going to be a chronological
* relationship necessarily. */
flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER;
/* We should be able to switch to a different tree even if the current origin
* is unconfigured */
flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED;
upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname, flags,
cancellable, error);
if (upgrader == NULL)
goto out;
@ -780,17 +753,14 @@ rebase_transaction_execute (RpmostreedTransaction *transaction,
rpmostreed_transaction_connect_download_progress (transaction, progress);
rpmostreed_transaction_connect_signature_progress (transaction, repo);
/* Always allow older; there's not going to be a chronological
* relationship necessarily. */
if (!ostree_sysroot_upgrader_pull (upgrader, 0,
OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
progress, &changed,
cancellable, error))
if (!rpmostree_sysroot_upgrader_pull (upgrader, NULL, 0,
progress, &changed,
cancellable, error))
goto out;
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
if (!rpmostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (!self->skip_purge)
@ -904,7 +874,7 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
DeployTransaction *self;
OstreeSysroot *sysroot;
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
glnx_unref_object OstreeAsyncProgress *progress = NULL;
@ -919,15 +889,16 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
sysroot = rpmostreed_transaction_get_sysroot (transaction);
upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, self->osname,
cancellable, error);
upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname,
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER,
cancellable, error);
if (upgrader == NULL)
goto out;
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
goto out;
origin = ostree_sysroot_upgrader_dup_origin (upgrader);
origin = rpmostree_sysroot_upgrader_dup_origin (upgrader);
if (origin == NULL)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -947,13 +918,13 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
if (version != NULL)
{
g_autofree char *refspec = NULL;
const char *refspec = NULL;
rpmostreed_transaction_emit_message_printf (transaction,
"Resolving version '%s'",
version);
refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
refspec = rpmostree_sysroot_upgrader_get_refspec (upgrader);
if (refspec == NULL)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -982,19 +953,18 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
g_key_file_set_comment (origin, "origin", "override-commit", comment, NULL);
}
if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, cancellable, error))
if (!rpmostree_sysroot_upgrader_set_origin (upgrader, origin, cancellable, error))
goto out;
if (!ostree_sysroot_upgrader_pull (upgrader, 0,
OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
progress, &changed, cancellable, error))
if (!rpmostree_sysroot_upgrader_pull (upgrader, NULL, 0,
progress, &changed, cancellable, error))
goto out;
rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction));
if (changed)
{
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
if (!rpmostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (self->reboot)

View File

@ -72,3 +72,12 @@ RpmostreedTransaction *
gboolean reboot,
GCancellable *cancellable,
GError **error);
RpmostreedTransaction *
rpmostreed_transaction_new_pkg_add (GDBusMethodInvocation *invocation,
OstreeSysroot *sysroot,
const char *osname,
const char *const *packages,
gboolean reboot,
GCancellable *cancellable,
GError **error);

View File

@ -130,7 +130,7 @@ rpmostreed_generate_object_path_from_va (const gchar *base,
*/
gboolean
rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec,
gchar *base_refspec,
const gchar *base_refspec,
gchar **out_refspec,
GError **error)
{

View File

@ -31,7 +31,7 @@ gchar * rpmostreed_generate_object_path_from_va (const gchar *base,
va_list va);
gboolean rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec,
gchar *base_refspec,
const gchar *base_refspec,
gchar **out_refspec,
GError **error);
void

View File

@ -695,7 +695,6 @@ workaround_selinux_cross_labeling_recurse (int dfd,
nonbin_name = g_strndup (name, lastdot - name);
g_print ("Setting mtime of '%s' to newer than '%s'\n", nonbin_name, name);
if (TEMP_FAILURE_RETRY (utimensat (dfd_iter.fd, nonbin_name, NULL, 0)) == -1)
{
glnx_set_error_from_errno (error);
@ -1570,12 +1569,14 @@ read_xattrs_cb (OstreeRepo *repo,
}
gboolean
rpmostree_commit (GFile *rootfs,
rpmostree_commit (int rootfs_fd,
OstreeRepo *repo,
const char *refname,
GVariant *metadata,
const char *gpg_keyid,
gboolean enable_selinux,
OstreeRepoDevInoCache *devino_cache,
char **out_new_revision,
GCancellable *cancellable,
GError **error)
{
@ -1586,10 +1587,6 @@ rpmostree_commit (GFile *rootfs,
gs_free char *new_revision = NULL;
gs_unref_object GFile *root_tree = NULL;
gs_unref_object OstreeSePolicy *sepolicy = NULL;
gs_fd_close int rootfs_fd = -1;
if (!gs_file_open_dir_fd (rootfs, &rootfs_fd, cancellable, error))
goto out;
/* hardcode targeted policy for now */
if (enable_selinux)
@ -1598,7 +1595,6 @@ rpmostree_commit (GFile *rootfs,
goto out;
}
g_print ("Committing '%s' ...\n", gs_file_get_path_cached (rootfs));
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
goto out;
@ -1607,12 +1603,9 @@ rpmostree_commit (GFile *rootfs,
ostree_repo_commit_modifier_set_xattr_callback (commit_modifier,
read_xattrs_cb, NULL,
GINT_TO_POINTER (rootfs_fd));
if (sepolicy && ostree_sepolicy_get_name (sepolicy) != NULL)
{
const char *policy_name = ostree_sepolicy_get_name (sepolicy);
g_print ("Labeling with SELinux policy '%s'\n", policy_name);
ostree_repo_commit_modifier_set_sepolicy (commit_modifier, sepolicy);
}
ostree_repo_commit_modifier_set_sepolicy (commit_modifier, sepolicy);
else if (enable_selinux)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -1620,13 +1613,19 @@ rpmostree_commit (GFile *rootfs,
goto out;
}
if (!ostree_repo_write_directory_to_mtree (repo, rootfs, mtree, commit_modifier, cancellable, error))
if (devino_cache)
ostree_repo_commit_modifier_set_devino_cache (commit_modifier, devino_cache);
if (!ostree_repo_write_dfd_to_mtree (repo, rootfs_fd, ".", mtree, commit_modifier, cancellable, error))
goto out;
if (!ostree_repo_write_mtree (repo, mtree, &root_tree, cancellable, error))
goto out;
if (!ostree_repo_resolve_rev (repo, refname, TRUE, &parent_revision, error))
goto out;
if (refname)
{
if (!ostree_repo_resolve_rev (repo, refname, TRUE, &parent_revision, error))
goto out;
}
if (!ostree_repo_write_commit (repo, parent_revision, "", "", metadata,
(OstreeRepoFile*)root_tree, &new_revision,
@ -1635,25 +1634,20 @@ rpmostree_commit (GFile *rootfs,
if (gpg_keyid)
{
g_print ("Signing commit %s with key %s\n", new_revision, gpg_keyid);
if (!ostree_repo_sign_commit (repo, new_revision, gpg_keyid, NULL,
cancellable, error))
goto out;
}
ostree_repo_transaction_set_ref (repo, NULL, refname, new_revision);
if (refname)
ostree_repo_transaction_set_ref (repo, NULL, refname, new_revision);
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
goto out;
g_print ("%s => %s\n", refname, new_revision);
if (!g_getenv ("RPM_OSTREE_PRESERVE_ROOTFS"))
(void) gs_shutil_rm_rf (rootfs, NULL, NULL);
else
g_print ("Preserved %s\n", gs_file_get_path_cached (rootfs));
ret = TRUE;
if (out_new_revision)
*out_new_revision = g_steal_pointer (&new_revision);
out:
return ret;
}

View File

@ -21,7 +21,7 @@
#pragma once
#include <ostree.h>
#include <json-glib/json-glib.h>
#include "rpmostree-json-parsing.h"
gboolean
rpmostree_treefile_postprocessing (GFile *rootfs,
@ -43,12 +43,14 @@ rpmostree_prepare_rootfs_for_commit (GFile *rootfs,
GError **error);
gboolean
rpmostree_commit (GFile *rootfs,
rpmostree_commit (int rootfs_dfd,
OstreeRepo *repo,
const char *refname,
GVariant *metadata,
const char *gpg_keyid,
gboolean enable_selinux,
OstreeRepoDevInoCache *devino_cache,
char **out_new_revision,
GCancellable *cancellable,
GError **error);
gboolean

View File

@ -405,3 +405,51 @@ _rpmostree_util_next_version (const char *auto_version_prefix,
num = g_ascii_strtoull (end, NULL, 10);
return g_strdup_printf ("%s.%llu", auto_version_prefix, num + 1);
}
GKeyFile *
_rpmostree_util_keyfile_clone (GKeyFile *keyfile)
{
GKeyFile *ret = g_key_file_new ();
gsize len;
gs_free char *data = g_key_file_to_data (keyfile, &len, NULL);
gboolean loaded;
loaded = g_key_file_load_from_data (ret, data, len, 0, NULL);
g_assert (loaded);
return ret;
}
gboolean
_rpmostree_util_parse_origin (GKeyFile *origin,
char **out_refspec,
char ***out_packages,
GError **error)
{
gboolean ret = FALSE;
g_autofree char *origin_refspec = NULL;
g_auto(GStrv) origin_packages = NULL;
gboolean origin_is_bare_refspec = TRUE;
origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
if (!origin_refspec)
{
origin_refspec = g_key_file_get_string (origin, "origin", "baserefspec", NULL);
origin_is_bare_refspec = FALSE;
}
if (!origin_refspec)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No origin/refspec or origin/baserefspec in current deployment origin; cannot upgrade via rpm-ostree");
goto out;
}
*out_refspec = g_steal_pointer (&origin_refspec);
if (origin_is_bare_refspec)
*out_packages = NULL;
else
*out_packages = g_key_file_get_string_list (origin, "packages", "requested", NULL, NULL);
ret = TRUE;
out:
return ret;
}

View File

@ -86,3 +86,12 @@ _rpmostree_sync_wait_on_pid (pid_t pid,
char *
_rpmostree_util_next_version (const char *auto_version_prefix,
const char *last_version);
GKeyFile *
_rpmostree_util_keyfile_clone (GKeyFile *keyfile);
gboolean
_rpmostree_util_parse_origin (GKeyFile *origin,
char **out_refspec,
char ***out_packages,
GError **error);