684 lines
24 KiB
C
684 lines
24 KiB
C
/*
|
|
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.0+
|
|
*
|
|
* 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 "ot-main.h"
|
|
#include "ot-builtins.h"
|
|
#include "ostree.h"
|
|
#include "ostree-cmdprivate.h"
|
|
#include "ot-main.h"
|
|
#include "otutil.h"
|
|
|
|
static char *opt_from_rev;
|
|
static char *opt_to_rev;
|
|
static char *opt_min_fallback_size;
|
|
static char *opt_max_bsdiff_size;
|
|
static char *opt_max_chunk_size;
|
|
static char *opt_endianness;
|
|
static char *opt_filename;
|
|
static gboolean opt_empty;
|
|
static gboolean opt_swap_endianness;
|
|
static gboolean opt_inline;
|
|
static gboolean opt_disable_bsdiff;
|
|
static gboolean opt_if_not_exists;
|
|
static char **opt_key_ids;
|
|
static char *opt_sign_name;
|
|
static char *opt_keysfilename;
|
|
static char *opt_keysdir;
|
|
|
|
#define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
|
|
BUILTINPROTO(list);
|
|
BUILTINPROTO(show);
|
|
BUILTINPROTO(delete);
|
|
BUILTINPROTO(generate);
|
|
BUILTINPROTO(apply_offline);
|
|
BUILTINPROTO(verify);
|
|
BUILTINPROTO(indexes);
|
|
BUILTINPROTO(reindex);
|
|
|
|
#undef BUILTINPROTO
|
|
|
|
static OstreeCommand static_delta_subcommands[] = {
|
|
{ "list", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_list,
|
|
"List static delta files" },
|
|
{ "show", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_show,
|
|
"Dump information on a delta" },
|
|
{ "delete", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_delete,
|
|
"Remove a delta" },
|
|
{ "generate", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_generate,
|
|
"Generate static delta files" },
|
|
{ "apply-offline", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_apply_offline,
|
|
"Apply static delta file" },
|
|
{ "verify", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_verify,
|
|
"Verify static delta signatures" },
|
|
{ "indexes", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_indexes,
|
|
"List static delta indexes" },
|
|
{ "reindex", OSTREE_BUILTIN_FLAG_NONE,
|
|
ot_static_delta_builtin_reindex,
|
|
"Regenerate static delta indexes" },
|
|
{ NULL, 0, NULL, NULL }
|
|
};
|
|
|
|
/* ATTENTION:
|
|
* Please remember to update the bash-completion script (bash/ostree) and
|
|
* man page (man/ostree-static-delta.xml) when changing the option list(s).
|
|
*/
|
|
|
|
static GOptionEntry generate_options[] = {
|
|
{ "from", 0, 0, G_OPTION_ARG_STRING, &opt_from_rev, "Create delta from revision REV", "REV" },
|
|
{ "empty", 0, 0, G_OPTION_ARG_NONE, &opt_empty, "Create delta from scratch", NULL },
|
|
{ "inline", 0, 0, G_OPTION_ARG_NONE, &opt_inline, "Inline delta parts into main delta", NULL },
|
|
{ "to", 0, 0, G_OPTION_ARG_STRING, &opt_to_rev, "Create delta to revision REV", "REV" },
|
|
{ "disable-bsdiff", 0, 0, G_OPTION_ARG_NONE, &opt_disable_bsdiff, "Disable use of bsdiff", NULL },
|
|
{ "if-not-exists", 'n', 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Only generate if a delta does not already exist", NULL },
|
|
{ "set-endianness", 0, 0, G_OPTION_ARG_STRING, &opt_endianness, "Choose metadata endianness ('l' or 'B')", "ENDIAN" },
|
|
{ "swap-endianness", 0, 0, G_OPTION_ARG_NONE, &opt_swap_endianness, "Swap metadata endianness from host order", NULL },
|
|
{ "min-fallback-size", 0, 0, G_OPTION_ARG_STRING, &opt_min_fallback_size, "Minimum uncompressed size in megabytes for individual HTTP request", NULL},
|
|
{ "max-bsdiff-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_bsdiff_size, "Maximum size in megabytes to consider bsdiff compression for input files", NULL},
|
|
{ "max-chunk-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_chunk_size, "Maximum size of delta chunks in megabytes", NULL},
|
|
{ "filename", 0, 0, G_OPTION_ARG_FILENAME, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"},
|
|
{ "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Sign the delta with", "KEY_ID"},
|
|
{ "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"},
|
|
#if defined(HAVE_LIBSODIUM)
|
|
{ "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME"},
|
|
#endif
|
|
{ NULL }
|
|
};
|
|
|
|
static GOptionEntry apply_offline_options[] = {
|
|
{ "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"},
|
|
#if defined(HAVE_LIBSODIUM)
|
|
{ "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME"},
|
|
{ "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME"},
|
|
#endif
|
|
{ NULL }
|
|
};
|
|
|
|
static GOptionEntry list_options[] = {
|
|
{ NULL }
|
|
};
|
|
|
|
static GOptionEntry verify_options[] = {
|
|
{ "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"},
|
|
#if defined(HAVE_LIBSODIUM)
|
|
{ "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME"},
|
|
{ "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME"},
|
|
#endif
|
|
{ NULL }
|
|
};
|
|
|
|
static GOptionEntry indexes_options[] = {
|
|
{ NULL }
|
|
};
|
|
|
|
static GOptionEntry reindex_options[] = {
|
|
{ "to", 0, 0, G_OPTION_ARG_STRING, &opt_to_rev, "Only update delta index to revision REV", "REV" },
|
|
{ NULL }
|
|
};
|
|
|
|
static void
|
|
static_delta_usage (char **argv,
|
|
gboolean is_error)
|
|
{
|
|
OstreeCommand *command = static_delta_subcommands;
|
|
void (*print_func) (const gchar *format, ...);
|
|
|
|
if (is_error)
|
|
print_func = g_printerr;
|
|
else
|
|
print_func = g_print;
|
|
|
|
print_func ("Usage:\n");
|
|
print_func (" ostree static-delta [OPTION...] COMMAND\n\n");
|
|
print_func ("Builtin \"static-delta\" Commands:\n");
|
|
|
|
while (command->name)
|
|
{
|
|
if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
|
|
print_func (" %-17s%s\n", command->name, command->description ?: "");
|
|
command++;
|
|
}
|
|
|
|
print_func ("\n");
|
|
}
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_list (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
g_autoptr(GOptionContext) context = g_option_context_new ("");
|
|
if (!ostree_option_context_parse (context, list_options, &argc, &argv,
|
|
invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
g_autoptr(GPtrArray) delta_names = NULL;
|
|
if (!ostree_repo_list_static_delta_names (repo, &delta_names, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (delta_names->len == 0)
|
|
g_print ("(No static deltas)\n");
|
|
else
|
|
{
|
|
for (guint i = 0; i < delta_names->len; i++)
|
|
g_print ("%s\n", (char*)delta_names->pdata[i]);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_indexes (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
g_autoptr(GOptionContext) context = g_option_context_new ("");
|
|
if (!ostree_option_context_parse (context, indexes_options, &argc, &argv,
|
|
invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
g_autoptr(GPtrArray) indexes = NULL;
|
|
if (!ostree_repo_list_static_delta_indexes (repo, &indexes, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (indexes->len == 0)
|
|
g_print ("(No static deltas indexes)\n");
|
|
else
|
|
{
|
|
for (guint i = 0; i < indexes->len; i++)
|
|
g_print ("%s\n", (char*)indexes->pdata[i]);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_reindex (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr(GOptionContext) context = g_option_context_new ("");
|
|
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
if (!ostree_option_context_parse (context, reindex_options, &argc, &argv, invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (!ostree_repo_static_delta_reindex (repo, 0, opt_to_rev, cancellable, error))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_show (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
|
|
g_autoptr(GOptionContext) context = g_option_context_new ("");
|
|
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
if (!ostree_option_context_parse (context, list_options, &argc, &argv, invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (argc < 3)
|
|
{
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"DELTA must be specified");
|
|
return FALSE;
|
|
}
|
|
|
|
const char *delta_id = argv[2];
|
|
|
|
if (!ostree_cmd__private__ ()->ostree_static_delta_dump (repo, delta_id, cancellable, error))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_delete (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr(GOptionContext) context = g_option_context_new ("");
|
|
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
if (!ostree_option_context_parse (context, list_options, &argc, &argv, invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (argc < 3)
|
|
{
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"DELTA must be specified");
|
|
return FALSE;
|
|
}
|
|
|
|
const char *delta_id = argv[2];
|
|
|
|
if (!ostree_cmd__private__ ()->ostree_static_delta_delete (repo, delta_id, cancellable, error))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_generate (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr(GOptionContext) context = g_option_context_new ("[TO]");
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
if (!ostree_option_context_parse (context, generate_options, &argc, &argv, invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (!ostree_ensure_repo_writable (repo, error))
|
|
return FALSE;
|
|
|
|
if (argc >= 3 && opt_to_rev == NULL)
|
|
opt_to_rev = argv[2];
|
|
|
|
if (argc < 3 && opt_to_rev == NULL)
|
|
{
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"TO revision must be specified");
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
const char *from_source;
|
|
g_autofree char *from_resolved = NULL;
|
|
g_autofree char *to_resolved = NULL;
|
|
g_autofree char *from_parent_str = NULL;
|
|
g_autoptr(GVariantBuilder) parambuilder = NULL;
|
|
int endianness;
|
|
|
|
g_assert (opt_to_rev);
|
|
|
|
if (opt_empty)
|
|
{
|
|
if (opt_from_rev)
|
|
{
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Cannot specify both --empty and --from=REV");
|
|
return FALSE;
|
|
}
|
|
from_source = NULL;
|
|
}
|
|
else if (opt_from_rev == NULL)
|
|
{
|
|
from_parent_str = g_strconcat (opt_to_rev, "^", NULL);
|
|
from_source = from_parent_str;
|
|
}
|
|
else
|
|
{
|
|
from_source = opt_from_rev;
|
|
}
|
|
|
|
if (from_source)
|
|
{
|
|
if (!ostree_repo_resolve_rev (repo, from_source, FALSE, &from_resolved, error))
|
|
return FALSE;
|
|
}
|
|
if (!ostree_repo_resolve_rev (repo, opt_to_rev, FALSE, &to_resolved, error))
|
|
return FALSE;
|
|
|
|
if (opt_if_not_exists)
|
|
{
|
|
gboolean does_exist;
|
|
g_autofree char *delta_id = from_resolved ? g_strconcat (from_resolved, "-", to_resolved, NULL) : g_strdup (to_resolved);
|
|
if (!ostree_cmd__private__ ()->ostree_static_delta_query_exists (repo, delta_id, &does_exist, cancellable, error))
|
|
return FALSE;
|
|
if (does_exist)
|
|
{
|
|
g_print ("Delta %s already exists.\n", delta_id);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (opt_endianness)
|
|
{
|
|
if (strcmp (opt_endianness, "l") == 0)
|
|
endianness = G_LITTLE_ENDIAN;
|
|
else if (strcmp (opt_endianness, "B") == 0)
|
|
endianness = G_BIG_ENDIAN;
|
|
else
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Invalid endianness '%s'", opt_endianness);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
endianness = G_BYTE_ORDER;
|
|
|
|
if (opt_swap_endianness)
|
|
{
|
|
switch (endianness)
|
|
{
|
|
case G_LITTLE_ENDIAN:
|
|
endianness = G_BIG_ENDIAN;
|
|
break;
|
|
case G_BIG_ENDIAN:
|
|
endianness = G_LITTLE_ENDIAN;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
parambuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
if (opt_min_fallback_size)
|
|
g_variant_builder_add (parambuilder, "{sv}",
|
|
"min-fallback-size", g_variant_new_uint32 (g_ascii_strtoull (opt_min_fallback_size, NULL, 10)));
|
|
if (opt_max_bsdiff_size)
|
|
g_variant_builder_add (parambuilder, "{sv}",
|
|
"max-bsdiff-size", g_variant_new_uint32 (g_ascii_strtoull (opt_max_bsdiff_size, NULL, 10)));
|
|
if (opt_max_chunk_size)
|
|
g_variant_builder_add (parambuilder, "{sv}",
|
|
"max-chunk-size", g_variant_new_uint32 (g_ascii_strtoull (opt_max_chunk_size, NULL, 10)));
|
|
if (opt_disable_bsdiff)
|
|
g_variant_builder_add (parambuilder, "{sv}",
|
|
"bsdiff-enabled", g_variant_new_boolean (FALSE));
|
|
if (opt_inline)
|
|
g_variant_builder_add (parambuilder, "{sv}",
|
|
"inline-parts", g_variant_new_boolean (TRUE));
|
|
if (opt_filename)
|
|
g_variant_builder_add (parambuilder, "{sv}",
|
|
"filename", g_variant_new_bytestring (opt_filename));
|
|
|
|
g_variant_builder_add (parambuilder, "{sv}", "verbose", g_variant_new_boolean (TRUE));
|
|
if (opt_endianness || opt_swap_endianness)
|
|
g_variant_builder_add (parambuilder, "{sv}", "endianness", g_variant_new_uint32 (endianness));
|
|
|
|
if (opt_key_ids || opt_keysfilename)
|
|
{
|
|
g_autoptr(GPtrArray) key_ids = g_ptr_array_new ();
|
|
|
|
for (char **iter = opt_key_ids; iter != NULL && *iter != NULL; ++iter)
|
|
g_ptr_array_add (key_ids, *iter);
|
|
|
|
if (opt_keysfilename)
|
|
{
|
|
g_autoptr (GFile) keyfile = NULL;
|
|
g_autoptr (GFileInputStream) key_stream_in = NULL;
|
|
g_autoptr (GDataInputStream) key_data_in = NULL;
|
|
|
|
if (!g_file_test (opt_keysfilename, G_FILE_TEST_IS_REGULAR))
|
|
{
|
|
g_warning ("Can't open file '%s' with keys", opt_keysfilename);
|
|
return glnx_throw (error, "File object '%s' is not a regular file", opt_keysfilename);
|
|
}
|
|
|
|
keyfile = g_file_new_for_path (opt_keysfilename);
|
|
key_stream_in = g_file_read (keyfile, NULL, error);
|
|
if (key_stream_in == NULL)
|
|
return FALSE;
|
|
|
|
key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in));
|
|
g_assert (key_data_in != NULL);
|
|
|
|
/* Use simple file format with just a list of base64 public keys per line */
|
|
while (TRUE)
|
|
{
|
|
gsize len = 0;
|
|
g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error);
|
|
g_autoptr (GVariant) sk = NULL;
|
|
|
|
if (*error != NULL)
|
|
return FALSE;
|
|
|
|
if (line == NULL)
|
|
break;
|
|
|
|
// Pass the key as a string
|
|
g_ptr_array_add (key_ids, g_strdup (line));
|
|
}
|
|
}
|
|
|
|
g_autoptr(GVariant) key_ids_v = g_variant_new_strv ((const char *const *)key_ids->pdata,
|
|
key_ids->len);
|
|
g_variant_builder_add (parambuilder, "{s@v}", "sign-key-ids",
|
|
g_variant_new_variant (g_steal_pointer (&key_ids_v)));
|
|
}
|
|
opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
|
|
g_variant_builder_add (parambuilder, "{sv}", "sign-name",
|
|
g_variant_new_bytestring (opt_sign_name));
|
|
|
|
g_print ("Generating static delta:\n");
|
|
g_print (" From: %s\n", from_resolved ? from_resolved : "empty");
|
|
g_print (" To: %s\n", to_resolved);
|
|
{ g_autoptr(GVariant) params = g_variant_ref_sink (g_variant_builder_end (parambuilder));
|
|
if (!ostree_repo_static_delta_generate (repo, OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR,
|
|
from_resolved, to_resolved, NULL,
|
|
params,
|
|
cancellable, error))
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_apply_offline (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr(GOptionContext) context = NULL;
|
|
g_autoptr(OstreeRepo) repo = NULL;
|
|
g_autoptr (OstreeSign) sign = NULL;
|
|
char **key_ids;
|
|
int n_key_ids;
|
|
|
|
context = g_option_context_new ("");
|
|
if (!ostree_option_context_parse (context, apply_offline_options, &argc, &argv, invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (!ostree_ensure_repo_writable (repo, error))
|
|
return FALSE;
|
|
|
|
if (argc < 3)
|
|
{
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"PATH must be specified");
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined(HAVE_LIBSODIUM)
|
|
/* Initialize crypto system */
|
|
opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
|
|
#endif
|
|
|
|
if (opt_sign_name)
|
|
{
|
|
sign = ostree_sign_get_by_name (opt_sign_name, error);
|
|
if (!sign)
|
|
return glnx_throw (error, "Signing type %s is not supported", opt_sign_name);
|
|
|
|
key_ids = argv + 3;
|
|
n_key_ids = argc - 3;
|
|
for (int i = 0; i < n_key_ids; i++)
|
|
{
|
|
g_autoptr (GVariant) pk = g_variant_new_string(key_ids[i]);
|
|
if (!ostree_sign_add_pk(sign, pk, error))
|
|
return FALSE;
|
|
}
|
|
if ((n_key_ids == 0) || opt_keysfilename)
|
|
{
|
|
g_autoptr (GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
g_autoptr (GVariant) options = NULL;
|
|
|
|
/* Use custom directory with public and revoked keys instead of system-wide directories */
|
|
if (opt_keysdir)
|
|
g_variant_builder_add (builder, "{sv}", "basedir", g_variant_new_string (opt_keysdir));
|
|
/* The last chance for verification source -- system files */
|
|
if (opt_keysfilename)
|
|
g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_keysfilename));
|
|
options = g_variant_builder_end (builder);
|
|
|
|
if (!ostree_sign_load_pk (sign, options, error))
|
|
{
|
|
/* If it fails to load system default public keys, consider there no signature engine */
|
|
if (!opt_keysdir && !opt_keysfilename)
|
|
{
|
|
g_clear_error(error);
|
|
g_clear_object(&sign);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *patharg = argv[2];
|
|
g_autoptr(GFile) path = g_file_new_for_path (patharg);
|
|
|
|
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (!ostree_repo_static_delta_execute_offline_with_signature (repo, path, sign, FALSE, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ot_static_delta_builtin_verify (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
g_autoptr (GOptionContext) context = g_option_context_new ("STATIC-DELTA-FILE [KEY-ID...]");
|
|
g_autoptr (OstreeRepo) repo = NULL;
|
|
gboolean verified;
|
|
char **key_ids;
|
|
int n_key_ids;
|
|
|
|
if (!ostree_option_context_parse (context, verify_options, &argc, &argv, invocation, &repo, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (argc < 3)
|
|
{
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"DELTA must be specified");
|
|
return FALSE;
|
|
}
|
|
|
|
opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
|
|
|
|
const char *delta_id = argv[2];
|
|
|
|
g_autoptr (OstreeSign) sign = ostree_sign_get_by_name (opt_sign_name, error);
|
|
if (!sign)
|
|
{
|
|
g_print("Sign-type not supported\n");
|
|
return FALSE;
|
|
}
|
|
|
|
key_ids = argv + 3;
|
|
n_key_ids = argc - 3;
|
|
for (int i = 0; i < n_key_ids; i++)
|
|
{
|
|
g_autoptr (GVariant) pk = g_variant_new_string(key_ids[i]);
|
|
if (!ostree_sign_add_pk(sign, pk, error))
|
|
return FALSE;
|
|
}
|
|
if ((n_key_ids == 0) || opt_keysfilename)
|
|
{
|
|
g_autoptr (GVariantBuilder) builder = NULL;
|
|
g_autoptr (GVariant) options = NULL;
|
|
|
|
builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
/* Use custom directory with public and revoked keys instead of system-wide directories */
|
|
if (opt_keysdir)
|
|
g_variant_builder_add (builder, "{sv}", "basedir", g_variant_new_string (opt_keysdir));
|
|
/* The last chance for verification source -- system files */
|
|
if (opt_keysfilename)
|
|
g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_keysfilename));
|
|
options = g_variant_builder_end (builder);
|
|
|
|
if (!ostree_sign_load_pk (sign, options, error))
|
|
return FALSE;
|
|
}
|
|
|
|
verified = ostree_repo_static_delta_verify_signature (repo, delta_id, sign, NULL, error);
|
|
g_print ("Verification %s\n", verified ? "OK" : "fails");
|
|
|
|
return verified;
|
|
}
|
|
|
|
gboolean
|
|
ostree_builtin_static_delta (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
|
|
{
|
|
gboolean want_help = FALSE;
|
|
const char *cmdname = NULL;
|
|
for (int i = 1; i < argc; i++)
|
|
{
|
|
if (argv[i][0] != '-')
|
|
{
|
|
cmdname = argv[i];
|
|
break;
|
|
}
|
|
else if (g_str_equal (argv[i], "--help") || g_str_equal (argv[i], "-h"))
|
|
{
|
|
want_help = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!cmdname && !want_help)
|
|
{
|
|
static_delta_usage (argv, TRUE);
|
|
return glnx_throw (error, "No command specified");
|
|
}
|
|
|
|
OstreeCommand *command = NULL;
|
|
if (cmdname)
|
|
{
|
|
command = static_delta_subcommands;
|
|
while (command->name)
|
|
{
|
|
if (g_strcmp0 (cmdname, command->name) == 0)
|
|
break;
|
|
command++;
|
|
}
|
|
}
|
|
|
|
if (want_help && command == NULL)
|
|
{
|
|
static_delta_usage (argv, FALSE);
|
|
return TRUE; /* Note early return */
|
|
}
|
|
|
|
if (!command->fn)
|
|
{
|
|
static_delta_usage (argv, TRUE);
|
|
return glnx_throw (error, "Unknown \"static-delta\" subcommand '%s'", cmdname);
|
|
}
|
|
|
|
g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), cmdname);
|
|
g_set_prgname (prgname);
|
|
|
|
OstreeCommandInvocation sub_invocation = { .command = command };
|
|
return command->fn (argc, argv, &sub_invocation, cancellable, error);
|
|
}
|