From 98d5f6e3db376ca0a7ab5f505474a0105bee19a7 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 27 Jan 2016 22:02:36 -0500 Subject: [PATCH] static-delta: Add `show` subcommand Right now though, almost all of the details of deltas are private, so we can't do the "honest thing" and have the command line just use the shared library. Eventually some of this should appear in the API, but for now add command line which is useful for debugging. --- src/libostree/ostree-cmdprivate.c | 4 +- src/libostree/ostree-cmdprivate.h | 1 + src/libostree/ostree-repo-static-delta-core.c | 93 +++++++++++++++++++ .../ostree-repo-static-delta-private.h | 11 +++ src/libotutil/ot-variant-utils.c | 22 +++++ src/libotutil/ot-variant-utils.h | 7 ++ src/ostree/ot-builtin-static-delta.c | 35 +++++++ 7 files changed, 172 insertions(+), 1 deletion(-) diff --git a/src/libostree/ostree-cmdprivate.c b/src/libostree/ostree-cmdprivate.c index 99834937..74c32a3c 100644 --- a/src/libostree/ostree-cmdprivate.c +++ b/src/libostree/ostree-cmdprivate.c @@ -23,6 +23,7 @@ #include "ostree-cmdprivate.h" #include "ostree-repo-private.h" #include "ostree-core-private.h" +#include "ostree-repo-static-delta-private.h" #include "ostree-sysroot.h" #include "ostree-bootloader-grub2.h" @@ -44,7 +45,8 @@ const OstreeCmdPrivateVTable * ostree_cmd__private__ (void) { static OstreeCmdPrivateVTable table = { - impl_ostree_generate_grub2_config + impl_ostree_generate_grub2_config, + _ostree_repo_static_delta_dump }; return &table; diff --git a/src/libostree/ostree-cmdprivate.h b/src/libostree/ostree-cmdprivate.h index 317a7592..7746406b 100644 --- a/src/libostree/ostree-cmdprivate.h +++ b/src/libostree/ostree-cmdprivate.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS typedef struct { gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error); + gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error); } OstreeCmdPrivateVTable; const OstreeCmdPrivateVTable * diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c index b2ffddc5..bc1b460c 100644 --- a/src/libostree/ostree-repo-static-delta-core.c +++ b/src/libostree/ostree-repo-static-delta-core.c @@ -22,6 +22,7 @@ #include "ostree-core-private.h" #include "ostree-repo-private.h" +#include "ostree-cmdprivate.h" #include "ostree-repo-static-delta-private.h" #include "otutil.h" @@ -404,3 +405,95 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self, out: return ret; } + +gboolean +_ostree_repo_static_delta_dump (OstreeRepo *self, + const char *delta_id, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_autofree char *superblock_path = NULL; + glnx_fd_close int superblock_fd = -1; + g_autoptr(GVariant) delta_superblock = NULL; + guint64 total_size = 0, total_usize = 0; + guint64 total_fallback_size = 0, total_fallback_usize = 0; + guint i; + + _ostree_parse_delta_name (delta_id, &from, &to); + superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to); + + if (!ot_util_variant_map_at (self->repo_dir_fd, superblock_path, + (GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT, + TRUE, &delta_superblock, error)) + goto out; + + g_print ("Delta: %s\n", delta_id); + { guint64 ts; + g_variant_get_child (delta_superblock, 1, "t", &ts); + g_print ("Timestamp: %" G_GUINT64_FORMAT "\n", GUINT64_FROM_BE (ts)); + } + { g_autoptr(GVariant) recurse = NULL; + g_variant_get_child (delta_superblock, 5, "@ay", &recurse); + g_print ("Number of parents: %u\n", (guint)(g_variant_get_size (recurse) / (OSTREE_SHA256_DIGEST_LEN * 2))); + } + { g_autoptr(GVariant) fallback = NULL; + guint n_fallback; + + g_variant_get_child (delta_superblock, 7, "@a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT, &fallback); + n_fallback = g_variant_n_children (fallback); + + g_print ("Number of fallback entries: %u\n", n_fallback); + + for (i = 0; i < n_fallback; i++) + { + guint64 size, usize; + g_variant_get_child (fallback, i, "(y@aytt)", NULL, NULL, &size, &usize); + total_fallback_size += size; + total_fallback_usize += usize; + } + { g_autofree char *sizestr = g_format_size (total_fallback_size); + g_autofree char *usizestr = g_format_size (total_fallback_usize); + g_print ("Total Fallback Size: %" G_GUINT64_FORMAT " (%s)\n", total_fallback_size, sizestr); + g_print ("Total Fallback Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", total_fallback_usize, usizestr); + } + } + { g_autoptr(GVariant) meta_entries = NULL; + guint n_parts; + + g_variant_get_child (delta_superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries); + n_parts = g_variant_n_children (meta_entries); + g_print ("Number of parts: %u\n", n_parts); + + for (i = 0; i < n_parts; i++) + { + guint32 version; + guint64 size, usize; + g_autoptr(GVariant) objects = NULL; + g_variant_get_child (meta_entries, i, "(u@aytt@ay)", &version, NULL, &size, &usize, &objects); + total_size += size; + total_usize += usize; + g_print ("Part%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n", + i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize); + } + } + + { g_autofree char *sizestr = g_format_size (total_size); + g_autofree char *usizestr = g_format_size (total_usize); + g_print ("Total Part Size: %" G_GUINT64_FORMAT " (%s)\n", total_size, sizestr); + g_print ("Total Part Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", total_usize, usizestr); + } + { guint64 overall_size = total_size + total_fallback_size; + guint64 overall_usize = total_usize + total_fallback_usize; + g_autofree char *sizestr = g_format_size (overall_size); + g_autofree char *usizestr = g_format_size (overall_usize); + g_print ("Total Size: %" G_GUINT64_FORMAT " (%s)\n", overall_size, sizestr); + g_print ("Total Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", overall_usize, usizestr); + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/libostree/ostree-repo-static-delta-private.h b/src/libostree/ostree-repo-static-delta-private.h index de32ec65..b0e82ade 100644 --- a/src/libostree/ostree-repo-static-delta-private.h +++ b/src/libostree/ostree-repo-static-delta-private.h @@ -103,6 +103,11 @@ G_BEGIN_DECLS */ #define OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT "(a{sv}tayay" OSTREE_COMMIT_GVARIANT_STRING "aya" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")" +gboolean _ostree_static_delta_dump (OstreeRepo *repo, + const char *delta_id, + GCancellable *cancellable, + GError **error); + gboolean _ostree_static_delta_part_validate (OstreeRepo *repo, GInputStream *in, guint part_offset, @@ -177,4 +182,10 @@ _ostree_delta_compute_similar_objects (OstreeRepo *repo, GCancellable *cancellable, GError **error); +gboolean +_ostree_repo_static_delta_dump (OstreeRepo *repo, + const char *delta_id, + GCancellable *cancellable, + GError **error); + G_END_DECLS diff --git a/src/libotutil/ot-variant-utils.c b/src/libotutil/ot-variant-utils.c index 1210a785..ed650268 100644 --- a/src/libotutil/ot-variant-utils.c +++ b/src/libotutil/ot-variant-utils.c @@ -154,6 +154,28 @@ ot_util_variant_map (GFile *src, return ret; } +gboolean +ot_util_variant_map_at (int dfd, + const char *path, + const GVariantType *type, + gboolean trusted, + GVariant **out_variant, + GError **error) +{ + glnx_fd_close int fd = -1; + g_autoptr(GVariant) ret_variant = NULL; + + fd = openat (dfd, path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + glnx_set_error_from_errno (error); + g_prefix_error (error, "Opening %s: ", path); + return FALSE; + } + + return ot_util_variant_map_fd (fd, 0, type, trusted, out_variant, error); +} + typedef struct { gpointer addr; gsize len; diff --git a/src/libotutil/ot-variant-utils.h b/src/libotutil/ot-variant-utils.h index 34b6eb5d..1a7abe0e 100644 --- a/src/libotutil/ot-variant-utils.h +++ b/src/libotutil/ot-variant-utils.h @@ -48,6 +48,13 @@ gboolean ot_util_variant_map (GFile *src, GVariant **out_variant, GError **error); +gboolean ot_util_variant_map_at (int dfd, + const char *path, + const GVariantType *type, + gboolean trusted, + GVariant **out_variant, + GError **error); + gboolean ot_util_variant_map_fd (int fd, goffset offset, const GVariantType *type, diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index 903e5fd6..c3c99ba0 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -23,6 +23,7 @@ #include "ot-main.h" #include "ot-builtins.h" #include "ostree.h" +#include "ostree-cmdprivate.h" #include "ot-main.h" #include "otutil.h" @@ -38,6 +39,7 @@ static gboolean opt_disable_bsdiff; #define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, GCancellable *cancellable, GError **error) BUILTINPROTO(list); +BUILTINPROTO(show); BUILTINPROTO(generate); BUILTINPROTO(apply_offline); @@ -45,6 +47,7 @@ BUILTINPROTO(apply_offline); static OstreeCommand static_delta_subcommands[] = { { "list", ot_static_delta_builtin_list }, + { "show", ot_static_delta_builtin_show }, { "generate", ot_static_delta_builtin_generate }, { "apply-offline", ot_static_delta_builtin_apply_offline }, { NULL, NULL } @@ -129,6 +132,38 @@ ot_static_delta_builtin_list (int argc, char **argv, GCancellable *cancellable, return ret; } +static gboolean +ot_static_delta_builtin_show (int argc, char **argv, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + GOptionContext *context; + glnx_unref_object OstreeRepo *repo = NULL; + const char *delta_id = NULL; + + context = g_option_context_new ("SHOW - Dump information on a delta"); + + if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) + goto out; + + if (argc < 3) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "DELTA must be specified"); + goto out; + } + + delta_id = argv[2]; + + if (!ostree_cmd__private__ ()->ostree_static_delta_dump (repo, delta_id, cancellable, error)) + goto out; + + ret = TRUE; + out: + if (context) + g_option_context_free (context); + return ret; +} + static gboolean ot_static_delta_builtin_generate (int argc, char **argv, GCancellable *cancellable, GError **error) {