New upstream version 2018.1
This commit is contained in:
commit
e91328b9e9
64 files changed
+1078
-363
No files matched your search
@@ -17,10 +17,14 @@
|
||||
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
|
||||
# Gracefully exit if ostree is not installed
|
||||
# Gracefully exit if ostree is not installed, or there's
|
||||
# no system repository initialized.
|
||||
if ! which ostree >/dev/null 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
if ! test -d /ostree/repo; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Make sure we're in the right environment
|
||||
if ! test -n "${GRUB_DEVICE}"; then
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# To use a custrom script for generating grub.cfg, set the --with-grub2-mkconfig=no
|
||||
# configure switch when configuring and building OSTree.
|
||||
# The builtin grub.cfg generator.
|
||||
#
|
||||
# This script is called by ostree/src/libostree/ostree-bootloader-grub2.c whenever
|
||||
# boot loader configuration file needs to be updated. It can be used as a template
|
||||
@@ -28,7 +27,7 @@ entries_path=$(dirname $new_grub2_cfg)/entries
|
||||
|
||||
read_config()
|
||||
{
|
||||
config_file=${entries_path}/${1}
|
||||
config_file=${1}
|
||||
title=""
|
||||
initrd=""
|
||||
options=""
|
||||
@@ -67,11 +66,13 @@ populate_menu()
|
||||
else
|
||||
boot_prefix="${OSTREE_BOOT_PARTITION}"
|
||||
fi
|
||||
for config in $(ls ${entries_path}); do
|
||||
for config in $(ls $entries_path/*.conf); do
|
||||
read_config ${config}
|
||||
menu="${menu}menuentry '${title}' {\n"
|
||||
menu="${menu}\t linux ${boot_prefix}${linux} ${options}\n"
|
||||
menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
|
||||
if [ -n "${initrd}" ] ; then
|
||||
menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
|
||||
fi
|
||||
menu="${menu}}\n\n"
|
||||
done
|
||||
# The printf command seems to be more reliable across shells for special character (\n, \t) evaluation
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
***/
|
||||
|
||||
/* Add new symbols here. Release commits should copy this section into -released.sym. */
|
||||
LIBOSTREE_2017.16 {
|
||||
} LIBOSTREE_2017.15;
|
||||
LIBOSTREE_2018.2 {
|
||||
} LIBOSTREE_2018.1;
|
||||
|
||||
/* Stub section for the stable release *after* this development one; don't
|
||||
* edit this other than to update the last number. This is just a copy/paste
|
||||
|
||||
@@ -451,6 +451,9 @@ LIBOSTREE_2017.15 {
|
||||
ostree_break_hardlink;
|
||||
} LIBOSTREE_2017.14;
|
||||
|
||||
LIBOSTREE_2018.1 {
|
||||
} LIBOSTREE_2017.15;
|
||||
|
||||
/* NOTE: Only add more content here in release commits! See the
|
||||
* comments at the top of this file.
|
||||
*/
|
||||
@@ -164,6 +164,17 @@ _ostree_loose_path (char *buf,
|
||||
OstreeObjectType objtype,
|
||||
OstreeRepoMode repo_mode);
|
||||
|
||||
gboolean _ostree_validate_structureof_metadata (OstreeObjectType objtype,
|
||||
GVariant *commit,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_verify_metadata_object (OstreeObjectType objtype,
|
||||
const char *expected_checksum,
|
||||
GVariant *metadata,
|
||||
GError **error);
|
||||
|
||||
|
||||
#define _OSTREE_METADATA_GPGSIGS_NAME "ostree.gpgsigs"
|
||||
#define _OSTREE_METADATA_GPGSIGS_TYPE G_VARIANT_TYPE ("aay")
|
||||
|
||||
|
||||
@@ -2071,6 +2071,74 @@ validate_variant (GVariant *variant,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* TODO: make this public later; just wraps the previously public
|
||||
* commit/dirtree/dirmeta verifiers.
|
||||
*/
|
||||
gboolean
|
||||
_ostree_validate_structureof_metadata (OstreeObjectType objtype,
|
||||
GVariant *metadata,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype));
|
||||
|
||||
switch (objtype)
|
||||
{
|
||||
case OSTREE_OBJECT_TYPE_COMMIT:
|
||||
if (!ostree_validate_structureof_commit (metadata, error))
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_DIR_TREE:
|
||||
if (!ostree_validate_structureof_dirtree (metadata, error))
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_DIR_META:
|
||||
if (!ostree_validate_structureof_dirmeta (metadata, error))
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT:
|
||||
case OSTREE_OBJECT_TYPE_COMMIT_META:
|
||||
/* TODO */
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_FILE:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Used by fsck as well as pull. Verify the checksum of a metadata object
|
||||
* and its "structure" or the additional schema we impose on GVariants such
|
||||
* as ensuring the "ay" checksum entries are of length 32. Another important
|
||||
* one is checking for path traversal in dirtree objects.
|
||||
*/
|
||||
gboolean
|
||||
_ostree_verify_metadata_object (OstreeObjectType objtype,
|
||||
const char *expected_checksum,
|
||||
GVariant *metadata,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (expected_checksum);
|
||||
|
||||
g_auto(OtChecksum) hasher = { 0, };
|
||||
ot_checksum_init (&hasher);
|
||||
ot_checksum_update (&hasher, g_variant_get_data (metadata), g_variant_get_size (metadata));
|
||||
|
||||
char actual_checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
ot_checksum_get_hexdigest (&hasher, actual_checksum, sizeof (actual_checksum));
|
||||
if (!_ostree_compare_object_checksum (objtype, expected_checksum, actual_checksum, error))
|
||||
return FALSE;
|
||||
|
||||
/* Add the checksum + objtype prefix here */
|
||||
{ const char *error_prefix = glnx_strjoina (expected_checksum, ".", ostree_object_type_to_string (objtype));
|
||||
GLNX_AUTO_PREFIX_ERROR(error_prefix, error);
|
||||
if (!_ostree_validate_structureof_metadata (objtype, metadata, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_validate_structureof_commit:
|
||||
* @commit: A commit object, %OSTREE_OBJECT_TYPE_COMMIT
|
||||
|
||||
@@ -714,7 +714,7 @@ initiate_next_curl_request (FetcherRequest *req,
|
||||
curl_easy_setopt (req->easy, CURLOPT_URL, uri);
|
||||
}
|
||||
|
||||
curl_easy_setopt (req->easy, CURLOPT_USERAGENT, "ostree ");
|
||||
curl_easy_setopt (req->easy, CURLOPT_USERAGENT, OSTREE_FETCHER_USERAGENT_STRING);
|
||||
if (self->extra_headers)
|
||||
curl_easy_setopt (req->easy, CURLOPT_HTTPHEADER, self->extra_headers);
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@ ostree_fetcher_session_thread (gpointer data)
|
||||
g_main_context_push_thread_default (mainctx);
|
||||
|
||||
/* We retain ownership of the SoupSession reference. */
|
||||
closure->session = soup_session_async_new_with_options (SOUP_SESSION_USER_AGENT, "ostree ",
|
||||
closure->session = soup_session_async_new_with_options (SOUP_SESSION_USER_AGENT, OSTREE_FETCHER_USERAGENT_STRING,
|
||||
SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
|
||||
SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
|
||||
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* We used to only send "ostree/" but now include the version
|
||||
* https://github.com/ostreedev/ostree/issues/1405
|
||||
* This came up in allowing Fedora infrastructure to work around a libcurl bug with HTTP2.
|
||||
*/
|
||||
#define OSTREE_FETCHER_USERAGENT_STRING (PACKAGE_NAME "/" PACKAGE_VERSION)
|
||||
|
||||
static inline gboolean
|
||||
_ostree_fetcher_tmpf_from_flags (OstreeFetcherRequestFlags flags,
|
||||
int dfd,
|
||||
|
||||
@@ -535,6 +535,10 @@ checkout_one_file_at (OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
/* Validate this up front to prevent path traversal attacks */
|
||||
if (!ot_util_filename_validate (destination_name, error))
|
||||
return FALSE;
|
||||
|
||||
gboolean need_copy = TRUE;
|
||||
gboolean is_bare_user_symlink = FALSE;
|
||||
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
|
||||
@@ -897,6 +901,15 @@ checkout_tree_at_recurse (OstreeRepo *self,
|
||||
while (g_variant_iter_loop (&viter, "(&s@ay@ay)", &dname,
|
||||
&subdirtree_csum_v, &subdirmeta_csum_v))
|
||||
{
|
||||
/* Validate this up front to prevent path traversal attacks. Note that
|
||||
* we don't validate at the top of this function like we do for
|
||||
* checkout_one_file_at() becuase I believe in some cases this function
|
||||
* can be called *initially* with user-specified paths for the root
|
||||
* directory.
|
||||
*/
|
||||
if (!ot_util_filename_validate (dname, error))
|
||||
return FALSE;
|
||||
|
||||
const size_t origlen = selabel_path_buf ? selabel_path_buf->len : 0;
|
||||
if (selabel_path_buf)
|
||||
{
|
||||
|
||||
@@ -2027,6 +2027,13 @@ ostree_repo_write_metadata (OstreeRepo *self,
|
||||
if (!metadata_size_valid (objtype, g_variant_get_size (normalized), error))
|
||||
return FALSE;
|
||||
|
||||
/* For untrusted objects, verify their structure here */
|
||||
if (expected_checksum)
|
||||
{
|
||||
if (!_ostree_validate_structureof_metadata (objtype, object, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autoptr(GBytes) vdata = g_variant_get_data_as_bytes (normalized);
|
||||
if (!write_metadata_object (self, objtype, expected_checksum,
|
||||
vdata, out_csum, cancellable, error))
|
||||
@@ -4101,6 +4108,7 @@ _ostree_repo_import_object (OstreeRepo *self,
|
||||
&variant, error))
|
||||
return FALSE;
|
||||
|
||||
/* Note this one also now verifies structure in the !trusted case */
|
||||
g_autofree guchar *real_csum = NULL;
|
||||
if (!ostree_repo_write_metadata (self, objtype,
|
||||
checksum, variant,
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include "libglnx.h"
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
#include "ostree-repo-pull-private.h"
|
||||
|
||||
#ifdef HAVE_LIBCURL_OR_LIBSOUP
|
||||
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-repo-pull-private.h"
|
||||
#include "ostree-repo-static-delta-private.h"
|
||||
#include "ostree-metalink.h"
|
||||
#include "ostree-fetcher-util.h"
|
||||
@@ -736,6 +736,12 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||
|
||||
g_variant_get_child (files_variant, i, "(&s@ay)", &filename, &csum);
|
||||
|
||||
/* Note this is now obsoleted by the _ostree_validate_structureof_metadata()
|
||||
* but I'm keeping this since:
|
||||
* 1) It's cheap
|
||||
* 2) We want to continue to do validation for objects written to disk
|
||||
* before libostree's validation was strengthened.
|
||||
*/
|
||||
if (!ot_util_filename_validate (filename, error))
|
||||
return FALSE;
|
||||
|
||||
@@ -810,6 +816,7 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||
g_variant_get_child (dirs_variant, i, "(&s@ay@ay)",
|
||||
&dirname, &tree_csum, &meta_csum);
|
||||
|
||||
/* See comment above for files */
|
||||
if (!ot_util_filename_validate (dirname, error))
|
||||
return FALSE;
|
||||
|
||||
@@ -1222,24 +1229,20 @@ meta_fetch_on_complete (GObject *object,
|
||||
FALSE, &metadata, error))
|
||||
goto out;
|
||||
|
||||
/* For commit objects, compute the hash and check the GPG signature before
|
||||
* writing to the repo, and also write the .commitpartial to say that
|
||||
* we're still processing this commit.
|
||||
/* Compute checksum and verify structure now. Note this is a recent change
|
||||
* (Jan 2018) - we used to verify the checksum only when writing down
|
||||
* below. But we want to do "structure" verification early on as well
|
||||
* before the object is written even to the staging directory.
|
||||
*/
|
||||
if (!_ostree_verify_metadata_object (objtype, checksum, metadata, error))
|
||||
goto out;
|
||||
|
||||
/* For commit objects, check the GPG signature before writing to the repo,
|
||||
* and also write the .commitpartial to say that we're still processing
|
||||
* this commit.
|
||||
*/
|
||||
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
||||
{
|
||||
/* Verify checksum */
|
||||
OtChecksum hasher = { 0, };
|
||||
ot_checksum_init (&hasher);
|
||||
{ g_autoptr(GBytes) bytes = g_variant_get_data_as_bytes (metadata);
|
||||
ot_checksum_update_bytes (&hasher, bytes);
|
||||
}
|
||||
char hexdigest[OSTREE_SHA256_STRING_LEN+1];
|
||||
ot_checksum_get_hexdigest (&hasher, hexdigest, sizeof (hexdigest));
|
||||
|
||||
if (!_ostree_compare_object_checksum (objtype, checksum, hexdigest, error))
|
||||
goto out;
|
||||
|
||||
/* Do GPG verification. `detached_data` may be NULL if no detached
|
||||
* metadata was found during pull; that's handled by
|
||||
* gpg_verify_unwritten_commit(). If we ever change the pull code to
|
||||
@@ -1256,7 +1259,13 @@ meta_fetch_on_complete (GObject *object,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ostree_repo_write_metadata_async (pull_data->repo, objtype, checksum, metadata,
|
||||
/* Note that we now (Jan 2018) pass NULL for checksum, which means "don't
|
||||
* verify checksum", since we just did it above. Related to this...now
|
||||
* that we're doing all the verification here, one thing we could do later
|
||||
* just `glnx_link_tmpfile_at()` into the repository, like the content
|
||||
* fetch path does for trusted commits.
|
||||
*/
|
||||
ostree_repo_write_metadata_async (pull_data->repo, objtype, NULL, metadata,
|
||||
pull_data->cancellable,
|
||||
on_metadata_written, fetch_data);
|
||||
pull_data->n_outstanding_metadata_write_requests++;
|
||||
|
||||
@@ -497,8 +497,13 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
|
||||
goto out;
|
||||
}
|
||||
|
||||
metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype),
|
||||
state->payload_data + offset, length, TRUE, NULL, NULL);
|
||||
/* Unfortunately we need a copy because GVariant wants pointer-alignment
|
||||
* and we didn't guarantee that in static deltas. We can do so in the
|
||||
* future.
|
||||
*/
|
||||
g_autoptr(GBytes) metadata_copy = g_bytes_new (state->payload_data + offset, length);
|
||||
metadata = g_variant_new_from_bytes (ostree_metadata_variant_type (state->output_objtype),
|
||||
metadata_copy, FALSE);
|
||||
|
||||
{
|
||||
g_autofree guchar *actual_csum = NULL;
|
||||
|
||||
@@ -3941,6 +3941,7 @@ ostree_repo_delete_object (OstreeRepo *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Thin wrapper for _ostree_verify_metadata_object() */
|
||||
static gboolean
|
||||
fsck_metadata_object (OstreeRepo *self,
|
||||
OstreeObjectType objtype,
|
||||
@@ -3956,39 +3957,7 @@ fsck_metadata_object (OstreeRepo *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_auto(OtChecksum) hasher = { 0, };
|
||||
ot_checksum_init (&hasher);
|
||||
ot_checksum_update (&hasher, g_variant_get_data (metadata), g_variant_get_size (metadata));
|
||||
|
||||
char actual_checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
ot_checksum_get_hexdigest (&hasher, actual_checksum, sizeof (actual_checksum));
|
||||
if (!_ostree_compare_object_checksum (objtype, sha256, actual_checksum, error))
|
||||
return FALSE;
|
||||
|
||||
switch (objtype)
|
||||
{
|
||||
case OSTREE_OBJECT_TYPE_COMMIT:
|
||||
if (!ostree_validate_structureof_commit (metadata, error))
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_DIR_TREE:
|
||||
if (!ostree_validate_structureof_dirtree (metadata, error))
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_DIR_META:
|
||||
if (!ostree_validate_structureof_dirmeta (metadata, error))
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT:
|
||||
case OSTREE_OBJECT_TYPE_COMMIT_META:
|
||||
/* TODO */
|
||||
break;
|
||||
case OSTREE_OBJECT_TYPE_FILE:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return _ostree_verify_metadata_object (objtype, sha256, metadata, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -1700,21 +1700,29 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL);
|
||||
ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath);
|
||||
|
||||
val = ostree_bootconfig_parser_get (bootconfig, "options");
|
||||
g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_from_string (val);
|
||||
|
||||
if (kernel_layout->initramfs_namever)
|
||||
{
|
||||
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL);
|
||||
ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath);
|
||||
}
|
||||
|
||||
val = ostree_bootconfig_parser_get (bootconfig, "options");
|
||||
else
|
||||
{
|
||||
g_autofree char *prepare_root_arg = NULL;
|
||||
prepare_root_arg = g_strdup_printf ("init=/ostree/boot.%d/%s/%s/%d/usr/lib/ostree/ostree-prepare-root",
|
||||
new_bootversion, osname, bootcsum,
|
||||
ostree_deployment_get_bootserial (deployment));
|
||||
_ostree_kernel_args_replace_take (kargs, g_steal_pointer (&prepare_root_arg));
|
||||
}
|
||||
|
||||
/* Note this is parsed in ostree-impl-system-generator.c */
|
||||
g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d",
|
||||
new_bootversion, osname, bootcsum,
|
||||
ostree_deployment_get_bootserial (deployment));
|
||||
g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_from_string (val);
|
||||
_ostree_kernel_args_replace_take (kargs, ostree_kernel_arg);
|
||||
ostree_kernel_arg = NULL;
|
||||
_ostree_kernel_args_replace_take (kargs, g_steal_pointer (&ostree_kernel_arg));
|
||||
|
||||
g_autofree char *options_key = _ostree_kernel_args_to_string (kargs);
|
||||
ostree_bootconfig_parser_set (bootconfig, "options", options_key);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_YEAR_VERSION (2017)
|
||||
#define OSTREE_YEAR_VERSION (2018)
|
||||
|
||||
/**
|
||||
* OSTREE_RELEASE_VERSION:
|
||||
@@ -43,7 +43,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_RELEASE_VERSION (15)
|
||||
#define OSTREE_RELEASE_VERSION (1)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION
|
||||
@@ -52,7 +52,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION (2017.15)
|
||||
#define OSTREE_VERSION (2018.1)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION_S:
|
||||
@@ -62,7 +62,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION_S "2017.15"
|
||||
#define OSTREE_VERSION_S "2018.1"
|
||||
|
||||
#define OSTREE_ENCODE_VERSION(year,release) \
|
||||
((year) << 16 | (release))
|
||||
|
||||
@@ -40,6 +40,7 @@ static char **opt_kernel_argv_append;
|
||||
static gboolean opt_kernel_proc_cmdline;
|
||||
static char *opt_osname;
|
||||
static char *opt_origin_path;
|
||||
static gboolean opt_kernel_arg_none;
|
||||
|
||||
/* ATTENTION:
|
||||
* Please remember to update the bash-completion script (bash/ostree) and
|
||||
@@ -56,6 +57,7 @@ static GOptionEntry options[] = {
|
||||
{ "karg-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_proc_cmdline, "Import current /proc/cmdline", NULL },
|
||||
{ "karg", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv, "Set kernel argument, like root=/dev/sda1; this overrides any earlier argument with the same name", "NAME=VALUE" },
|
||||
{ "karg-append", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv_append, "Append kernel argument; useful with e.g. console= that can be used multiple times", "NAME=VALUE" },
|
||||
{ "karg-none", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_arg_none, "Do not import kernel arguments", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -79,6 +81,12 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocat
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (opt_kernel_proc_cmdline && opt_kernel_arg_none)
|
||||
{
|
||||
ot_util_usage_error (context, "Can't specify both --karg-proc-cmdline and --karg-none", error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *refspec = argv[1];
|
||||
|
||||
OstreeRepo *repo = ostree_sysroot_repo (sysroot);
|
||||
@@ -130,7 +138,7 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocat
|
||||
if (!_ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (merge_deployment)
|
||||
else if (merge_deployment && !opt_kernel_arg_none)
|
||||
{
|
||||
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
|
||||
g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);
|
||||
|
||||
@@ -45,6 +45,7 @@ static char *opt_skiplist_file;
|
||||
static char **opt_metadata_strings;
|
||||
static char **opt_metadata_variants;
|
||||
static char **opt_detached_metadata_strings;
|
||||
static char **opt_metadata_keep;
|
||||
static gboolean opt_link_checkout_speedup;
|
||||
static gboolean opt_skip_if_unchanged;
|
||||
static gboolean opt_tar_autocreate_parents;
|
||||
@@ -96,6 +97,7 @@ static GOptionEntry options[] = {
|
||||
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" },
|
||||
{ "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" },
|
||||
{ "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" },
|
||||
{ "keep-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_keep, "Keep metadata KEY and its associated VALUE from parent", "KEY" },
|
||||
{ "add-detached-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_detached_metadata_strings, "Add a key/value pair to detached metadata", "KEY=VALUE" },
|
||||
{ "owner-uid", 0, 0, G_OPTION_ARG_INT, &opt_owner_uid, "Set file ownership user id", "UID" },
|
||||
{ "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" },
|
||||
@@ -466,7 +468,47 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_metadata_strings || opt_metadata_variants)
|
||||
if (!(opt_branch || opt_orphan))
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"A branch must be specified with --branch, or use --orphan");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_parent)
|
||||
{
|
||||
if (g_str_equal (opt_parent, "none"))
|
||||
parent = NULL;
|
||||
else
|
||||
{
|
||||
if (!ostree_validate_checksum_string (opt_parent, error))
|
||||
goto out;
|
||||
parent = g_strdup (opt_parent);
|
||||
}
|
||||
}
|
||||
else if (!opt_orphan)
|
||||
{
|
||||
if (!ostree_repo_resolve_rev (repo, opt_branch, TRUE, &parent, error))
|
||||
{
|
||||
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY))
|
||||
{
|
||||
/* A folder exists with the specified ref name,
|
||||
* which is handled by _ostree_repo_write_ref */
|
||||
g_clear_error (error);
|
||||
}
|
||||
else goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parent && opt_metadata_keep)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Either --branch or --parent must be specified when using "
|
||||
"--keep-metadata");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_metadata_strings || opt_metadata_variants || opt_metadata_keep)
|
||||
{
|
||||
g_autoptr(GVariantBuilder) builder =
|
||||
g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
||||
@@ -479,6 +521,31 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
|
||||
!parse_keyvalue_strings (builder, opt_metadata_variants, TRUE, error))
|
||||
goto out;
|
||||
|
||||
if (opt_metadata_keep)
|
||||
{
|
||||
g_assert (parent);
|
||||
|
||||
g_autoptr(GVariant) parent_commit = NULL;
|
||||
if (!ostree_repo_load_commit (repo, parent, &parent_commit, NULL, error))
|
||||
goto out;
|
||||
|
||||
g_auto(GVariantDict) dict;
|
||||
g_variant_dict_init (&dict, g_variant_get_child_value (parent_commit, 0));
|
||||
for (char **keyp = opt_metadata_keep; keyp && *keyp; keyp++)
|
||||
{
|
||||
const char *key = *keyp;
|
||||
g_autoptr(GVariant) val = g_variant_dict_lookup_value (&dict, key, NULL);
|
||||
if (!val)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Missing metadata key '%s' from commit '%s'", key, parent);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_variant_builder_add (builder, "{sv}", key, val);
|
||||
}
|
||||
}
|
||||
|
||||
metadata = g_variant_ref_sink (g_variant_builder_end (builder));
|
||||
}
|
||||
|
||||
@@ -493,13 +560,6 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
|
||||
detached_metadata = g_variant_ref_sink (g_variant_builder_end (builder));
|
||||
}
|
||||
|
||||
if (!(opt_branch || opt_orphan))
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"A branch must be specified with --branch, or use --orphan");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_no_xattrs)
|
||||
flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS;
|
||||
if (opt_consume)
|
||||
@@ -543,31 +603,6 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_parent)
|
||||
{
|
||||
if (g_str_equal (opt_parent, "none"))
|
||||
parent = NULL;
|
||||
else
|
||||
{
|
||||
if (!ostree_validate_checksum_string (opt_parent, error))
|
||||
goto out;
|
||||
parent = g_strdup (opt_parent);
|
||||
}
|
||||
}
|
||||
else if (!opt_orphan)
|
||||
{
|
||||
if (!ostree_repo_resolve_rev (repo, opt_branch, TRUE, &parent, error))
|
||||
{
|
||||
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY))
|
||||
{
|
||||
/* A folder exists with the specified ref name,
|
||||
* which is handled by _ostree_repo_write_ref */
|
||||
g_clear_error (error);
|
||||
}
|
||||
else goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_editor)
|
||||
{
|
||||
if (!commit_editor (repo, opt_branch, &opt_subject, &commit_body, cancellable, error))
|
||||
|
||||
@@ -30,12 +30,14 @@
|
||||
#include "ostree-remote-private.h"
|
||||
|
||||
static gchar *opt_cache_dir = NULL;
|
||||
static gchar *opt_finders = NULL;
|
||||
static gboolean opt_disable_fsync = FALSE;
|
||||
static gboolean opt_pull = FALSE;
|
||||
|
||||
static GOptionEntry options[] =
|
||||
{
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ "finders", 0, 0, G_OPTION_ARG_STRING, &opt_finders, "Use the specified comma separated list of finders (e.g. config,lan,mount)", "FINDERS" },
|
||||
{ "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
|
||||
{ "pull", 0, 0, G_OPTION_ARG_NONE, &opt_pull, "Pull the updates after finding them", NULL },
|
||||
{ NULL }
|
||||
@@ -116,6 +118,52 @@ collection_ref_free0 (OstreeCollectionRef *ref)
|
||||
ostree_collection_ref_free (ref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
validate_finders_list (char **finders,
|
||||
GOptionContext *context,
|
||||
GError **error)
|
||||
{
|
||||
typedef struct {
|
||||
gchar *finder_name;
|
||||
gboolean already_used;
|
||||
} Finder;
|
||||
Finder valid_finders[] = {
|
||||
{.finder_name = "config", .already_used = FALSE},
|
||||
{.finder_name = "lan", .already_used = FALSE},
|
||||
{.finder_name = "mount", .already_used = FALSE}
|
||||
};
|
||||
|
||||
if (finders == NULL || *finders == NULL)
|
||||
{
|
||||
ot_util_usage_error (context, "List of finders in --finders option must not be empty", error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (char **iter = finders; iter && *iter; iter++)
|
||||
{
|
||||
gboolean is_valid_finder = FALSE;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (valid_finders[i].already_used == TRUE)
|
||||
continue;
|
||||
if (g_strcmp0 (*iter, valid_finders[i].finder_name) == 0)
|
||||
{
|
||||
is_valid_finder = TRUE;
|
||||
valid_finders[i].already_used = TRUE;
|
||||
}
|
||||
}
|
||||
if (!is_valid_finder)
|
||||
{
|
||||
g_autofree gchar *error_msg = NULL;
|
||||
error_msg = g_strdup_printf ("Unknown or duplicate finder type given in --finders option: ‘%s’", *iter);
|
||||
ot_util_usage_error (context, error_msg, error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* TODO: Add a man page. */
|
||||
gboolean
|
||||
ostree_builtin_find_remotes (int argc,
|
||||
@@ -127,12 +175,17 @@ ostree_builtin_find_remotes (int argc,
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(OstreeRepo) repo = NULL;
|
||||
g_autoptr(GPtrArray) refs = NULL; /* (element-type OstreeCollectionRef) */
|
||||
g_autoptr(GPtrArray) finders = NULL; /* (element-type OstreeRepoFinder) */
|
||||
g_autoptr(OstreeRepoFinder) finder_config = NULL;
|
||||
g_autoptr(OstreeRepoFinder) finder_mount = NULL;
|
||||
g_autoptr(OstreeRepoFinder) finder_avahi = NULL;
|
||||
g_autoptr(OstreeAsyncProgress) progress = NULL;
|
||||
gsize i;
|
||||
g_autoptr(GAsyncResult) find_result = NULL, pull_result = NULL;
|
||||
g_auto(OstreeRepoFinderResultv) results = NULL;
|
||||
g_auto(GLnxConsoleRef) console = { 0, };
|
||||
g_autoptr(GHashTable) refs_found = NULL; /* set (element-type OstreeCollectionRef) */
|
||||
g_auto(GStrv) finders_strings = NULL;
|
||||
|
||||
context = g_option_context_new ("COLLECTION-ID REF [COLLECTION-ID REF...]");
|
||||
|
||||
@@ -176,18 +229,65 @@ ostree_builtin_find_remotes (int argc,
|
||||
|
||||
g_ptr_array_add (refs, NULL);
|
||||
|
||||
/* Build the array of OstreeRepoFinder instances */
|
||||
if (opt_finders != NULL)
|
||||
{
|
||||
g_auto(GStrv) finders_strings = NULL;
|
||||
|
||||
finders_strings = g_strsplit (opt_finders, ",", 0);
|
||||
if (!validate_finders_list (finders_strings, context, error))
|
||||
return FALSE;
|
||||
|
||||
finders = g_ptr_array_new ();
|
||||
for (char **iter =finders_strings; iter && *iter; iter++)
|
||||
{
|
||||
if (g_strcmp0 (*iter, "config") == 0)
|
||||
{
|
||||
finder_config = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ());
|
||||
g_ptr_array_add (finders, finder_config);
|
||||
}
|
||||
else if (g_strcmp0 (*iter, "mount") == 0)
|
||||
{
|
||||
finder_mount = OSTREE_REPO_FINDER (ostree_repo_finder_mount_new (NULL));
|
||||
g_ptr_array_add (finders, finder_mount);
|
||||
}
|
||||
else if (g_strcmp0 (*iter, "lan") == 0)
|
||||
{
|
||||
#ifdef HAVE_AVAHI
|
||||
GMainContext *main_context = g_main_context_get_thread_default ();
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
finder_avahi = OSTREE_REPO_FINDER (ostree_repo_finder_avahi_new (main_context));
|
||||
ostree_repo_finder_avahi_start (OSTREE_REPO_FINDER_AVAHI (finder_avahi), &local_error);
|
||||
|
||||
if (local_error != NULL)
|
||||
{
|
||||
g_warning ("Avahi finder failed; removing it: %s", local_error->message);
|
||||
g_clear_object (&finder_avahi);
|
||||
}
|
||||
else
|
||||
g_ptr_array_add (finders, finder_avahi);
|
||||
#else
|
||||
ot_util_usage_error (context, "LAN repo finder requested but ostree was compiled without Avahi support", error);
|
||||
return FALSE;
|
||||
#endif /* HAVE_AVAHI */
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
g_ptr_array_add (finders, NULL);
|
||||
}
|
||||
|
||||
/* Run the operation. */
|
||||
glnx_console_lock (&console);
|
||||
|
||||
if (console.is_tty)
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console);
|
||||
|
||||
/* FIXME: Eventually some command line options for customising the finders
|
||||
* list would be good. */
|
||||
ostree_repo_find_remotes_async (repo,
|
||||
(const OstreeCollectionRef * const *) refs->pdata,
|
||||
NULL /* no options */,
|
||||
NULL /* default finders */,
|
||||
finders != NULL ? (OstreeRepoFinder **) finders->pdata : NULL,
|
||||
progress, cancellable,
|
||||
get_result_cb, &find_result);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ static OstreeCommand remote_subcommands[] = {
|
||||
{ "gpg-import", OSTREE_BUILTIN_FLAG_NONE,
|
||||
ot_remote_builtin_gpg_import,
|
||||
"Import GPG keys" },
|
||||
#ifdef HAVE_LIBSOUP
|
||||
#ifdef HAVE_LIBCURL_OR_LIBSOUP
|
||||
{ "add-cookie", OSTREE_BUILTIN_FLAG_NONE,
|
||||
ot_remote_builtin_add_cookie,
|
||||
"Add a cookie to remote" },
|
||||
|
||||
@@ -31,7 +31,7 @@ BUILTINPROTO(add);
|
||||
BUILTINPROTO(delete);
|
||||
BUILTINPROTO(gpg_import);
|
||||
BUILTINPROTO(list);
|
||||
#ifdef HAVE_LIBSOUP
|
||||
#ifdef HAVE_LIBCURL_OR_LIBSOUP
|
||||
BUILTINPROTO(add_cookie);
|
||||
BUILTINPROTO(list_cookies);
|
||||
BUILTINPROTO(delete_cookie);
|
||||
|
||||
@@ -19,5 +19,7 @@ bin_PROGRAMS += rofiles-fuse
|
||||
|
||||
rofiles_fuse_SOURCES = src/rofiles-fuse/main.c
|
||||
|
||||
rofiles_fuse_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(BUILDOPT_FUSE_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx $(NULL)
|
||||
rofiles_fuse_LDADD = libglnx.la $(BUILDOPT_FUSE_LIBS) $(OT_INTERNAL_GIO_UNIX_LIBS)
|
||||
rofiles_fuse_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(BUILDOPT_FUSE_CFLAGS) \
|
||||
$(OT_INTERNAL_GIO_UNIX_CFLAGS) -I $(srcdir)/src/libostree -I $(builddir)/src/libostree \
|
||||
-I$(srcdir)/libglnx
|
||||
rofiles_fuse_LDADD = libglnx.la $(BUILDOPT_FUSE_LIBS) $(OT_INTERNAL_GIO_UNIX_LIBS) libostree-1.la
|
||||
+115
-35
@@ -35,9 +35,14 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ostree.h"
|
||||
|
||||
// Global to store our read-write path
|
||||
static int basefd = -1;
|
||||
/* Whether or not to automatically "copyup" (in overlayfs terms).
|
||||
* What we're really doing is breaking hardlinks.
|
||||
*/
|
||||
static gboolean opt_copyup;
|
||||
|
||||
static inline const char *
|
||||
ENSURE_RELPATH (const char *path)
|
||||
@@ -200,52 +205,103 @@ callback_link (const char *from, const char *to)
|
||||
/* Check whether @stbuf refers to a hardlinked regfile or symlink, and if so
|
||||
* return -EROFS. Otherwise return 0.
|
||||
*/
|
||||
static int
|
||||
can_write_stbuf (struct stat *stbuf)
|
||||
static gboolean
|
||||
can_write_stbuf (const struct stat *stbuf)
|
||||
{
|
||||
/* If it's not a regular file or symlink, ostree won't hardlink it, so allow
|
||||
* writes - it might be a FIFO or device that somehow
|
||||
* ended up underneath our mount.
|
||||
*/
|
||||
if (!(S_ISREG (stbuf->st_mode) || S_ISLNK (stbuf->st_mode)))
|
||||
return 0;
|
||||
return TRUE;
|
||||
/* If the object isn't hardlinked, it's OK to write */
|
||||
if (stbuf->st_nlink <= 1)
|
||||
return 0;
|
||||
return TRUE;
|
||||
/* Otherwise, it's a hardlinked file or symlink; it must be
|
||||
* immutable.
|
||||
*/
|
||||
return -EROFS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check whether @path refers to a hardlinked regfile or symlink, and if so
|
||||
* return -EROFS. Otherwise return 0.
|
||||
*/
|
||||
static int
|
||||
can_write (const char *path)
|
||||
gioerror_to_errno (GIOErrorEnum e)
|
||||
{
|
||||
struct stat stbuf;
|
||||
if (fstatat (basefd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
|
||||
/* It's obviously crappy to have to do this but
|
||||
* we also don't want to try to have "raw errno" versions
|
||||
* of everything down in ostree_break_hardlink() so...
|
||||
* let's just reverse map a few ones I think are going to be common.
|
||||
*/
|
||||
switch (e)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
case G_IO_ERROR_NOT_FOUND:
|
||||
return ENOENT;
|
||||
case G_IO_ERROR_IS_DIRECTORY:
|
||||
return EISDIR;
|
||||
case G_IO_ERROR_PERMISSION_DENIED:
|
||||
return EPERM;
|
||||
case G_IO_ERROR_NO_SPACE:
|
||||
return ENOSPC;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
return can_write_stbuf (&stbuf);
|
||||
}
|
||||
|
||||
#define VERIFY_WRITE(path) do { \
|
||||
int r = can_write (path); \
|
||||
if (r != 0) \
|
||||
return r; \
|
||||
static int
|
||||
verify_write_or_copyup (const char *path, const struct stat *stbuf,
|
||||
gboolean *out_did_copyup)
|
||||
{
|
||||
struct stat stbuf_local;
|
||||
|
||||
if (out_did_copyup)
|
||||
*out_did_copyup = FALSE;
|
||||
|
||||
/* If a stbuf wasn't provided, gather it now */
|
||||
if (!stbuf)
|
||||
{
|
||||
if (fstatat (basefd, path, &stbuf_local, AT_SYMLINK_NOFOLLOW) == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
stbuf = &stbuf_local;
|
||||
}
|
||||
|
||||
/* Verify writability, if that fails, perform copy-up if enabled */
|
||||
if (!can_write_stbuf (stbuf))
|
||||
{
|
||||
if (opt_copyup)
|
||||
{
|
||||
g_autoptr(GError) tmp_error = NULL;
|
||||
if (!ostree_break_hardlink (basefd, path, FALSE, NULL, &tmp_error))
|
||||
return -gioerror_to_errno ((GIOErrorEnum)tmp_error->code);
|
||||
if (out_did_copyup)
|
||||
*out_did_copyup = TRUE;
|
||||
}
|
||||
else
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Given a path (which is absolute), convert it
|
||||
* to a relative path (even for the caller) and
|
||||
* perform either write verification or copy-up.
|
||||
*/
|
||||
#define PATH_WRITE_ENTRYPOINT(path) do { \
|
||||
path = ENSURE_RELPATH (path); \
|
||||
int r = verify_write_or_copyup (path, NULL, NULL); \
|
||||
if (r != 0) \
|
||||
return r; \
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
callback_chmod (const char *path, mode_t mode)
|
||||
{
|
||||
path = ENSURE_RELPATH (path);
|
||||
VERIFY_WRITE(path);
|
||||
PATH_WRITE_ENTRYPOINT (path);
|
||||
|
||||
/* Note we can't use AT_SYMLINK_NOFOLLOW yet;
|
||||
* https://marc.info/?l=linux-kernel&m=148830147803162&w=2
|
||||
* https://marc.info/?l=linux-fsdevel&m=149193779929561&w=2
|
||||
@@ -258,8 +314,8 @@ callback_chmod (const char *path, mode_t mode)
|
||||
static int
|
||||
callback_chown (const char *path, uid_t uid, gid_t gid)
|
||||
{
|
||||
path = ENSURE_RELPATH (path);
|
||||
VERIFY_WRITE(path);
|
||||
PATH_WRITE_ENTRYPOINT (path);
|
||||
|
||||
if (fchownat (basefd, path, uid, gid, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
@@ -268,12 +324,9 @@ callback_chown (const char *path, uid_t uid, gid_t gid)
|
||||
static int
|
||||
callback_truncate (const char *path, off_t size)
|
||||
{
|
||||
glnx_autofd int fd = -1;
|
||||
PATH_WRITE_ENTRYPOINT (path);
|
||||
|
||||
path = ENSURE_RELPATH (path);
|
||||
VERIFY_WRITE(path);
|
||||
|
||||
fd = openat (basefd, path, O_NOFOLLOW|O_WRONLY);
|
||||
glnx_autofd int fd = openat (basefd, path, O_NOFOLLOW|O_WRONLY);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
@@ -286,6 +339,9 @@ callback_truncate (const char *path, off_t size)
|
||||
static int
|
||||
callback_utimens (const char *path, const struct timespec tv[2])
|
||||
{
|
||||
/* This one isn't write-verified, we support changing times
|
||||
* even for hardlinked files.
|
||||
*/
|
||||
path = ENSURE_RELPATH (path);
|
||||
|
||||
if (utimensat (basefd, path, tv, AT_SYMLINK_NOFOLLOW) == -1)
|
||||
@@ -324,20 +380,39 @@ do_open (const char *path, mode_t mode, struct fuse_file_info *finfo)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int r = can_write_stbuf (&stbuf);
|
||||
gboolean did_copyup;
|
||||
int r = verify_write_or_copyup (path, &stbuf, &did_copyup);
|
||||
if (r != 0)
|
||||
{
|
||||
(void) close (fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Handle O_TRUNC here only after verifying hardlink state */
|
||||
if (finfo->flags & O_TRUNC)
|
||||
/* In the copyup case, we need to re-open */
|
||||
if (did_copyup)
|
||||
{
|
||||
if (ftruncate (fd, 0) == -1)
|
||||
(void) close (fd);
|
||||
/* Note that unlike the initial open, we will pass through
|
||||
* O_TRUNC. More ideally in this copyup case we'd avoid copying
|
||||
* the whole file in the first place, but eh. It's not like we're
|
||||
* high performance anyways.
|
||||
*/
|
||||
fd = openat (basefd, path, finfo->flags & ~(O_EXCL|O_CREAT), mode);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In the non-copyup case we handle O_TRUNC here, after we've verified
|
||||
* the hardlink state above with verify_write_or_copyup().
|
||||
*/
|
||||
if (finfo->flags & O_TRUNC)
|
||||
{
|
||||
(void) close (fd);
|
||||
return -errno;
|
||||
if (ftruncate (fd, 0) == -1)
|
||||
{
|
||||
(void) close (fd);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,6 +596,7 @@ struct fuse_operations callback_oper = {
|
||||
enum {
|
||||
KEY_HELP,
|
||||
KEY_VERSION,
|
||||
KEY_COPYUP,
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -565,6 +641,9 @@ rofs_parse_opt (void *data, const char *arg, int key,
|
||||
case KEY_HELP:
|
||||
usage (outargs->argv[0]);
|
||||
exit (EXIT_SUCCESS);
|
||||
case KEY_COPYUP:
|
||||
opt_copyup = TRUE;
|
||||
return 0;
|
||||
default:
|
||||
fprintf (stderr, "see `%s -h' for usage\n", outargs->argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
@@ -577,6 +656,7 @@ static struct fuse_opt rofs_opts[] = {
|
||||
FUSE_OPT_KEY ("--help", KEY_HELP),
|
||||
FUSE_OPT_KEY ("-V", KEY_VERSION),
|
||||
FUSE_OPT_KEY ("--version", KEY_VERSION),
|
||||
FUSE_OPT_KEY ("--copyup", KEY_COPYUP),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
|
||||
@@ -102,10 +102,16 @@ main(int argc, char *argv[])
|
||||
struct stat stbuf;
|
||||
int we_mounted_proc = 0;
|
||||
|
||||
if (argc < 2)
|
||||
root_arg = "/";
|
||||
if (getpid() == 1)
|
||||
{
|
||||
root_arg = "/";
|
||||
}
|
||||
else
|
||||
root_arg = argv[1];
|
||||
{
|
||||
if (argc < 2)
|
||||
err (EXIT_FAILURE, "usage: ostree-prepare-root SYSROOT");
|
||||
root_arg = argv[1];
|
||||
}
|
||||
|
||||
if (stat ("/proc/cmdline", &stbuf) < 0)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user