package layering: major rework

- Move the package layering logic away from pkg-add and into the
  upgrader
- Add pkg-delete
- Add dry-run option

Closes: #289
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon 2016-05-20 14:21:06 -04:00 committed by Atomic Bot
parent a25cdde25c
commit ead1ecdd23
21 changed files with 1452 additions and 447 deletions

View File

@ -42,6 +42,7 @@ librpmostreed_la_SOURCES = \
src/daemon/rpmostreed-transaction-types.h \
src/daemon/rpmostreed-transaction-types.c \
src/daemon/rpmostreed-transaction-pkg-add.c \
src/daemon/rpmostreed-transaction-pkg-delete.c \
src/daemon/rpmostree-package-variants.h \
src/daemon/rpmostree-package-variants.c \
src/daemon/rpmostreed-os.h \

View File

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

14
TODO
View File

@ -25,3 +25,17 @@ Autobuilder
* Write an intelligent scheduler
- Task with same name of newer version wait until old one is done
- Walk infinite test matrix
Package layering
----------------
* Provide a mechanism for updating packages (& pruning older versions)
* Support pkgs which bring their own pps
https://github.com/projectatomic/rpm-ostree/pull/107#issuecomment-205082381
* Support local RPMs installation (though `ostree admin unlock` makes this
easier now, but it's not carried over)
* Add a way to mark commits as valid for multiple policies rather than creating
a new commit everytime we relabel
* Related to the above: store the header metadata in the tree itself rather than
in the commit to avoid duplication across relabeling commits
* Add a --onto option?

@ -1 +1 @@
Subproject commit 08ae6639e522e9b11765245fbecdbbe474ccde98
Subproject commit 40ef5f7400d4f8eed6a8f834917008b33ad4fb4e

View File

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

View File

@ -29,10 +29,12 @@
static char *opt_osname;
static gboolean opt_reboot;
static gboolean opt_dry_run;
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 },
{ "dry-run", 'n', 0, G_OPTION_ARG_NONE, &opt_dry_run, "Exit after printing the transaction", NULL },
{ NULL }
};
@ -42,6 +44,7 @@ get_args_variant (void)
GVariantDict dict;
g_variant_dict_init (&dict, NULL);
g_variant_dict_insert (&dict, "reboot", "b", opt_reboot);
g_variant_dict_insert (&dict, "dry-run", "b", opt_dry_run);
return g_variant_dict_end (&dict);
}
@ -99,7 +102,11 @@ rpmostree_builtin_pkg_add (int argc,
error))
goto out;
if (!opt_reboot)
if (opt_dry_run)
{
g_print ("Exiting because of '--dry-run' option\n");
}
else if (!opt_reboot)
{
const char *sysroot_path;

View File

@ -0,0 +1,128 @@
/* -*- 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 gboolean opt_dry_run;
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 },
{ "dry-run", 'n', 0, G_OPTION_ARG_NONE, &opt_dry_run, "Exit after printing the transaction", NULL },
{ NULL }
};
static GVariant *
get_args_variant (void)
{
GVariantDict dict;
g_variant_dict_init (&dict, NULL);
g_variant_dict_insert (&dict, "reboot", "b", opt_reboot);
g_variant_dict_insert (&dict, "dry-run", "b", opt_dry_run);
return g_variant_dict_end (&dict);
}
int
rpmostree_builtin_pkg_delete (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...] - Remove previously 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_delete_sync (os_proxy,
get_args_variant (),
(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_dry_run)
{
g_print ("Exiting because of '--dry-run' option\n");
}
else if (!opt_reboot)
{
const char *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

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

View File

@ -178,6 +178,12 @@
<arg type="s" name="transaction_address" direction="out"/>
</method>
<method name="PkgDelete">
<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">

File diff suppressed because it is too large Load Diff

View File

@ -36,13 +36,18 @@ typedef struct RpmOstreeSysrootUpgrader RpmOstreeSysrootUpgrader;
* RpmOstreeSysrootUpgraderFlags:
* @RPMOSTREE_SYSROOT_UPGRADER_FLAGS_NONE: No options
* @RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED: Do not error if the origin has an unconfigured-state key
* @RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER: Do not error if the new deployment was composed earlier than the current deployment
* @RPMOSTREE_SYSROOT_UPGRADER_FLAGS_REDEPLOY: Use the same revision as the current deployment
* @RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_DRY_RUN: If layering packages, only print the transaction
*
* 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)
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_NONE = (1 << 0),
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED = (1 << 1),
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER = (1 << 2),
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_REDEPLOY = (1 << 3),
RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_DRY_RUN = (1 << 4)
} RpmOstreeSysrootUpgraderFlags;
GType rpmostree_sysroot_upgrader_get_type (void);
@ -55,6 +60,7 @@ RpmOstreeSysrootUpgrader *rpmostree_sysroot_upgrader_new (OstreeSysroot
GCancellable *cancellable,
GError **error);
OstreeDeployment* rpmostree_sysroot_upgrader_get_merge_deployment (RpmOstreeSysrootUpgrader *self);
const char *rpmostree_sysroot_upgrader_get_refspec (RpmOstreeSysrootUpgrader *self);
const char *const*rpmostree_sysroot_upgrader_get_packages (RpmOstreeSysrootUpgrader *self);
@ -65,6 +71,25 @@ 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_set_origin_rebase (RpmOstreeSysrootUpgrader *self,
const char *new_refspec,
GError **error);
void rpmostree_sysroot_upgrader_set_origin_override (RpmOstreeSysrootUpgrader *self,
const char *override_commit);
gboolean
rpmostree_sysroot_upgrader_add_packages (RpmOstreeSysrootUpgrader *self,
char **new_packages,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_sysroot_upgrader_delete_packages (RpmOstreeSysrootUpgrader *self,
char **packages,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_sysroot_upgrader_pull (RpmOstreeSysrootUpgrader *self,
const char *dir_to_pull,
@ -79,9 +104,4 @@ 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

@ -711,7 +711,6 @@ os_handle_pkg_add (RPMOSTreeOS *interface,
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;
@ -719,6 +718,7 @@ os_handle_pkg_add (RPMOSTreeOS *interface,
GVariantDict options_dict;
const char *osname;
gboolean opt_reboot = FALSE;
gboolean opt_dry_run = FALSE;
GError *local_error = NULL;
/* If a compatible transaction is in progress, share its bus address. */
@ -748,6 +748,9 @@ os_handle_pkg_add (RPMOSTreeOS *interface,
g_variant_dict_lookup (&options_dict,
"reboot", "b",
&opt_reboot);
g_variant_dict_lookup (&options_dict,
"dry-run", "b",
&opt_dry_run);
g_variant_dict_clear (&options_dict);
transaction = rpmostreed_transaction_new_pkg_add (invocation,
@ -755,6 +758,7 @@ os_handle_pkg_add (RPMOSTreeOS *interface,
osname,
arg_packages,
opt_reboot,
opt_dry_run,
cancellable,
&local_error);
@ -778,6 +782,83 @@ out:
return TRUE;
}
static gboolean
os_handle_pkg_delete (RPMOSTreeOS *interface,
GDBusMethodInvocation *invocation,
GVariant *arg_options,
const char * const *arg_packages)
{
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;
gboolean opt_dry_run = 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_lookup (&options_dict,
"dry-run", "b",
&opt_dry_run);
g_variant_dict_clear (&options_dict);
transaction = rpmostreed_transaction_new_pkg_delete (invocation,
ot_sysroot,
osname,
arg_packages,
opt_reboot,
opt_dry_run,
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_delete (interface, invocation, client_address);
}
return TRUE;
}
static gboolean
os_handle_get_cached_rebase_rpm_diff (RPMOSTreeOS *interface,
GDBusMethodInvocation *invocation,
@ -1152,6 +1233,7 @@ rpmostreed_os_iface_init (RPMOSTreeOSIface *iface)
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_pkg_delete = os_handle_pkg_delete;
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

@ -43,6 +43,7 @@ typedef struct {
char *osname;
char **packages;
gboolean reboot;
gboolean dry_run;
} PkgAddTransaction;
typedef RpmostreedTransactionClass PkgAddTransactionClass;
@ -65,407 +66,37 @@ pkg_add_transaction_finalize (GObject *object)
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, };
PkgAddTransaction *self = NULL;
OstreeSysroot *sysroot = NULL;
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;
HifContext *hifctx = NULL;
g_autoptr(RpmOstreeContext) ctx = 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);
int flags = RPMOSTREE_SYSROOT_UPGRADER_FLAGS_REDEPLOY;
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;
}
if (self->dry_run)
flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_DRY_RUN;
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);
upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname, flags,
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,
"Merge deployment has no origin");
if (error && *error == NULL)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not create sysroot upgrader");
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))
if (!rpmostree_sysroot_upgrader_add_packages (upgrader, self->packages,
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;
HyQuery query = NULL;
g_autoptr(GPtrArray) 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 (pkglist->len == 0)
g_hash_table_add (layer_new_packages, (char*)desired_pkg);
if (query)
hy_query_free (query);
}
}
ctx = rpmostree_context_new_system (cancellable, error);
if (!ctx)
goto out;
hifctx = rpmostree_context_get_hif (ctx);
{
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 (!hif_context_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 metadata: ");
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;
/* 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;
@ -474,10 +105,6 @@ pkg_add_transaction_execute (RpmostreedTransaction *transaction,
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;
}
@ -503,6 +130,7 @@ rpmostreed_transaction_new_pkg_add (GDBusMethodInvocation *invocation,
const char *osname,
const char * const *packages,
gboolean reboot,
gboolean dry_run,
GCancellable *cancellable,
GError **error)
{
@ -524,6 +152,7 @@ rpmostreed_transaction_new_pkg_add (GDBusMethodInvocation *invocation,
self->osname = g_strdup (osname);
self->packages = g_strdupv ((char**)packages);
self->reboot = reboot;
self->dry_run = dry_run;
}
return (RpmostreedTransaction *) self;

View File

@ -0,0 +1,159 @@
/*
* 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-postprocess.h"
#include "rpmostree-rpm-util.h"
#include "rpmostree-core.h"
typedef struct {
RpmostreedTransaction parent;
char *osname;
char **packages;
gboolean reboot;
gboolean dry_run;
} PkgDeleteTransaction;
typedef RpmostreedTransactionClass PkgDeleteTransactionClass;
GType pkg_delete_transaction_get_type (void);
G_DEFINE_TYPE (PkgDeleteTransaction,
pkg_delete_transaction,
RPMOSTREED_TYPE_TRANSACTION)
static void
pkg_delete_transaction_finalize (GObject *object)
{
PkgDeleteTransaction *self;
self = (PkgDeleteTransaction *) object;
g_free (self->osname);
g_strfreev (self->packages);
G_OBJECT_CLASS (pkg_delete_transaction_parent_class)->finalize (object);
}
static gboolean
pkg_delete_transaction_execute (RpmostreedTransaction *transaction,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
PkgDeleteTransaction *self = NULL;
OstreeSysroot *sysroot = NULL;
glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL;
int flags = RPMOSTREE_SYSROOT_UPGRADER_FLAGS_REDEPLOY;
self = (PkgDeleteTransaction *) transaction;
sysroot = rpmostreed_transaction_get_sysroot (transaction);
if (self->dry_run)
flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_DRY_RUN;
upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname, flags,
cancellable, error);
if (upgrader == NULL)
{
if (error && *error == NULL)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not create sysroot upgrader");
goto out;
}
if (!rpmostree_sysroot_upgrader_delete_packages (upgrader, self->packages,
cancellable, error))
goto out;
if (!rpmostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (self->reboot)
rpmostreed_reboot (cancellable, error);
ret = TRUE;
out:
return ret;
}
static void
pkg_delete_transaction_class_init (PkgDeleteTransactionClass *class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (class);
object_class->finalize = pkg_delete_transaction_finalize;
class->execute = pkg_delete_transaction_execute;
}
static void
pkg_delete_transaction_init (PkgDeleteTransaction *self)
{
}
RpmostreedTransaction *
rpmostreed_transaction_new_pkg_delete (GDBusMethodInvocation *invocation,
OstreeSysroot *sysroot,
const char *osname,
const char * const *packages,
gboolean reboot,
gboolean dry_run,
GCancellable *cancellable,
GError **error)
{
PkgDeleteTransaction *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_delete_transaction_get_type (),
cancellable, error,
"invocation", invocation,
"sysroot-path", gs_file_get_path_cached (ostree_sysroot_get_path (sysroot)),
NULL);
if (self != NULL)
{
self->osname = g_strdup (osname);
self->packages = g_strdupv ((char**)packages);
self->reboot = reboot;
self->dry_run = dry_run;
}
return (RpmostreedTransaction *) self;
}

View File

@ -79,5 +79,16 @@ RpmostreedTransaction *
const char *osname,
const char *const *packages,
gboolean reboot,
gboolean dry_run,
GCancellable *cancellable,
GError **error);
RpmostreedTransaction *
rpmostreed_transaction_new_pkg_delete (GDBusMethodInvocation *invocation,
OstreeSysroot *sysroot,
const char *osname,
const char *const *packages,
gboolean reboot,
gboolean dry_run,
GCancellable *cancellable,
GError **error);

View File

@ -708,7 +708,7 @@ workaround_selinux_cross_labeling_recurse (int dfd,
return ret;
}
static gboolean
gboolean
rpmostree_prepare_rootfs_get_sepolicy (int dfd,
const char *path,
OstreeSePolicy **out_sepolicy,

View File

@ -36,6 +36,13 @@ rpmostree_rootfs_postprocess_common (int rootfs_fd,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_prepare_rootfs_get_sepolicy (int dfd,
const char *path,
OstreeSePolicy **out_sepolicy,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_prepare_rootfs_for_commit (GFile *rootfs,
JsonObject *treefile,

View File

@ -703,6 +703,7 @@ rpmrev_free (struct RpmRevisionData *ptr)
gboolean
rpmostree_checkout_only_rpmdb_tempdir (OstreeRepo *repo,
const char *ref,
const char *template,
char **out_tempdir,
int *out_tempdir_dfd,
GCancellable *cancellable,
@ -716,7 +717,7 @@ rpmostree_checkout_only_rpmdb_tempdir (OstreeRepo *repo,
g_return_val_if_fail (out_tempdir != NULL, FALSE);
if (!rpmostree_mkdtemp ("/tmp/rpmostree-dbquery-XXXXXX", &tempdir, &tempdir_dfd, error))
if (!rpmostree_mkdtemp (template, &tempdir, &tempdir_dfd, error))
goto out;
if (!ostree_repo_resolve_rev (repo, ref, FALSE, &commit, error))
@ -772,6 +773,8 @@ get_sack_for_root (int dfd,
g_return_val_if_fail (out_sack != NULL, FALSE);
sack = hif_sack_new ();
hif_sack_set_rootdir (sack, fullpath);
if (!hif_sack_setup (sack, HIF_SACK_LOAD_FLAG_BUILD_CACHE, error))
goto out;
@ -813,11 +816,13 @@ rpmostree_get_refsack_for_commit (OstreeRepo *repo,
g_autofree char *tempdir = NULL;
glnx_fd_close int tempdir_dfd = -1;
HifSack *hsack;
if (!rpmostree_checkout_only_rpmdb_tempdir (repo, ref, &tempdir, &tempdir_dfd,
if (!rpmostree_checkout_only_rpmdb_tempdir (repo, ref,
"/tmp/rpmostree-dbquery-XXXXXX",
&tempdir, &tempdir_dfd,
cancellable, error))
goto out;
if (!get_sack_for_root (tempdir_dfd, ".",
&hsack, cancellable, error))
goto out;
@ -842,7 +847,9 @@ rpmostree_get_refts_for_commit (OstreeRepo *repo,
rpmts ts;
int r;
if (!rpmostree_checkout_only_rpmdb_tempdir (repo, ref, &tempdir, NULL,
if (!rpmostree_checkout_only_rpmdb_tempdir (repo, ref,
"/tmp/rpmostree-dbquery-XXXXXX",
&tempdir, NULL,
cancellable, error))
goto out;

View File

@ -85,6 +85,7 @@ GS_DEFINE_CLEANUP_FUNCTION0(struct RpmRevisionData *, _cleanup_rpmrev_free, rpmr
gboolean
rpmostree_checkout_only_rpmdb_tempdir (OstreeRepo *repo,
const char *ref,
const char *template,
char **out_tempdir,
int *out_tempdir_dfd,
GCancellable *cancellable,

View File

@ -427,7 +427,6 @@ _rpmostree_util_parse_origin (GKeyFile *origin,
{
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);
@ -443,13 +442,74 @@ _rpmostree_util_parse_origin (GKeyFile *origin,
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);
if (out_refspec)
*out_refspec = g_steal_pointer (&origin_refspec);
if (out_packages)
{
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;
}
gboolean
rpmostree_split_path_ptrarray_validate (const char *path,
GPtrArray **out_components,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GPtrArray) ret_components = NULL;
if (strlen (path) > PATH_MAX)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Path '%s' is too long", path);
goto out;
}
ret_components = g_ptr_array_new_with_free_func (g_free);
do
{
const char *p = strchr (path, '/');
g_autofree char *component = NULL;
if (!p)
{
component = g_strdup (path);
path = NULL;
}
else
{
component = g_strndup (path, p - path);
path = p + 1;
}
if (!component[0])
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid empty component in path '%s'", path);
goto out;
}
if (g_str_equal (component, ".") ||
g_str_equal (component, ".."))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid special element '.' or '..' in path %s", path);
goto out;
}
g_ptr_array_add (ret_components, (char*)g_steal_pointer (&component));
} while (path && *path);
ret = TRUE;
*out_components = g_steal_pointer (&ret_components);
out:
return ret;
}

View File

@ -95,3 +95,8 @@ _rpmostree_util_parse_origin (GKeyFile *origin,
char **out_refspec,
char ***out_packages,
GError **error);
gboolean
rpmostree_split_path_ptrarray_validate (const char *path,
GPtrArray **out_components,
GError **error);