From bd9e931b332957f82ef69742048bf6cb3da3be12 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 17 Aug 2017 13:23:51 -0400 Subject: [PATCH 01/83] build-sys: Post-release version bump Closes: #1089 Approved by: jlebon --- configure.ac | 4 ++-- src/libostree/libostree-devel.sym | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5c13e742..72f96d3c 100644 --- a/configure.ac +++ b/configure.ac @@ -4,10 +4,10 @@ dnl update libostree-released.sym from libostree-devel.sym, and update the check dnl in test-symbols.sh, and also set is_release_build=yes below. Then make dnl another post-release commit to bump the version, and set is_release_build=no. m4_define([year_version], [2017]) -m4_define([release_version], [10]) +m4_define([release_version], [11]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) -is_release_build=yes +is_release_build=no AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIR([buildutil]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index 01f182f6..76aa280f 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -18,6 +18,8 @@ ***/ /* Add new symbols here. Release commits should copy this section into -released.sym. */ +LIBOSTREE_2017.11 { +} LIBOSTREE_2017.10; /* 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 From e6a4203c52d68ca8fe7c5e60e127141e1c4ea7ee Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 17 Aug 2017 14:00:08 -0400 Subject: [PATCH 02/83] boot: Add a tmpfiles.d snippet to clean up /var/tmp/ostree-ovl.XXX This is simplest for now. Compare with similar logic from `/usr/lib/tmpfiles.d/tmp.conf`: ``` R! /tmp/systemd-private-* ``` Closes: https://github.com/ostreedev/ostree/issues/393 Closes: #1090 Approved by: jlebon --- Makefile-boot.am | 2 ++ src/boot/ostree-tmpfiles.conf | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/boot/ostree-tmpfiles.conf diff --git a/Makefile-boot.am b/Makefile-boot.am index 8d7ade07..213ff043 100644 --- a/Makefile-boot.am +++ b/Makefile-boot.am @@ -38,6 +38,8 @@ endif if BUILDOPT_SYSTEMD systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ src/boot/ostree-remount.service +systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d +systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf # Allow the distcheck install under $prefix test to pass AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemunitdir='$${libdir}/systemd/system' diff --git a/src/boot/ostree-tmpfiles.conf b/src/boot/ostree-tmpfiles.conf new file mode 100644 index 00000000..49e2dcb3 --- /dev/null +++ b/src/boot/ostree-tmpfiles.conf @@ -0,0 +1,19 @@ +# Copyright (C) 2017 Colin Walters +# +# 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. + +# https://github.com/ostreedev/ostree/issues/393 +R! /var/tmp/ostree-unlock-ovl.* From 984d22303ddbf2c2553dc283ce29e0aaf2b13b6d Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 17 Aug 2017 16:49:26 -0400 Subject: [PATCH 03/83] bin: Squash some -Wuninit warnings with porting to new style I noticed this with a local build of an RPM: ``` /usr/include/glib-2.0/glib/glib-autocleanups.h:28:3: warning: 'help' may be used uninitialized in this function [-Wmaybe-uninitialized] g_free (*pp); ^~~~~~~~~~~~ src/ostree/ot-main.c:82:20: note: 'help' was declared here g_autofree char *help; ^~~~ ``` Closes: #1091 Approved by: jlebon --- src/ostree/ot-admin-builtin-instutil.c | 26 +++++++++----------------- src/ostree/ot-main.c | 10 +++------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c index 0694ba77..2baa27f7 100644 --- a/src/ostree/ot-admin-builtin-instutil.c +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -65,10 +65,7 @@ ostree_admin_instutil_option_context_new_with_commands (void) gboolean ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - OstreeAdminInstUtilCommand *subcommand; const char *subcommand_name = NULL; - g_autofree char *prgname = NULL; int in, out; for (in = 1, out = 1; in < argc; in++, out++) @@ -94,7 +91,7 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr argc = out; - subcommand = admin_instutil_subcommands; + OstreeAdminInstUtilCommand *subcommand = admin_instutil_subcommands; while (subcommand->name) { if (g_strcmp0 (subcommand_name, subcommand->name) == 0) @@ -104,10 +101,8 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr if (!subcommand->name) { - g_autoptr(GOptionContext) context = NULL; - g_autofree char *help; - - context = ostree_admin_instutil_option_context_new_with_commands (); + g_autoptr(GOptionContext) context = + ostree_admin_instutil_option_context_new_with_commands (); /* This will not return for some options (e.g. --version). */ if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, @@ -126,19 +121,16 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr } } - help = g_option_context_get_help (context, FALSE, NULL); + g_autofree char *help = g_option_context_get_help (context, FALSE, NULL); g_printerr ("%s", help); - - goto out; + return FALSE; } - prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); g_set_prgname (prgname); if (!subcommand->fn (argc, argv, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return FALSE; + + return TRUE; } diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 4d47985b..7b906bfa 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -78,15 +78,11 @@ int ostree_usage (OstreeCommand *commands, gboolean is_error) { - g_autoptr(GOptionContext) context = NULL; - g_autofree char *help; - - context = ostree_option_context_new_with_commands (commands); - + g_autoptr(GOptionContext) context = + ostree_option_context_new_with_commands (commands); g_option_context_add_main_entries (context, global_entries, NULL); - help = g_option_context_get_help (context, FALSE, NULL); - + g_autofree char *help = g_option_context_get_help (context, FALSE, NULL); if (is_error) g_printerr ("%s", help); else From 3ab0d5e6644885440bac6abd17b6d2637df5435f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 15 Aug 2017 11:22:21 -0400 Subject: [PATCH 04/83] lib/sysroot: Support /usr/lib/modules/$kver for kernel/initramfs This is the new Fedora kernel standard layout; it has the advantage of being in `/usr` like `/usr/lib/ostree-boot`, but it's not OSTree specific. Further, I think in practice forcing tree builders to compute the checksum is an annoying stumbling block; since we already switched to e.g. computing checksums always when doing pulls, the cost of doing another checksum for the kernel/initramfs is tiny. The "bootcsum" becomes more of an internal implementation detail. Now, there is a transition; my current thought for this is that rpm-ostree will change to default to injecting into both `/usr/lib/ostree-boot` and `/usr/lib/modules`, and stop doing `/boot`, then maybe next year say we drop the `/usr/lib/ostree-boot` by default. A twist here is that the default Fedora kernel RPM layout (and what's in rpm-ostree today) includes a kernel but *not* an initramfs in `/usr/lib/modules`. If we looked only there, we'd just find the kernel. So we need to look in both, and then special case this - pick the legacy layout if we have `/usr/lib/modules` but not an initramfs. While here, rework the code to have an `OstreeKernelLayout` struct which makes dealing with all of the variables nicer. Closes: #1079 Approved by: jlebon --- docs/manual/deployment.md | 9 +- src/libostree/ostree-sysroot-deploy.c | 379 +++++++++++++++++++------- tests/libtest.sh | 58 ++-- tests/test-admin-deploy-syslinux.sh | 45 ++- tests/test-admin-deploy-uboot.sh | 1 + 5 files changed, 364 insertions(+), 128 deletions(-) diff --git a/docs/manual/deployment.md b/docs/manual/deployment.md index 76d05701..0db03117 100644 --- a/docs/manual/deployment.md +++ b/docs/manual/deployment.md @@ -43,8 +43,13 @@ to a filesystem tree that represents the underlying basis of a deployment. For short, we will call this the "tree", to distinguish it from the concept of a deployment. -First, the tree must include a kernel stored as -`vmlinuz(-.*)?-$checksum` in either `/boot` or `/usr/lib/ostree-boot`. +First, the tree must include a kernel (and optionally an initramfs). The +current standard locations for these are `/usr/lib/modules/$kver/vmlinuz` and +`/usr/lib/modules/$kver/initramfs`. The "boot checksum" will be computed +automatically. This follows the current Fedora kernel layout, and is +the current recommended path. However, older versions of libostree don't +support this; you may need to also put kernels in the previous (legacy) +paths, which are `vmlinuz(-.*)?-$checksum` in either `/boot` or `/usr/lib/ostree-boot`. The checksum should be a SHA256 hash of the kernel contents; it must be pre-computed before storing the kernel in the repository. Optionally, the directory can also contain an initramfs, stored as diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 60fbc1d3..8b2f5e4b 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -882,46 +882,173 @@ ostree_sysroot_write_origin_file (OstreeSysroot *sysroot, cancellable, error); } -/* Originally OSTree defined kernels to be found underneath /boot - * in the tree. But that means when mounting /boot at runtime - * we end up masking the content underneath, triggering a warning. - * - * For that reason, and also consistency with the "/usr defines the OS" model we - * later switched to defining the in-tree kernels to be found under - * /usr/lib/ostree-boot. - */ -static gboolean -get_kernel_from_tree (int deployment_dfd, - int *out_boot_dfd, - char **out_kernel_srcpath, - char **out_kernel_namever, - char **out_initramfs_srcpath, - char **out_initramfs_namever, - char **out_bootcsum, - GCancellable *cancellable, - GError **error) +typedef struct { + int boot_dfd; + char *kernel_srcpath; + char *kernel_namever; + char *initramfs_srcpath; + char *initramfs_namever; + char *bootcsum; +} OstreeKernelLayout; +static void +_ostree_kernel_layout_free (OstreeKernelLayout *layout) { - g_autofree char *ret_kernel_srcpath = NULL; - g_autofree char *ret_kernel_namever = NULL; - g_autofree char *ret_initramfs_srcpath = NULL; - g_autofree char *ret_initramfs_namever = NULL; - g_autofree char *kernel_checksum = NULL; - g_autofree char *initramfs_checksum = NULL; + if (layout->boot_dfd != -1) + (void) close (layout->boot_dfd); + g_free (layout->kernel_srcpath); + g_free (layout->kernel_namever); + g_free (layout->initramfs_srcpath); + g_free (layout->initramfs_namever); + g_free (layout->bootcsum); + g_free (layout); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeKernelLayout, _ostree_kernel_layout_free); - glnx_fd_close int ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE); - if (ret_boot_dfd == -1) +static OstreeKernelLayout* +_ostree_kernel_layout_new (void) +{ + OstreeKernelLayout *ret = g_new0 (OstreeKernelLayout, 1); + ret->boot_dfd = -1; + return ret; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_usrlib_modules (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *kver = NULL; + /* Look in usr/lib/modules */ + g_auto(GLnxDirFdIterator) mod_dfditer = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (deployment_dfd, "usr/lib/modules", &mod_dfditer, + &exists, error)) + return FALSE; + if (!exists) { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "%s", "openat(usr/lib/ostree-boot)"); - else - { - if (!glnx_opendirat (deployment_dfd, "boot", TRUE, &ret_boot_dfd, error)) - return FALSE; - } + /* No usr/lib/modules? We're done */ + *out_layout = NULL; + return TRUE; } + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + /* Reusable buffer for path string */ + g_autoptr(GString) pathbuf = g_string_new (""); + /* Loop until we find something that looks like a valid /usr/lib/modules/$kver */ + while (ret_layout->boot_dfd == -1) + { + struct dirent *dent; + struct stat stbuf; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&mod_dfditer, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + /* It's a directory, look for /vmlinuz as a regular file */ + g_string_truncate (pathbuf, 0); + g_string_append_printf (pathbuf, "%s/vmlinuz", dent->d_name); + if (fstatat (mod_dfditer.fd, pathbuf->str, &stbuf, 0) < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat(%s)", pathbuf->str); + else + continue; + } + else + { + /* Not a regular file? Loop again */ + if (!S_ISREG (stbuf.st_mode)) + continue; + } + + /* Looks valid, this should exit the loop */ + if (!glnx_opendirat (mod_dfditer.fd, dent->d_name, FALSE, &ret_layout->boot_dfd, error)) + return FALSE; + kver = g_strdup (dent->d_name); + ret_layout->kernel_srcpath = g_strdup ("vmlinuz"); + ret_layout->kernel_namever = g_strdup_printf ("vmlinuz-%s", kver); + } + + if (ret_layout->boot_dfd == -1) + { + *out_layout = NULL; + /* No kernel found? We're done. */ + return TRUE; + } + + /* We found a module directory, compute the checksum */ + g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); + glnx_fd_close int fd = -1; + /* Checksum the kernel */ + if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error)) + return FALSE; + g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + g_clear_object (&in); + (void) close (fd); fd = -1; + + /* Look for an initramfs, but it's optional */ + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "initramfs", &fd, error)) + return FALSE; + if (fd != -1) + { + ret_layout->initramfs_srcpath = g_strdup ("initramfs"); + ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s", kver); + in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + } + + ret_layout->bootcsum = g_strdup (g_checksum_get_string (checksum)); + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_legacy_layouts (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + const char *legacy_paths[] = {"usr/lib/ostree-boot", "boot"}; + g_autofree char *kernel_checksum = NULL; + g_autofree char *initramfs_checksum = NULL; + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + for (guint i = 0; i < G_N_ELEMENTS (legacy_paths); i++) + { + const char *path = legacy_paths[i]; + ret_layout->boot_dfd = glnx_opendirat_with_errno (deployment_dfd, path, TRUE); + if (ret_layout->boot_dfd == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + } + else + break; + } + + if (ret_layout->boot_dfd == -1) + { + /* No legacy found? We're done */ + *out_layout = NULL; + return TRUE; + } + + /* ret_layout->boot_dfd will point to either /usr/lib/ostree-boot or /boot, let's + * inspect it. + */ g_auto(GLnxDirFdIterator) dfditer = { 0, }; - if (!glnx_dirfd_iterator_init_at (ret_boot_dfd, ".", FALSE, &dfditer, error)) + if (!glnx_dirfd_iterator_init_at (ret_layout->boot_dfd, ".", FALSE, &dfditer, error)) return FALSE; while (TRUE) @@ -930,62 +1057,143 @@ get_kernel_from_tree (int deployment_dfd, if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) return FALSE; - if (dent == NULL) break; const char *name = dent->d_name; - if (ret_kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) + /* See if this is the kernel */ + if (ret_layout->kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) { const char *dash = strrchr (name, '-'); g_assert (dash); + /* In this version, we require that the tree builder generated a + * sha256 of the kernel+initramfs and appended it to the file names. + */ if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { kernel_checksum = g_strdup (dash + 1); - ret_kernel_srcpath = g_strdup (name); - ret_kernel_namever = g_strndup (name, dash - name); + ret_layout->kernel_srcpath = g_strdup (name); + ret_layout->kernel_namever = g_strndup (name, dash - name); } } - else if (ret_initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) + /* See if this is the initramfs */ + else if (ret_layout->initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) { const char *dash = strrchr (name, '-'); g_assert (dash); if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { initramfs_checksum = g_strdup (dash + 1); - ret_initramfs_srcpath = g_strdup (name); - ret_initramfs_namever = g_strndup (name, dash - name); + ret_layout->initramfs_srcpath = g_strdup (name); + ret_layout->initramfs_namever = g_strndup (name, dash - name); } } - if (ret_kernel_srcpath != NULL && ret_initramfs_srcpath != NULL) + /* If we found both a kernel and initramfs, break out of the loop */ + if (ret_layout->kernel_srcpath != NULL && ret_layout->initramfs_srcpath != NULL) break; } - if (ret_kernel_srcpath == NULL) + /* No kernel found? We're done */ + if (ret_layout->kernel_srcpath == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Failed to find kernel in /usr/lib/ostree-boot or /boot"); - return FALSE; + *out_layout = NULL; + return TRUE; } - if (ret_initramfs_srcpath != NULL) + /* The kernel/initramfs checksums must be the same */ + if (ret_layout->initramfs_srcpath != NULL) { + g_assert (kernel_checksum != NULL); + g_assert (initramfs_checksum != NULL); if (strcmp (kernel_checksum, initramfs_checksum) != 0) + return glnx_throw (error, "Mismatched kernel checksum vs initrd"); + ret_layout->bootcsum = g_steal_pointer (&kernel_checksum); + } + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* Locate kernel/initramfs in the tree; the current standard is to look in + * /usr/lib/modules/$kver/vmlinuz first. + * + * Originally OSTree defined kernels to be found underneath /boot + * in the tree. But that means when mounting /boot at runtime + * we end up masking the content underneath, triggering a warning. + * + * For that reason, and also consistency with the "/usr defines the OS" model we + * later switched to defining the in-tree kernels to be found under + * /usr/lib/ostree-boot. But since then, Fedora at least switched to storing the + * kernel in /usr/lib/modules, which makes sense and isn't ostree-specific, so + * we prefer that now. However, the default Fedora layout doesn't put the + * initramfs there, so we need to look in /usr/lib/ostree-boot first. + */ +static gboolean +get_kernel_from_tree (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeKernelLayout) usrlib_modules_layout = NULL; + g_autoptr(OstreeKernelLayout) legacy_layout = NULL; + + /* First, gather from usr/lib/modules/$kver if it exists */ + if (!get_kernel_from_tree_usrlib_modules (deployment_dfd, &usrlib_modules_layout, cancellable, error)) + return FALSE; + + /* Gather the legacy layout */ + if (!get_kernel_from_tree_legacy_layouts (deployment_dfd, &legacy_layout, cancellable, error)) + return FALSE; + + /* Evaluate the state of both layouts. If there's no legacy layout + * If a legacy layout exists, and it has + * an initramfs but the module layout doesn't, the legacy layout wins. This is + * what happens with rpm-ostree with Fedora today, until rpm-ostree learns the + * new layout. + */ + if (legacy_layout == NULL) + { + /* No legacy layout, let's see if we have a module layout...*/ + if (usrlib_modules_layout == NULL) { + /* Both layouts are not found? Throw. */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Mismatched kernel checksum vs initrd"); + "Failed to find kernel in /usr/lib/modules, /usr/lib/ostree-boot or /boot"); return FALSE; } + else + { + /* No legacy, just usr/lib/modules? We're done */ + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + } + else if (usrlib_modules_layout != NULL && + usrlib_modules_layout->initramfs_srcpath == NULL && + legacy_layout->initramfs_srcpath != NULL) + { + /* Does the module path not have an initramfs, but the legacy does? Prefer + * the latter then, to make rpm-ostree work as is today. + */ + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; + } + /* Prefer module layout */ + else if (usrlib_modules_layout != NULL) + { + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + else + { + /* And finally fall back to legacy; we know one exists since we + * checked first above. + */ + g_assert (legacy_layout->kernel_srcpath); + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; } - - *out_boot_dfd = glnx_steal_fd (&ret_boot_dfd); - *out_kernel_srcpath = g_steal_pointer (&ret_kernel_srcpath); - *out_kernel_namever = g_steal_pointer (&ret_kernel_namever); - *out_initramfs_srcpath = g_steal_pointer (&ret_initramfs_srcpath); - *out_initramfs_namever = g_steal_pointer (&ret_initramfs_namever); - *out_bootcsum = g_steal_pointer (&kernel_checksum); - return TRUE; } /* We used to syncfs(), but that doesn't flush the journal on XFS, @@ -1315,18 +1523,8 @@ install_deployment_kernel (OstreeSysroot *sysroot, return FALSE; /* Find the kernel/initramfs in the tree */ - glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_srcpath = NULL; - g_autofree char *tree_kernel_namever = NULL; - g_autofree char *tree_initramfs_srcpath = NULL; - g_autofree char *tree_initramfs_namever = NULL; - g_autofree char *tree_bootcsum = NULL; - if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_srcpath, - &tree_kernel_namever, - &tree_initramfs_srcpath, - &tree_initramfs_namever, - &tree_bootcsum, + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; @@ -1336,7 +1534,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, const char *osname = ostree_deployment_get_osname (deployment); const char *bootcsum = ostree_deployment_get_bootcsum (deployment); - g_assert_cmpstr (bootcsum, ==, tree_bootcsum); + g_assert_cmpstr (kernel_layout->bootcsum, ==, bootcsum); g_autofree char *bootcsumdir = g_strdup_printf ("ostree/%s-%s", osname, bootcsum); g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", new_bootversion); g_autofree char *bootconf_name = g_strdup_printf ("ostree-%s-%d.conf", osname, @@ -1355,12 +1553,13 @@ install_deployment_kernel (OstreeSysroot *sysroot, * it doesn't exist already. */ struct stat stbuf; - if (fstatat (bootcsum_dfd, tree_kernel_namever, &stbuf, 0) != 0) + if (fstatat (bootcsum_dfd, kernel_layout->kernel_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", tree_kernel_namever); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_srcpath, - bootcsum_dfd, tree_kernel_namever, + return glnx_throw_errno_prefix (error, "fstat %s", kernel_layout->kernel_namever); + if (!hardlink_or_copy_at (kernel_layout->boot_dfd, + kernel_layout->kernel_srcpath, + bootcsum_dfd, kernel_layout->kernel_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1369,15 +1568,15 @@ install_deployment_kernel (OstreeSysroot *sysroot, /* If we have an initramfs, then install it into * /boot/ostree/osname-${bootcsum} if it doesn't exist already. */ - if (tree_initramfs_srcpath) + if (kernel_layout->initramfs_srcpath) { - g_assert (tree_initramfs_namever); - if (fstatat (bootcsum_dfd, tree_initramfs_namever, &stbuf, 0) != 0) + g_assert (kernel_layout->initramfs_namever); + if (fstatat (bootcsum_dfd, kernel_layout->initramfs_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", tree_initramfs_namever); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_srcpath, - bootcsum_dfd, tree_initramfs_namever, + return glnx_throw_errno_prefix (error, "fstat %s", kernel_layout->initramfs_namever); + if (!hardlink_or_copy_at (kernel_layout->boot_dfd, kernel_layout->initramfs_srcpath, + bootcsum_dfd, kernel_layout->initramfs_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1458,12 +1657,12 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment)); ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key); - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_kernel_namever, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); - if (tree_initramfs_namever) + if (kernel_layout->initramfs_namever) { - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_initramfs_namever, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath); } @@ -2084,22 +2283,12 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, return FALSE; } - glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_srcpath = NULL; - g_autofree char *tree_kernel_namever = NULL; - g_autofree char *tree_initramfs_srcpath = NULL; - g_autofree char *tree_initramfs_namever = NULL; - g_autofree char *tree_bootcsum = NULL; - if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_srcpath, - &tree_kernel_namever, - &tree_initramfs_srcpath, - &tree_initramfs_namever, - &new_bootcsum, + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; - _ostree_deployment_set_bootcsum (new_deployment, new_bootcsum); + _ostree_deployment_set_bootcsum (new_deployment, kernel_layout->bootcsum); /* Create an empty boot configuration; we will merge things into * it as we go. diff --git a/tests/libtest.sh b/tests/libtest.sh index ff096505..ce7cc3d9 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -366,7 +366,7 @@ setup_os_repository () { shift bootmode=$1 shift - bootdir=${1:-usr/lib/ostree-boot} + bootdir=${1:-usr/lib/modules/3.6.0} oldpwd=`pwd` @@ -381,17 +381,24 @@ setup_os_repository () { cd ${test_tmpdir} mkdir osdata cd osdata - mkdir -p usr/bin usr/lib/modules/3.6.0 usr/share usr/etc - mkdir -p ${bootdir} - echo "a kernel" > ${bootdir}/vmlinuz-3.6.0 - echo "an initramfs" > ${bootdir}/initramfs-3.6.0 - bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + mkdir -p usr/bin ${bootdir} usr/lib/modules/3.6.0 usr/share usr/etc + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs + # /usr/lib/modules just uses "vmlinuz", since the version is in the module + # directory name. + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-3.6.0 + initramfs_path=${initramfs_path}-3.6.0 + fi + echo "a kernel" > ${kernel_path} + echo "an initramfs" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') export bootcsum # Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not # /usr/lib/modules. - if [[ $bootdir != usr/lib/modules ]]; then - mv ${bootdir}/vmlinuz-3.6.0{,-${bootcsum}} - mv ${bootdir}/initramfs-3.6.0{,-${bootcsum}} + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} fi echo "an executable" > usr/bin/sh @@ -412,7 +419,7 @@ EOF echo "a default daemon file" > usr/etc/testdirectory/test ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" - + # Ensure these commits have distinct second timestamps sleep 2 echo "a new executable" > usr/bin/sh @@ -447,7 +454,7 @@ EOF setup_os_boot_grub2 "${bootmode}" ;; esac - + cd ${test_tmpdir} mkdir ${test_tmpdir}/httpd cd httpd @@ -465,17 +472,30 @@ os_repository_new_commit () branch=${3:-testos/buildmaster/x86_64-runtime} echo "BOOT ITERATION: $boot_checksum_iteration" cd ${test_tmpdir}/osdata - bootdir=usr/lib/ostree-boot - if ! test -d ${bootdir}; then - bootdir=boot + if test -f usr/lib/modules/3.6.0/vmlinuz; then + bootdir=usr/lib/modules/3.6.0 + else + if test -d usr/lib/ostree-boot; then + bootdir=usr/lib/ostree-boot + else + bootdir=boot + fi fi rm ${bootdir}/* - echo "new: a kernel ${boot_checksum_iteration}" > ${bootdir}/vmlinuz-3.6.0 - echo "new: an initramfs ${boot_checksum_iteration}" > ${bootdir}/initramfs-3.6.0 - bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-3.6.0 + initramfs_path=${initramfs_path}-3.6.0 + fi + echo "new: a kernel ${boot_checksum_iteration}" > ${kernel_path} + echo "new: an initramfs ${boot_checksum_iteration}" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') export bootcsum - mv ${bootdir}/vmlinuz-3.6.0 ${bootdir}/vmlinuz-3.6.0-${bootcsum} - mv ${bootdir}/initramfs-3.6.0 ${bootdir}/initramfs-3.6.0-${bootcsum} + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi echo "a new default config file" > usr/etc/a-new-default-config-file mkdir -p usr/etc/new-default-dir diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index b19a74f0..2a3c497d 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..20" +echo "1..22" . $(dirname $0)/libtest.sh @@ -28,22 +28,43 @@ setup_os_repository "archive-z2" "syslinux" . $(dirname $0)/admin-test.sh +# Test the legacy dirs +for test_bootdir in "boot" "usr/lib/ostree-boot"; do + cd ${test_tmpdir} + rm httpd osdata testos-repo sysroot -rf + setup_os_repository "archive" "syslinux" $test_bootdir + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime + rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' + assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' + # kernel/initrams should also be in the tree's /boot with the checksum + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/vmlinuz-3.6.0-${bootcsum} 'a kernel' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0-${bootcsum} 'an initramfs' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' + assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' + ${CMD_PREFIX} ostree admin status + validate_bootloader + echo "ok kernel in $test_bootdir" +done + +# And test that legacy overrides /usr/lib/modules cd ${test_tmpdir} rm httpd osdata testos-repo sysroot -rf -setup_os_repository "archive-z2" "syslinux" "boot" - +setup_os_repository "archive" "syslinux" "usr/lib/ostree-boot" +cd osdata +echo "this is a kernel without an initramfs like Fedora 26" > usr/lib/modules/3.6.0/vmlinuz +usrlib_modules_bootcsum=$(cat usr/lib/modules/3.6.0/vmlinuz | sha256sum | cut -f 1 -d ' ') +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" +cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' -assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' -# kernel/initrams should also be in the tree's /boot with the checksum -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/vmlinuz-3.6.0-${bootcsum} 'a kernel' -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/initramfs-3.6.0-${bootcsum} 'an initramfs' -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' -assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' -${CMD_PREFIX} ostree admin status -validate_bootloader -echo "ok kernel in tree's /boot" +# Note this bootcsum shouldn't be the modules one +assert_not_streq "${bootcsum}" "${usrlib_modules_bootcsum}" +echo "ok kernel in /usr/lib/modules and /usr/lib/ostree-boot" diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index 3685e31e..c7a6c751 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -30,6 +30,7 @@ setup_os_repository "archive-z2" "uboot" . $(dirname $0)/admin-test.sh cd ${test_tmpdir} +mkdir -p osdata/usr/lib/ostree-boot cat << 'EOF' > osdata/usr/lib/ostree-boot/uEnv.txt loaduimage=load mmc ${bootpart} ${loadaddr} ${kernel_image} loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}${fdtfile} From 7b3e55a3f4915a8baf110c3e64d143bd2e3beda1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 18 Aug 2017 11:04:58 -0400 Subject: [PATCH 05/83] docs/build: s/libOSTree/libostree/ I find "libOSTree" awkward to type and really to look at. Let's be nicer on people's pinky fingers and eyes and drop it all down to lowercase. Closes: #1093 Approved by: jlebon --- README.md | 34 ++++++++++++++++++---------------- configure.ac | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 743d49df..3e72c061 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ -libOSTree -====== +libostree +--------- New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ ) ----- -This project is now known as "libOSTree", renamed from "OSTree"; the focus is on -the shared library. However, in most of the rest of the documentation, we will -use the term "OSTree", since it's slightly shorter, and changing all -documentation at once is impractical. We expect to transition to the new name -over time. +This project is now known as "libostree", though it is still appropriate to use +the previous name: "OSTree" (or "ostree"). The focus is on projects which use +libostree's shared library, rather than users directly invoking the command line +tools (except for build systems). However, in most of the rest of the +documentation, we will use the term "OSTree", since it's slightly shorter, and +changing all documentation at once is impractical. We expect to transition to +the new name over time. -libOSTree is a library and suite of command line tools that combines a -"git-like" model for committing and downloading bootable filesystem trees, along -with a layer for deploying them and managing the bootloader configuration. +As implied above, libostree is both a shared library and suite of command line +tools that combines a "git-like" model for committing and downloading bootable +filesystem trees, along with a layer for deploying them and managing the +bootloader configuration. The core OSTree model is like git in that it checksums individual files and has a content-addressed-object store. It's unlike git in that it "checks out" the @@ -24,16 +27,14 @@ of **Features:** - - Atomic upgrades and rollback for the system + - Transactional upgrades and rollback for the system - Replicating content incrementally over HTTP via GPG signatures and "pinned TLS" support - Support for parallel installing more than just 2 bootable roots - Binary history on the server side (and client) - Introspectable shared library API for build and deployment systems - -This last point is important - you should think of the OSTree command -line as effectively a "demo" for the shared library. The intent is that -package managers, system upgrade tools, container build tools and the like -use OSTree as a "deduplicating hardlink store". + - Flexible support for multiple branches and repositories, supporting + projects like [flatpak](https://github.com/flatpak/flatpak) which + use libostree for applications, rather than hosts. Projects using OSTree --------------------- @@ -87,6 +88,7 @@ Once you have a git clone or recursive archive, building is the same as almost every autotools project: ``` +git submodule update --init env NOCONFIGURE=1 ./autogen.sh ./configure --prefix=... make diff --git a/configure.ac b/configure.ac index 72f96d3c..88dbc709 100644 --- a/configure.ac +++ b/configure.ac @@ -525,7 +525,7 @@ src/libostree/ostree-version.h AC_OUTPUT echo " - libOSTree $VERSION ($release_build_type) + libostree $VERSION ($release_build_type) =============== From 1e5b06be5b7351ba4b9b398ac4d5431348ae6c03 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 18 Aug 2017 20:51:10 -0400 Subject: [PATCH 06/83] lib/deploy: Add .img to end of initramfs in /usr/lib/modules Follow up to ; I was working on the rpm-ostree updates for this, and I think it's more consistent if we have `.img` here, since that's a closer match to the "remove $kver" that results in `vmlinuz`. Also just best practice to have file suffix types where they make sense. The astute reader might notice this sneaks in a change where we'd crash if the legacy bootdir didn't have an initramfs...yeah, should probably have test coverage of that. Closes: #1095 Approved by: jlebon --- docs/manual/deployment.md | 2 +- src/libostree/ostree-sysroot-deploy.c | 27 +++++++++++++++++++++------ tests/libtest.sh | 20 +++++++++++--------- tests/test-admin-deploy-syslinux.sh | 6 +++--- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/docs/manual/deployment.md b/docs/manual/deployment.md index 0db03117..013a2d0e 100644 --- a/docs/manual/deployment.md +++ b/docs/manual/deployment.md @@ -45,7 +45,7 @@ distinguish it from the concept of a deployment. First, the tree must include a kernel (and optionally an initramfs). The current standard locations for these are `/usr/lib/modules/$kver/vmlinuz` and -`/usr/lib/modules/$kver/initramfs`. The "boot checksum" will be computed +`/usr/lib/modules/$kver/initramfs.img`. The "boot checksum" will be computed automatically. This follows the current Fedora kernel layout, and is the current recommended path. However, older versions of libostree don't support this; you may need to also put kernels in the previous (legacy) diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 8b2f5e4b..f50f2457 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -994,13 +994,27 @@ get_kernel_from_tree_usrlib_modules (int deployment_dfd, g_clear_object (&in); (void) close (fd); fd = -1; - /* Look for an initramfs, but it's optional */ - if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "initramfs", &fd, error)) - return FALSE; + /* Look for an initramfs, but it's optional; since there wasn't any precedent + * for this, let's be a bit conservative and support both `initramfs.img` and + * `initramfs`. + */ + const char *initramfs_paths[] = {"initramfs.img", "initramfs"}; + const char *initramfs_path = NULL; + for (guint i = 0; i < G_N_ELEMENTS(initramfs_paths); i++) + { + initramfs_path = initramfs_paths[i]; + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, initramfs_path, &fd, error)) + return FALSE; + if (fd != -1) + break; + else + initramfs_path = NULL; + } if (fd != -1) { - ret_layout->initramfs_srcpath = g_strdup ("initramfs"); - ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s", kver); + g_assert (initramfs_path); + ret_layout->initramfs_srcpath = g_strdup (initramfs_path); + ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s.img", kver); in = g_unix_input_stream_new (fd, FALSE); if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) return FALSE; @@ -1108,9 +1122,10 @@ get_kernel_from_tree_legacy_layouts (int deployment_dfd, g_assert (initramfs_checksum != NULL); if (strcmp (kernel_checksum, initramfs_checksum) != 0) return glnx_throw (error, "Mismatched kernel checksum vs initrd"); - ret_layout->bootcsum = g_steal_pointer (&kernel_checksum); } + ret_layout->bootcsum = g_steal_pointer (&kernel_checksum); + *out_layout = g_steal_pointer (&ret_layout); return TRUE; } diff --git a/tests/libtest.sh b/tests/libtest.sh index ce7cc3d9..1381a69e 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -381,14 +381,15 @@ setup_os_repository () { cd ${test_tmpdir} mkdir osdata cd osdata - mkdir -p usr/bin ${bootdir} usr/lib/modules/3.6.0 usr/share usr/etc + kver=3.6.0 + mkdir -p usr/bin ${bootdir} usr/lib/modules/${kver} usr/share usr/etc kernel_path=${bootdir}/vmlinuz - initramfs_path=${bootdir}/initramfs + initramfs_path=${bootdir}/initramfs.img # /usr/lib/modules just uses "vmlinuz", since the version is in the module # directory name. if [[ $bootdir != usr/lib/modules/* ]]; then - kernel_path=${kernel_path}-3.6.0 - initramfs_path=${initramfs_path}-3.6.0 + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img fi echo "a kernel" > ${kernel_path} echo "an initramfs" > ${initramfs_path} @@ -472,8 +473,9 @@ os_repository_new_commit () branch=${3:-testos/buildmaster/x86_64-runtime} echo "BOOT ITERATION: $boot_checksum_iteration" cd ${test_tmpdir}/osdata - if test -f usr/lib/modules/3.6.0/vmlinuz; then - bootdir=usr/lib/modules/3.6.0 + kver=3.6.0 + if test -f usr/lib/modules/${kver}/vmlinuz; then + bootdir=usr/lib/modules/${kver} else if test -d usr/lib/ostree-boot; then bootdir=usr/lib/ostree-boot @@ -483,10 +485,10 @@ os_repository_new_commit () fi rm ${bootdir}/* kernel_path=${bootdir}/vmlinuz - initramfs_path=${bootdir}/initramfs + initramfs_path=${bootdir}/initramfs.img if [[ $bootdir != usr/lib/modules/* ]]; then - kernel_path=${kernel_path}-3.6.0 - initramfs_path=${initramfs_path}-3.6.0 + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img fi echo "new: a kernel ${boot_checksum_iteration}" > ${kernel_path} echo "new: an initramfs ${boot_checksum_iteration}" > ${initramfs_path} diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index 2a3c497d..3516c478 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -39,10 +39,10 @@ for test_bootdir in "boot" "usr/lib/ostree-boot"; do assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' - assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' # kernel/initrams should also be in the tree's /boot with the checksum assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/vmlinuz-3.6.0-${bootcsum} 'a kernel' - assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0-${bootcsum} 'an initramfs' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0.img-${bootcsum} 'an initramfs' assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin status @@ -64,7 +64,7 @@ rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmast ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' -assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' # Note this bootcsum shouldn't be the modules one assert_not_streq "${bootcsum}" "${usrlib_modules_bootcsum}" echo "ok kernel in /usr/lib/modules and /usr/lib/ostree-boot" From ca61a2bd9d5002ac6cdf2371077e15b0c25da2bc Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Mon, 21 Aug 2017 09:42:48 +0300 Subject: [PATCH 07/83] lib/sysroot: fix placement for not-default deployment When using the OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT flag, the deployment is said to be added after the booted or merge deployment. Fix the condition to do so instead of adding it in the second place. Closes: #1097 Approved by: cgwalters --- src/libostree/ostree-sysroot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 86a4f37a..e6471ab5 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -1545,7 +1545,7 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, g_ptr_array_add (new_deployments, g_object_ref (deployment)); } - if (!added_new) + if ((!added_new) && is_merge_or_booted) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); added_new = TRUE; From 618617d68b6ea82a71b3394ccd726e6b4b3e156e Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 18 May 2017 18:12:33 -0400 Subject: [PATCH 08/83] lib/pull: Add support for timestamp-check option, use in upgrader For both flatpak and ostree-as-host, we really want to verify up front during pulls that we're not being downgraded. Currently both flatpak and `OstreeSysrootUpgrader` do this before deployments, but at that point we've already downloaded all the data, which is annoying. Closes: https://github.com/ostreedev/ostree/issues/687 Closes: #1055 Approved by: jlebon --- src/libostree/ostree-core-private.h | 7 +++ src/libostree/ostree-core.c | 32 ++++++++++++++ src/libostree/ostree-repo-pull.c | 54 +++++++++++++++++++++++ src/libostree/ostree-sysroot-upgrader.c | 45 +++++++++---------- src/ostree/ot-builtin-pull.c | 5 +++ tests/libtest.sh | 10 ++++- tests/pull-test.sh | 27 +++++++++++- tests/test-admin-upgrade-not-backwards.sh | 30 ++++++++++--- 8 files changed, 178 insertions(+), 32 deletions(-) diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h index 799bd228..5a2835d5 100644 --- a/src/libostree/ostree-core-private.h +++ b/src/libostree/ostree-core-private.h @@ -179,6 +179,13 @@ _ostree_raw_file_to_archive_stream (GInputStream *input, gboolean ostree_validate_collection_id (const char *collection_id, GError **error); #endif /* !OSTREE_ENABLE_EXPERIMENTAL_API */ +gboolean +_ostree_compare_timestamps (const char *current_rev, + guint64 current_ts, + const char *new_rev, + guint64 new_ts, + GError **error); + #if (defined(OSTREE_COMPILATION) || GLIB_CHECK_VERSION(2, 44, 0)) && !defined(OSTREE_ENABLE_EXPERIMENTAL_API) #include #include "ostree-ref.h" diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index c13d2f2e..4118cf7e 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -2086,6 +2086,38 @@ ostree_commit_get_timestamp (GVariant *commit_variant) return GUINT64_FROM_BE (ret); } +/* Used in pull/deploy to validate we're not being downgraded */ +gboolean +_ostree_compare_timestamps (const char *current_rev, + guint64 current_ts, + const char *new_rev, + guint64 new_ts, + GError **error) +{ + /* Newer timestamp is OK */ + if (new_ts > current_ts) + return TRUE; + /* If they're equal, ensure they're the same rev */ + if (new_ts == current_ts || strcmp (current_rev, new_rev) == 0) + return TRUE; + + /* Looks like a downgrade, format an error message */ + g_autoptr(GDateTime) current_dt = g_date_time_new_from_unix_utc (current_ts); + g_autoptr(GDateTime) new_dt = g_date_time_new_from_unix_utc (new_ts); + + if (current_dt == NULL || new_dt == NULL) + return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid", + new_rev, new_ts, + current_rev, current_ts); + + g_autofree char *current_ts_str = g_date_time_format (current_dt, "%c"); + g_autofree char *new_ts_str = g_date_time_format (new_dt, "%c"); + + return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'", + new_rev, new_ts_str, current_rev, current_ts_str); +} + + GVariant * _ostree_detached_metadata_append_gpg_sig (GVariant *existing_metadata, GBytes *signature_bytes) diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index e21342fe..0bb1bc04 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -104,6 +104,7 @@ typedef struct { GBytes *summary_data_sig; GVariant *summary; GHashTable *summary_deltas_checksums; + GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */ GPtrArray *static_delta_superblocks; GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */ GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */ @@ -136,6 +137,7 @@ typedef struct { guint n_fetched_localcache_metadata; guint n_fetched_localcache_content; + gboolean timestamp_check; /* Verify commit timestamps */ int maxdepth; guint64 start_time; @@ -1647,6 +1649,33 @@ scan_commit_object (OtPullData *pull_data, goto out; } + if (pull_data->timestamp_check) + { + /* We don't support timestamp checking while recursing right now */ + g_assert (ref); + g_assert_cmpint (recursion_depth, ==, 0); + const char *orig_rev = NULL; + if (!g_hash_table_lookup_extended (pull_data->ref_original_commits, + ref, NULL, (void**)&orig_rev)) + g_assert_not_reached (); + + g_autoptr(GVariant) orig_commit = NULL; + if (orig_rev) + { + if (!ostree_repo_load_commit (pull_data->repo, orig_rev, + &orig_commit, NULL, error)) + { + g_prefix_error (error, "Reading %s for timestamp-check: ", ref->ref_name); + goto out; + } + + guint64 orig_ts = ostree_commit_get_timestamp (orig_commit); + guint64 new_ts = ostree_commit_get_timestamp (commit); + if (!_ostree_compare_timestamps (orig_rev, orig_ts, checksum, new_ts, error)) + goto out; + } + } + /* If we found a legacy transaction flag, assume all commits are partial */ is_partial = commitstate_is_partial (pull_data, commitstate); @@ -3199,6 +3228,7 @@ initiate_request (OtPullData *pull_data, * * disable-static-deltas (b): Do not use static deltas * * require-static-deltas (b): Require static deltas * * override-commit-ids (as): Array of specific commit IDs to fetch for refs + * * timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11 * * dry-run (b): Only print information on what will be downloaded (requires static deltas) * * override-url (s): Fetch objects from this URL if remote specifies no metalink in options * * inherit-transaction (b): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction. @@ -3275,10 +3305,12 @@ ostree_repo_pull_with_options (OstreeRepo *self, (void) g_variant_lookup (options, "http-headers", "@a(ss)", &pull_data->extra_headers); (void) g_variant_lookup (options, "update-frequency", "u", &update_frequency); (void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos); + (void) g_variant_lookup (options, "timestamp-check", "b", &pull_data->timestamp_check); } g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE); + g_return_val_if_fail (!pull_data->timestamp_check || pull_data->maxdepth == 0, FALSE); g_return_val_if_fail (!opt_collection_refs_set || (refs_to_fetch == NULL && override_commit_ids == NULL), FALSE); if (refs_to_fetch && override_commit_ids) @@ -3322,6 +3354,9 @@ ostree_repo_pull_with_options (OstreeRepo *self, pull_data->summary_deltas_checksums = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_free); + pull_data->ref_original_commits = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal, + (GDestroyNotify)NULL, + (GDestroyNotify)g_variant_unref); pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, (GDestroyNotify)g_variant_unref, NULL); pull_data->fetched_detached_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -3923,6 +3958,24 @@ ostree_repo_pull_with_options (OstreeRepo *self, ref_with_collection = ostree_collection_ref_dup (ref); } + /* If we have timestamp checking enabled, find the current value of + * the ref, and store its timestamp in the hash map, to check later. + */ + if (pull_data->timestamp_check) + { + g_autofree char *from_rev = NULL; + if (!ostree_repo_resolve_rev (pull_data->repo, ref_with_collection->ref_name, TRUE, + &from_rev, error)) + goto out; + /* Explicitly store NULL if there's no previous revision. We do + * this so we can assert() if we somehow didn't find a ref in the + * hash at all. Note we don't copy the collection-ref, so the + * lifetime of this hash must be equal to `requested_refs_to_fetch`. + */ + g_hash_table_insert (pull_data->ref_original_commits, ref_with_collection, + g_steal_pointer (&from_rev)); + } + g_hash_table_replace (updated_requested_refs_to_fetch, g_steal_pointer (&ref_with_collection), g_steal_pointer (&contents)); @@ -4223,6 +4276,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_clear_pointer (&pull_data->scanned_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->ref_original_commits, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref); diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c index 8afea3a6..f028fa7c 100644 --- a/src/libostree/ostree-sysroot-upgrader.c +++ b/src/libostree/ostree-sysroot-upgrader.c @@ -24,6 +24,7 @@ #include "ostree.h" #include "ostree-sysroot-upgrader.h" +#include "ostree-core-private.h" /** * SECTION:ostree-sysroot-upgrader @@ -429,26 +430,10 @@ ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, error)) return FALSE; - if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit)) - { - GDateTime *old_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (old_commit)); - GDateTime *new_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (new_commit)); - g_autofree char *old_ts_str = NULL; - g_autofree char *new_ts_str = NULL; - - if (old_ts == NULL || new_ts == NULL) - return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid", - to_rev, ostree_commit_get_timestamp (new_commit), - from_rev, ostree_commit_get_timestamp (old_commit)); - - old_ts_str = g_date_time_format (old_ts, "%c"); - new_ts_str = g_date_time_format (new_ts, "%c"); - g_date_time_unref (old_ts); - g_date_time_unref (new_ts); - - return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit", - to_rev, new_ts_str, from_rev, old_ts_str); - } + if (!_ostree_compare_timestamps (from_rev, ostree_commit_get_timestamp (old_commit), + to_rev, ostree_commit_get_timestamp (new_commit), + error)) + return FALSE; return TRUE; } @@ -536,9 +521,23 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, if (self->origin_remote && (upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC) == 0) { - if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch, - flags, progress, - cancellable, error)) + g_autoptr(GVariantBuilder) optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (dir_to_pull && *dir_to_pull) + g_variant_builder_add (optbuilder, "{s@v}", "subdir", + g_variant_new_variant (g_variant_new_string (dir_to_pull))); + g_variant_builder_add (optbuilder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (flags))); + /* Add the timestamp check, unless disabled */ + if ((upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER) == 0) + g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + + g_variant_builder_add (optbuilder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1))); + g_autoptr(GVariant) opts = g_variant_ref_sink (g_variant_builder_end (optbuilder)); + if (!ostree_repo_pull_with_options (repo, self->origin_remote, + opts, progress, + cancellable, error)) return FALSE; if (progress) diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index 37cfd143..eceddb0f 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -34,6 +34,7 @@ static gboolean opt_dry_run; static gboolean opt_disable_static_deltas; static gboolean opt_require_static_deltas; static gboolean opt_untrusted; +static gboolean opt_timestamp_check; static gboolean opt_bareuseronly_files; static char** opt_subpaths; static char** opt_http_headers; @@ -64,6 +65,7 @@ static GOptionEntry options[] = { { "http-header", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_http_headers, "Add NAME=VALUE as HTTP header to all requests", "NAME=VALUE" }, { "update-frequency", 0, 0, G_OPTION_ARG_INT, &opt_frequency, "Sets the update frequency, in milliseconds (0=1000ms) (default: 0)", "FREQUENCY" }, { "localcache-repo", 'L', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_localcache_repos, "Add REPO as local cache source for objects during this pull", "REPO" }, + { "timestamp-check", 'T', 0, G_OPTION_ARG_NONE, &opt_timestamp_check, "Require fetched commits to have newer timestamps", NULL }, { NULL } }; @@ -288,6 +290,9 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError ** g_variant_builder_add (&builder, "{s@v}", "dry-run", g_variant_new_variant (g_variant_new_boolean (opt_dry_run))); + if (opt_timestamp_check) + g_variant_builder_add (&builder, "{s@v}", "timestamp-check", + g_variant_new_variant (g_variant_new_boolean (opt_timestamp_check))); if (override_commit_ids) g_variant_builder_add (&builder, "{s@v}", "override-commit-ids", diff --git a/tests/libtest.sh b/tests/libtest.sh index 1381a69e..4db8b730 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -550,6 +550,14 @@ ostree_file_path_to_checksum() { $CMD_PREFIX ostree --repo=$repo ls -C $ref $path | awk '{ print $5 }' } +# Given an object checksum, print its relative file path +ostree_checksum_to_relative_object_path() { + repo=$1 + checksum=$2 + if grep -Eq -e '^mode=archive' ${repo}/config; then suffix=z; else suffix=''; fi + echo objects/${checksum:0:2}/${checksum:2}.file${suffix} +} + # Given a path to a file in a repo for a ref, print the (relative) path to its # object ostree_file_path_to_relative_object_path() { @@ -558,7 +566,7 @@ ostree_file_path_to_relative_object_path() { path=$3 checksum=$(ostree_file_path_to_checksum $repo $ref $path) test -n "${checksum}" - echo objects/${checksum:0:2}/${checksum:2}.file + ostree_checksum_to_relative_object_path ${repo} ${checksum} } # Given a path to a file in a repo for a ref, print the path to its object diff --git a/tests/pull-test.sh b/tests/pull-test.sh index f51d4445..f44c2ced 100644 --- a/tests/pull-test.sh +++ b/tests/pull-test.sh @@ -35,7 +35,7 @@ function verify_initial_contents() { assert_file_has_content baz/cow '^moo$' } -echo "1..28" +echo "1..29" # Try both syntaxes repo_init --no-gpg-verify @@ -205,6 +205,31 @@ ${CMD_PREFIX} ostree --repo=parentpullrepo rev-parse origin:main > main.txt assert_file_has_content main.txt ${rev} echo "ok pull specific commit" +# test pull -T +cd ${test_tmpdir} +repo_init --no-gpg-verify +${CMD_PREFIX} ostree --repo=repo pull origin main +origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse main) +# Check we can pull the same commit with timestamp checking enabled +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_streq ${origrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +newrev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# New commit with timestamp checking +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_not_streq "${origrev}" "${newrev}" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +newrev2=$(${CMD_PREFIX} ostree --timestamp="October 25 1985" --repo=ostree-srv/gnomerepo commit -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +if ${CMD_PREFIX} ostree --repo=repo pull -T origin main 2>err.txt; then + fatal "pulled older commit with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +# But we can pull it without timestamp checking +${CMD_PREFIX} ostree --repo=repo pull origin main +echo "ok pull timestamp checking" + cd ${test_tmpdir} repo_init --no-gpg-verify ${CMD_PREFIX} ostree --repo=repo pull origin main diff --git a/tests/test-admin-upgrade-not-backwards.sh b/tests/test-admin-upgrade-not-backwards.sh index fd1e1108..67d51737 100755 --- a/tests/test-admin-upgrade-not-backwards.sh +++ b/tests/test-admin-upgrade-not-backwards.sh @@ -26,26 +26,42 @@ setup_os_repository "archive-z2" "syslinux" echo "1..2" +ref=testos/buildmaster/x86_64-runtime cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo -${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime -rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos ${ref} +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse ${ref}) export rev echo "rev=${rev}" -# This initial deployment gets kicked off with some kernel arguments -${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:${ref} assert_has_dir sysroot/boot/ostree/testos-${bootcsum} # This should be a no-op ${CMD_PREFIX} ostree admin upgrade --os=testos -# Now reset to an older revision -${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo reset testos/buildmaster/x86_64-runtime{,^} - +# Generate a new commit with an older timestamp that also has +# some new content, so we test timestamp checking during pull +# +origrev=$(ostree --repo=${test_tmpdir}/sysroot/ostree/repo rev-parse testos:${ref}) +cd ${test_tmpdir}/osdata +echo "new content for pull timestamp checking" > usr/share/test-pull-ts-check.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=tscheck" \ + -b ${ref} --timestamp='October 25 1985' +newrev=$(ostree --repo=${test_tmpdir}/testos-repo rev-parse ${ref}) +assert_not_streq ${origrev} ${newrev} +cd ${test_tmpdir} +tscheck_checksum=$(ostree_file_path_to_checksum testos-repo ${ref} /usr/share/test-pull-ts-check.txt) +tscheck_fileobjpath=$(ostree_checksum_to_relative_object_path testos-repo ${tscheck_checksum}) +assert_has_file testos-repo/${tscheck_fileobjpath} if ${CMD_PREFIX} ostree admin upgrade --os=testos 2>upgrade-err.txt; then assert_not_reached 'upgrade unexpectedly succeeded' fi assert_file_has_content upgrade-err.txt 'chronologically older' +currev=$(ostree --repo=sysroot/ostree/repo rev-parse testos:${ref}) +assert_not_streq ${newrev} ${currev} +assert_streq ${origrev} ${currev} +assert_not_has_file sysroot/ostree/repo/$tscheck_fileobjpath echo 'ok upgrade will not go backwards' From 19429b1a26d29c26e436ac34599897211fb6d86a Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 21 Aug 2017 15:00:49 -0400 Subject: [PATCH 09/83] tests: fix admin upgrade timestamp file check In #1055, I tried to be helpful but that didn't work out all too well. We need to recompute the file path since one is in archive mode and the other in bare mode. Closes: #1098 Approved by: cgwalters --- tests/test-admin-upgrade-not-backwards.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test-admin-upgrade-not-backwards.sh b/tests/test-admin-upgrade-not-backwards.sh index 67d51737..491b8bbc 100755 --- a/tests/test-admin-upgrade-not-backwards.sh +++ b/tests/test-admin-upgrade-not-backwards.sh @@ -52,8 +52,8 @@ newrev=$(ostree --repo=${test_tmpdir}/testos-repo rev-parse ${ref}) assert_not_streq ${origrev} ${newrev} cd ${test_tmpdir} tscheck_checksum=$(ostree_file_path_to_checksum testos-repo ${ref} /usr/share/test-pull-ts-check.txt) -tscheck_fileobjpath=$(ostree_checksum_to_relative_object_path testos-repo ${tscheck_checksum}) -assert_has_file testos-repo/${tscheck_fileobjpath} +tscheck_filez_objpath=$(ostree_checksum_to_relative_object_path testos-repo ${tscheck_checksum}) +assert_has_file testos-repo/${tscheck_filez_objpath} if ${CMD_PREFIX} ostree admin upgrade --os=testos 2>upgrade-err.txt; then assert_not_reached 'upgrade unexpectedly succeeded' fi @@ -61,7 +61,8 @@ assert_file_has_content upgrade-err.txt 'chronologically older' currev=$(ostree --repo=sysroot/ostree/repo rev-parse testos:${ref}) assert_not_streq ${newrev} ${currev} assert_streq ${origrev} ${currev} -assert_not_has_file sysroot/ostree/repo/$tscheck_fileobjpath +tscheck_file_objpath=$(ostree_checksum_to_relative_object_path sysroot/ostree/repo ${tscheck_checksum}) +assert_not_has_file sysroot/ostree/repo/${tscheck_file_objpath} echo 'ok upgrade will not go backwards' From e3a4049c247ec5435e2c0967e24802551536bc45 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 22 Aug 2017 18:32:43 +0100 Subject: [PATCH 10/83] build: Add distcheck configure flags to fix systemd and bash-completion When running distcheck, the systemd system-generator and bash-completion scripts are installed in absolute paths (/usr and /lib) as looked up from their pkg-config files. This breaks distcheck. Use a ${prefix}-relative path for both of them when configuring for distcheck. Signed-off-by: Philip Withnall Closes: #1103 Approved by: cgwalters --- Makefile-bash.am | 3 +++ Makefile-switchroot.am | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Makefile-bash.am b/Makefile-bash.am index e61829a2..2cb03151 100644 --- a/Makefile-bash.am +++ b/Makefile-bash.am @@ -19,3 +19,6 @@ completionsdir = @BASH_COMPLETIONSDIR@ dist_completions_DATA = bash/ostree + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += BASH_COMPLETIONSDIR='$${datadir}/bash-completion/completions' diff --git a/Makefile-switchroot.am b/Makefile-switchroot.am index dd24010e..70aa1c87 100644 --- a/Makefile-switchroot.am +++ b/Makefile-switchroot.am @@ -68,4 +68,7 @@ ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ ostree_system_generator_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libostree ostree_system_generator_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) ostree_system_generator_LDADD = $(AM_LDFLAGS) libglnx.la libostree-1.la $(OT_INTERNAL_GIO_UNIX_LIBS) + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' endif From 80eab25f8ad367ba7f391a89558ef90eb69ce232 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 22 Aug 2017 18:33:57 +0100 Subject: [PATCH 11/83] build: Ensure ostree-tmpfiles.conf is distributed Signed-off-by: Philip Withnall Closes: #1103 Approved by: cgwalters --- Makefile-boot.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile-boot.am b/Makefile-boot.am index 213ff043..828187ec 100644 --- a/Makefile-boot.am +++ b/Makefile-boot.am @@ -39,7 +39,7 @@ if BUILDOPT_SYSTEMD systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ src/boot/ostree-remount.service systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d -systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf +dist_systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf # Allow the distcheck install under $prefix test to pass AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemunitdir='$${libdir}/systemd/system' From 11fdca291950771858872386560e1103df1dda5f Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 21 Aug 2017 16:52:59 -0400 Subject: [PATCH 12/83] pull: better description for --mirror Describe the behaviour of --mirror a bit better. Closes: #1100 Closes: #1099 Approved by: dustymabe --- man/ostree-pull.xml | 7 ++++++- src/libostree/ostree-repo.h | 2 +- src/ostree/ot-builtin-pull.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/man/ostree-pull.xml b/man/ostree-pull.xml index 59a6dbc8..9c970714 100644 --- a/man/ostree-pull.xml +++ b/man/ostree-pull.xml @@ -103,7 +103,12 @@ Boston, MA 02111-1307, USA. - Write refs suitable for a mirror. + Write refs suitable for a mirror, i.e. refs are stored in the + heads/ directory rather than the + remotes/ directory. This makes the target repo + suitable to be exported for other clients to pull from as an ostree + remote. If no specific refs are specified, all refs will be fetched (the + remote must have a summary file present). diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 8766e6df..ab1aa0b3 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -1081,7 +1081,7 @@ gboolean ostree_repo_prune_from_reachable (OstreeRepo *self, /** * OstreeRepoPullFlags: * @OSTREE_REPO_PULL_FLAGS_NONE: No special options for pull - * @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors + * @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors and fetch all refs if none requested * @OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY: Fetch only the commit metadata * @OSTREE_REPO_PULL_FLAGS_UNTRUSTED: Don't trust local remote * @OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES: Since 2017.7. Reject writes of content objects with modes outside of 0775. diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index eceddb0f..ebcde49d 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -55,7 +55,7 @@ static GOptionEntry options[] = { { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, - { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL }, + { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror and fetches all refs if none provided", NULL }, { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL }, { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL }, { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, From 556e2deb93e5af5a60e83da4bec5b218831a513f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 23 Aug 2017 09:37:44 -0400 Subject: [PATCH 13/83] lib/commit: Remove duplicated function for filter processing The wrapping here is unnecessary, since `_ostree_repo_commit_modifier_apply()` already does what this function did. Further, the return type was wrong. Saw this while doing some libarchive work. Closes: #1104 Approved by: jlebon --- src/libostree/ostree-repo-commit.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 1c6e5e8d..dd63bf1a 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -2335,6 +2335,10 @@ create_tree_variant_from_hashes (GHashTable *file_checksums, return serialized_tree; } +/* If any filtering is set up, perform it, and return modified file info in + * @out_modified_info. Note that if no filtering is applied, @out_modified_info + * will simply be another reference (with incremented refcount) to @file_info. + */ OstreeRepoCommitFilterResult _ostree_repo_commit_modifier_apply (OstreeRepo *self, OstreeRepoCommitModifier *modifier, @@ -2410,24 +2414,6 @@ ptrarray_path_join (GPtrArray *path) return g_string_free (path_buf, FALSE); } -static gboolean -apply_commit_filter (OstreeRepo *self, - OstreeRepoCommitModifier *modifier, - const char *relpath, - GFileInfo *file_info, - GFileInfo **out_modified_info) -{ - if (modifier == NULL || - (modifier->filter == NULL && - (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) == 0)) - { - *out_modified_info = g_object_ref (file_info); - return OSTREE_REPO_COMMIT_FILTER_ALLOW; - } - - return _ostree_repo_commit_modifier_apply (self, modifier, relpath, file_info, out_modified_info); -} - static gboolean get_modified_xattrs (OstreeRepo *self, OstreeRepoCommitModifier *modifier, @@ -2564,7 +2550,7 @@ write_directory_content_to_mtree_internal (OstreeRepo *self, if (modifier != NULL) child_relpath = ptrarray_path_join (path); - filter_result = apply_commit_filter (self, modifier, child_relpath, child_info, &modified_info); + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info); if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW) { @@ -2733,7 +2719,7 @@ write_directory_to_mtree_internal (OstreeRepo *self, relpath = ptrarray_path_join (path); g_autoptr(GFileInfo) modified_info = NULL; - filter_result = apply_commit_filter (self, modifier, relpath, child_info, &modified_info); + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info); if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) { @@ -2812,7 +2798,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self, { relpath = ptrarray_path_join (path); - filter_result = apply_commit_filter (self, modifier, relpath, child_info, &modified_info); + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info); } else { From eb6f7c6db83ce384f89a142f173c2c064dad2f33 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 23 Aug 2017 10:09:44 -0400 Subject: [PATCH 14/83] lib/commit: Honor commit filter for libarchive --tar-autocreate-parents This makes `ostree commit --tree=tar` honor `--owner-uid` and `--owner-gid` for the root directory. Prep for further commit filtering work, although mostly for the unit test cases; this ensures we can use `ostree checkout` after autocreating a root directory. Closes: #1104 Approved by: jlebon --- src/libostree/ostree-repo-libarchive.c | 6 +++++- tests/test-libarchive.sh | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c index 1839a088..8d9e8969 100644 --- a/src/libostree/ostree-repo-libarchive.c +++ b/src/libostree/ostree-repo-libarchive.c @@ -861,7 +861,11 @@ ostree_repo_import_archive_to_mtree (OstreeRepo *self, g_file_info_set_attribute_uint32 (fi, "unix::gid", 0); g_file_info_set_attribute_uint32 (fi, "unix::mode", DEFAULT_DIRMODE); - if (!aic_ensure_parent_dir_with_file_info (&aictx, mtree, "/", fi, NULL, + g_autoptr(GFileInfo) mfi = NULL; + (void)_ostree_repo_commit_modifier_apply (self, modifier, "/", + fi, &mfi); + + if (!aic_ensure_parent_dir_with_file_info (&aictx, mtree, "/", mfi, NULL, cancellable, error)) goto out; } diff --git a/tests/test-libarchive.sh b/tests/test-libarchive.sh index 6540b94b..6653fa6a 100755 --- a/tests/test-libarchive.sh +++ b/tests/test-libarchive.sh @@ -26,7 +26,7 @@ fi . $(dirname $0)/libtest.sh -echo "1..20" +echo "1..21" setup_test_repository "bare" @@ -154,3 +154,13 @@ $OSTREE checkout partial partial-checkout cd partial-checkout assert_file_has_content subdir/original "original" echo "ok tar partial commit contents" + +cd ${test_tmpdir} +tar -cf empty.tar.gz -T /dev/null +uid=$(id -u) +gid=$(id -g) +$OSTREE commit -b tar-empty --tar-autocreate-parents \ + --owner-uid=${uid} --owner-gid=${gid} --tree=tar=empty.tar.gz +$OSTREE ls tar-empty > ls.txt +assert_file_has_content ls.txt "d00755 ${uid} ${gid} 0 /" +echo "ok tar autocreate with owner uid/gid" From 89801dd481d129fd98b21a0a7e418d15c073dc7b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 23 Aug 2017 13:31:40 -0400 Subject: [PATCH 15/83] build/maint.mk: Comment out setting of LC_ALL This triggers obscure bugs; really we shouldn't be overriding the global locale here. In practice, production build systems will be using fixed locales anyways. Also, we only use a small subset of this file (`make syntax-check`), which appears to work OK without this. I will probably try to work out where to submit this as at least an issue report for upstream gnulib. Closes: https://github.com/ostreedev/ostree/issues/1101 Closes: #1107 Approved by: heftig --- maint.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/maint.mk b/maint.mk index ff231c7d..09ab2401 100644 --- a/maint.mk +++ b/maint.mk @@ -105,7 +105,8 @@ my_distdir = $(PACKAGE)-$(VERSION) # Prevent programs like 'sort' from considering distinct strings to be equal. # Doing it here saves us from having to set LC_ALL elsewhere in this file. -export LC_ALL = C +# NOTE: commented out for https://github.com/ostreedev/ostree/issues/1101 +# export LC_ALL = C ## --------------- ## ## Sanity checks. ## From 882fa906e2df2af1870b620d1482a00607337b60 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 23 Aug 2017 13:03:39 -0400 Subject: [PATCH 16/83] bin/main: Remove duplicated usage output on unknown commands It's been this way for a long time, though not forever; I went back to v2014.11 as a random choice and it worked then. Not going to bother doing a full archive search for this though. Anyone who wants more context can help themselves. Closes: https://github.com/ostreedev/ostree/issues/1096 Closes: #1106 Approved by: jlebon --- src/ostree/ot-main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 7b906bfa..c8c3490e 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -185,9 +185,6 @@ ostree_run (int argc, } } - help = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", help); - goto out; } From 95bac299e54020e6cc795b126deefc8c2c7820f4 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 23 Aug 2017 14:25:43 -0400 Subject: [PATCH 17/83] lib/repo: Add some assertions for ABI sizes Things like https://sourceware.org/libabigail/manual/abidiff.html look interesting but in a brief look I couldn't work out how to conveniently use them for quick ABI sanity checking without doing a diff from a previous build (which we could do but would be more involved). This way will at least catch struct ABI breaks on x86_64 which I think we'd be most likely to do accidentally when trying to use one of the previous unused values. I found the hole values via gdb's `pahole` command. Closes: #1108 Approved by: jlebon --- src/libostree/ostree-repo.c | 27 +++++++++++++++++++++++++++ src/libostree/ostree-repo.h | 5 +++++ 2 files changed, 32 insertions(+) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 795016ce..d6bc4a91 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -47,6 +47,33 @@ #include #include +/* ABI Size checks for ostree-repo.h, only for LP64 systems; + * https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models + */ +#if __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 8 && __SIZEOF_INT__ == 4 +G_STATIC_ASSERT(sizeof(OstreeRepoTransactionStats) == sizeof(int) * 4 + 8 * 5); +G_STATIC_ASSERT(sizeof(OstreeRepoImportArchiveOptions) == sizeof(int) * 9 + 4 + sizeof(void*) * 8); +G_STATIC_ASSERT(sizeof(OstreeRepoExportArchiveOptions) == sizeof(int) * 9 + 4 + 8 + sizeof(void*) * 8); +G_STATIC_ASSERT(sizeof(OstreeRepoCheckoutAtOptions) == + sizeof(OstreeRepoCheckoutMode) + sizeof(OstreeRepoCheckoutOverwriteMode) + + sizeof(int)*6 + + sizeof(int)*5 + + sizeof(int) + + sizeof(void*)*2 + + sizeof(int)*6 + + sizeof(void*)*7); +G_STATIC_ASSERT(sizeof(OstreeRepoCommitTraverseIter) == + sizeof(int) + sizeof(int) + + sizeof(void*) * 10 + + 130 + 6); /* 6 byte hole */ +G_STATIC_ASSERT(sizeof(OstreeRepoPruneOptions) == + sizeof(OstreeRepoPruneFlags) + + 4 + + sizeof(void*) + + sizeof(int) * 12 + + sizeof(void*) * 7); +#endif + /** * SECTION:ostree-repo * @title: Content-addressed object store diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index ab1aa0b3..0d58729d 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -724,6 +724,7 @@ typedef struct { guint disable_xattrs : 1; guint reserved : 31; + /* 4 byte hole on 64 bit arches */ guint64 timestamp_secs; guint unused_uint[8]; @@ -838,6 +839,7 @@ typedef struct { gboolean force_copy; /* Since: 2017.6 */ gboolean bareuseronly_dirs; /* Since: 2017.7 */ gboolean unused_bools[5]; + /* 4 byte hole on 64 bit */ const char *subpath; @@ -972,6 +974,7 @@ gboolean ostree_repo_traverse_commit_union (OstreeRepo *repo, struct _OstreeRepoCommitTraverseIter { gboolean initialized; + /* 4 byte hole on 64 bit */ gpointer dummy[10]; char dummy_checksum_data[(OSTREE_SHA256_STRING_LEN+1)*2]; }; @@ -1060,6 +1063,8 @@ gboolean ostree_repo_prune (OstreeRepo *self, struct _OstreeRepoPruneOptions { OstreeRepoPruneFlags flags; + /* 4 byte hole on 64 bit */ + GHashTable *reachable; /* Set (object names) */ gboolean unused_bools[6]; From 7ed881baa75192521fa972fa702c66470dc0a225 Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Mon, 21 Aug 2017 17:08:12 -0700 Subject: [PATCH 18/83] lib/repo-refs: Include remote refs when using collections When working with collections it can be useful to see remote refs rather than just local and mirrored ones. This commit changes the "ostree refs -c" output to include remote refs, and includes remote refs with collection IDs in summary file generation as well. The former behavior is consistent with how "ostree refs" works, and the latter behavior is useful in facilitating P2P updates even when mirrors haven't been configured. To accomplish this, OstreeRepoListRefsExtFlags was extended with an EXCLUDE_REMOTES flag. This was done rather than an INCLUDE_REMOTES flag so that existing calls to ostree_repo_list_refs_ext continue to have the same behavior. This flag was added to ostree_repo_list_collection_refs (which is an experimental API break). Also, add unit tests for the "refs -c" and summary file behavior, and update relevant tests. Closes: #1069 Approved by: cgwalters --- src/libostree/ostree-repo-finder-mount.c | 4 +- src/libostree/ostree-repo-private.h | 11 +- src/libostree/ostree-repo-prune.c | 2 +- src/libostree/ostree-repo-refs.c | 160 ++++++++++++++--------- src/libostree/ostree-repo.c | 3 +- src/libostree/ostree-repo.h | 15 ++- src/ostree/ot-builtin-fsck.c | 1 + src/ostree/ot-builtin-prune.c | 4 +- src/ostree/ot-builtin-refs.c | 3 +- tests/test-find-remotes.sh | 7 +- tests/test-refs-collections.sh | 22 ++++ tests/test-summary-collections.sh | 25 ++++ 12 files changed, 180 insertions(+), 77 deletions(-) diff --git a/src/libostree/ostree-repo-finder-mount.c b/src/libostree/ostree-repo-finder-mount.c index 7f257f68..b7b15bf0 100644 --- a/src/libostree/ostree-repo-finder-mount.c +++ b/src/libostree/ostree-repo-finder-mount.c @@ -314,7 +314,9 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde g_autoptr(GHashTable) repo_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ - if (!ostree_repo_list_collection_refs (repo, refs[i]->collection_id, &repo_refs, cancellable, &local_error)) + if (!ostree_repo_list_collection_refs (repo, refs[i]->collection_id, &repo_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, &local_error)) { g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its refs could not be listed: %s", refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message); diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index e38e48bc..121c2d52 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -396,11 +396,12 @@ gboolean ostree_repo_set_collection_id (OstreeRepo *self, const gchar *collection_id, GError **error); -gboolean ostree_repo_list_collection_refs (OstreeRepo *self, - const char *match_collection_id, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error); +gboolean ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error); void ostree_repo_transaction_set_collection_ref (OstreeRepo *self, const OstreeCollectionRef *ref, diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c index 7cd9eb2c..2b596ecb 100644 --- a/src/libostree/ostree-repo-prune.c +++ b/src/libostree/ostree-repo-prune.c @@ -335,7 +335,7 @@ ostree_repo_prune (OstreeRepo *self, g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeChecksumRef utf8) */ if (!ostree_repo_list_collection_refs (self, NULL, &all_collection_refs, - cancellable, error)) + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) return FALSE; GLNX_HASH_TABLE_FOREACH_V (all_collection_refs, const char*, checksum) diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index 6c113fb6..04c99a03 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -560,7 +560,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) return FALSE; - if (remote) + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES) && remote) { prefix_path = glnx_strjoina ("refs/remotes/", remote, "/"); path = glnx_strjoina (prefix_path, ref_prefix); @@ -620,32 +620,35 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, ret_all_refs, cancellable, error)) return FALSE; - g_string_truncate (base_path, 0); - - if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) - return FALSE; - - while (TRUE) + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES)) { - struct dirent *dent; - glnx_fd_close int remote_dfd = -1; + g_string_truncate (base_path, 0); - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) - return FALSE; - if (!dent) - break; - - if (dent->d_type != DT_DIR) - continue; - - if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) + if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) return FALSE; - if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path, - remote_dfd, ".", - ret_all_refs, - cancellable, error)) - return FALSE; + while (TRUE) + { + struct dirent *dent; + glnx_fd_close int remote_dfd = -1; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (!dent) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path, + remote_dfd, ".", + ret_all_refs, + cancellable, error)) + return FALSE; + } } } @@ -1101,27 +1104,33 @@ _ostree_repo_update_collection_refs (OstreeRepo *self, * @self: Repo * @match_collection_id: (nullable): If non-%NULL, only list refs from this collection * @out_all_refs: (out) (element-type OstreeCollectionRef utf8): Mapping from collection–ref to checksum + * @flags: Options controlling listing behavior * @cancellable: Cancellable * @error: Error * - * List all local and mirrored refs, mapping them to the commit checksums they - * currently point to in @out_all_refs. If @match_collection_id is specified, - * the results will be limited to those with an equal collection ID. + * List all local, mirrored, and remote refs, mapping them to the commit + * checksums they currently point to in @out_all_refs. If @match_collection_id + * is specified, the results will be limited to those with an equal collection + * ID. * * #OstreeCollectionRefs are guaranteed to be returned with their collection ID * set to a non-%NULL value; so no refs from `refs/heads` will be listed if no * collection ID is configured for the repository * (ostree_repo_get_collection_id()). * + * If you want to exclude refs from `refs/remotes`, use + * %OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES in @flags. + * * Returns: %TRUE on success, %FALSE otherwise * Since: 2017.8 */ gboolean -ostree_repo_list_collection_refs (OstreeRepo *self, - const char *match_collection_id, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error) +ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error) { g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); @@ -1130,6 +1139,10 @@ ostree_repo_list_collection_refs (OstreeRepo *self, if (match_collection_id != NULL && !ostree_validate_collection_id (match_collection_id, error)) return FALSE; + const gchar *refs_dirs[] = { "refs/mirrors", "refs/remotes", NULL }; + if (flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES) + refs_dirs[1] = NULL; + g_autoptr(GHashTable) ret_all_refs = NULL; ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash, @@ -1150,7 +1163,7 @@ ostree_repo_list_collection_refs (OstreeRepo *self, if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE, + if (!enumerate_refs_recurse (self, NULL, flags, main_collection_id, refs_heads_dfd, base_path, refs_heads_dfd, ".", ret_all_refs, cancellable, error)) @@ -1159,36 +1172,65 @@ ostree_repo_list_collection_refs (OstreeRepo *self, g_string_truncate (base_path, 0); - gboolean refs_mirrors_exists = FALSE; - if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "refs/mirrors", - &dfd_iter, &refs_mirrors_exists, error)) - return FALSE; - - while (refs_mirrors_exists) + for (const char **iter = refs_dirs; iter && *iter; iter++) { - struct dirent *dent; - glnx_fd_close int collection_dfd = -1; - - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) - return FALSE; - if (!dent) - break; - - if (dent->d_type != DT_DIR) - continue; - - if (match_collection_id != NULL && g_strcmp0 (match_collection_id, dent->d_name) != 0) - continue; - - if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &collection_dfd, error)) + const char *refs_dir = *iter; + gboolean refs_dir_exists = FALSE; + if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, refs_dir, + &dfd_iter, &refs_dir_exists, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE, - dent->d_name, collection_dfd, base_path, - collection_dfd, ".", - ret_all_refs, - cancellable, error)) - return FALSE; + while (refs_dir_exists) + { + struct dirent *dent; + glnx_fd_close int subdir_fd = -1; + const gchar *current_collection_id; + g_autofree gchar *remote_collection_id = NULL; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (!dent) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (g_strcmp0 (refs_dir, "refs/mirrors") == 0) + { + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, dent->d_name) != 0) + continue; + else + current_collection_id = dent->d_name; + } + else /* refs_dir = "refs/remotes" */ + { + g_autoptr(GError) local_error = NULL; + if (!ostree_repo_get_remote_option (self, dent->d_name, "collection-id", + NULL, &remote_collection_id, &local_error) || + !ostree_validate_collection_id (remote_collection_id, &local_error)) + { + g_debug ("Ignoring remote ‘%s’ due to no valid collection ID being configured for it: %s", + dent->d_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, current_collection_id) != 0) + continue; + else + current_collection_id = remote_collection_id; + } + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &subdir_fd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, NULL, flags, + current_collection_id, subdir_fd, base_path, + subdir_fd, ".", + ret_all_refs, + cancellable, error)) + return FALSE; + } } ot_transfer_out_value (out_all_refs, &ret_all_refs); diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index d6bc4a91..ba33a018 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -4941,7 +4941,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self, * backwards compatibility). */ { g_autoptr(GHashTable) collection_refs = NULL; - if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, cancellable, error)) + if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, + OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) return FALSE; gsize collection_map_size = 0; diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 0d58729d..73da31e8 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -475,10 +475,12 @@ gboolean ostree_repo_list_refs (OstreeRepo *self, * OstreeRepoListRefsExtFlags: * @OSTREE_REPO_LIST_REFS_EXT_NONE: No flags. * @OSTREE_REPO_LIST_REFS_EXT_ALIASES: Only list aliases. Since: 2017.10 + * @OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES: Exclude remote refs. Since: 2017.11 */ typedef enum { OSTREE_REPO_LIST_REFS_EXT_NONE = 0, - OSTREE_REPO_LIST_REFS_EXT_ALIASES = 1, + OSTREE_REPO_LIST_REFS_EXT_ALIASES = (1 << 0), + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES = (1 << 1), } OstreeRepoListRefsExtFlags; _OSTREE_PUBLIC @@ -1190,11 +1192,12 @@ gchar *ostree_repo_resolve_keyring_for_collection (OstreeRepo *self, GError **error); _OSTREE_PUBLIC -gboolean ostree_repo_list_collection_refs (OstreeRepo *self, - const char *match_collection_id, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error); +gboolean ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error); #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c index 795fe098..ed357eca 100644 --- a/src/ostree/ot-builtin-fsck.c +++ b/src/ostree/ot-builtin-fsck.c @@ -252,6 +252,7 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError ** g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ if (!ostree_repo_list_collection_refs (repo, NULL, &all_collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) return FALSE; diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c index 997d848d..fd00e5fd 100644 --- a/src/ostree/ot-builtin-prune.c +++ b/src/ostree/ot-builtin-prune.c @@ -82,7 +82,9 @@ delete_commit (OstreeRepo *repo, const char *commit_to_delete, GCancellable *can #ifdef OSTREE_ENABLE_EXPERIMENTAL_API /* And check refs which *are* in a collection. */ - if (!ostree_repo_list_collection_refs (repo, NULL, &collection_refs, cancellable, error)) + if (!ostree_repo_list_collection_refs (repo, NULL, &collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, error)) goto out; g_hash_table_iter_init (&hashiter, collection_refs); diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index ead4ba48..3742f050 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -64,7 +64,8 @@ do_ref_with_collections (OstreeRepo *repo, if (!ostree_repo_list_collection_refs (repo, (!opt_create) ? refspec_prefix : NULL, - &refs, cancellable, error)) + &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, + cancellable, error)) goto out; if (!opt_delete && !opt_create) diff --git a/tests/test-find-remotes.sh b/tests/test-find-remotes.sh index 0cf0127f..0bbe54f0 100755 --- a/tests/test-find-remotes.sh +++ b/tests/test-find-remotes.sh @@ -56,8 +56,11 @@ ${CMD_PREFIX} ostree --repo=local refs > refs assert_file_has_content refs "^apps-remote:app1$" assert_file_has_content refs "^os-remote:os/amd64/master$" -${CMD_PREFIX} ostree --repo=local refs --collections | wc -l > refscount -assert_file_has_content refscount "^0$" +${CMD_PREFIX} ostree --repo=local refs --collections > refs +cat refs | wc -l > refscount +assert_file_has_content refs "^(org.example.AppsCollection, app1)$" +assert_file_has_content refs "^(org.example.OsCollection, os/amd64/master)$" +assert_file_has_content refscount "^2$" # Create a local mirror repository where we pull the branches *in mirror mode* from the two remotes. # This should pull them into refs/mirrors, since the remotes advertise a collection ID. diff --git a/tests/test-refs-collections.sh b/tests/test-refs-collections.sh index 4d49247d..f36fd7b9 100755 --- a/tests/test-refs-collections.sh +++ b/tests/test-refs-collections.sh @@ -103,6 +103,28 @@ ${CMD_PREFIX} ostree --repo=repo refs --collections > refs assert_file_has_content refs "^(org.example.Collection, ctest)$" assert_file_has_content refs "^(org.example.NewCollection, ctest-mirror)$" +# Remote refs should be listed if they have collection IDs + +cd ${test_tmpdir} +mkdir collection-repo +ostree_repo_init collection-repo --collection-id org.example.RemoteCollection +mkdir -p adir +${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" + +cd ${test_tmpdir} +mkdir no-collection-repo +ostree_repo_init no-collection-repo +mkdir -p adir2 +${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_not_file_has_content refs "rcommit2" + echo "ok 1 refs collections" # Test that listing, creating and deleting refs works from an old repository diff --git a/tests/test-summary-collections.sh b/tests/test-summary-collections.sh index 989e63e8..d12100ba 100755 --- a/tests/test-summary-collections.sh +++ b/tests/test-summary-collections.sh @@ -55,4 +55,29 @@ ${CMD_PREFIX} ostree --repo=repo summary --update ${CMD_PREFIX} ostree --repo=repo summary --view > summary assert_file_has_content summary "(org.example.OtherCollection, test-1-mirror)$" +# Test that remote refs are listed, but only if they have collection IDs +cd ${test_tmpdir} +mkdir collection-repo +ostree_repo_init collection-repo --collection-id org.example.RemoteCollection +mkdir -p adir +${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "(org.example.RemoteCollection, rcommit)$" + +cd ${test_tmpdir} +mkdir no-collection-repo +ostree_repo_init no-collection-repo +mkdir -p adir2 +${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_not_file_has_content summary "rcommit2" + echo "ok summary collections" From d0f40a6af8fb391d5ee34ca6d4bc2abfc5b21e16 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 22 Aug 2017 17:10:54 -0400 Subject: [PATCH 19/83] ostree-sysroot: convert function to new style Also convert ot-admin-builtin-deploy.c. Prep for more work there. Closes: #1110 Approved by: cgwalters --- src/libostree/ostree-sysroot.c | 47 +++++++++++------------ src/ostree/ot-admin-builtin-deploy.c | 57 +++++++++++----------------- 2 files changed, 44 insertions(+), 60 deletions(-) diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index e6471ab5..65cfb7c3 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -256,7 +256,7 @@ ensure_sysroot_fd (OstreeSysroot *self, * Access a file descriptor that refers to the root directory of this * sysroot. ostree_sysroot_load() must have been invoked prior to * calling this function. - * + * * Returns: A file descriptor valid for the lifetime of @self */ int @@ -276,7 +276,7 @@ _ostree_sysroot_bump_mtime (OstreeSysroot *self, glnx_set_prefix_error_from_errno (error, "%s", "futimens"); return FALSE; } - return TRUE; + return TRUE; } /** @@ -894,7 +894,7 @@ ostree_sysroot_get_subbootversion (OstreeSysroot *self) /** * ostree_sysroot_get_booted_deployment: * @self: Sysroot - * + * * Returns: (transfer none): The currently booted deployment, or %NULL if none */ OstreeDeployment * @@ -1377,7 +1377,7 @@ lock_in_thread (GTask *task, * @cancellable: Cancellable * @callback: Callback * @user_data: User data - * + * * An asynchronous version of ostree_sysroot_lock(). */ void @@ -1395,7 +1395,7 @@ ostree_sysroot_lock_async (OstreeSysroot *self, * @self: Self * @result: Result * @error: Error - * + * * Call when ostree_sysroot_lock_async() is ready. */ gboolean @@ -1413,7 +1413,7 @@ ostree_sysroot_lock_finish (OstreeSysroot *self, * @osname: Name group of operating system checkouts * @cancellable: Cancellable * @error: Error - * + * * Initialize the directory structure for an "osname", which is a * group of operating system deployments, with a shared `/var`. One * is required for generating a deployment. @@ -1505,36 +1505,34 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - guint i; - OstreeDeployment *booted_deployment = NULL; - g_autoptr(GPtrArray) deployments = NULL; - g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); - const gboolean postclean = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0; - OstreeSysrootWriteDeploymentsOpts write_opts = { .do_postclean = postclean }; - gboolean retain = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; - const gboolean make_default = !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0); - gboolean added_new = FALSE; + const gboolean postclean = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0; + const gboolean retain = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; + const gboolean make_default = + !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0); - deployments = ostree_sysroot_get_deployments (sysroot); - booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); + OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); if (osname == NULL && booted_deployment) osname = ostree_deployment_get_osname (booted_deployment); + gboolean added_new = FALSE; + g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); if (make_default) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); added_new = TRUE; } - for (i = 0; i < deployments->len; i++) + for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; - const gboolean is_merge_or_booted = + const gboolean is_merge_or_booted = ostree_deployment_equal (deployment, booted_deployment) || ostree_deployment_equal (deployment, merge_deployment); - + /* Keep deployments with different osnames, as well as the * booted and merge deployments */ @@ -1562,13 +1560,12 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, added_new = TRUE; } + OstreeSysrootWriteDeploymentsOpts write_opts = { .do_postclean = postclean }; if (!ostree_sysroot_write_deployments_with_options (sysroot, new_deployments, &write_opts, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /* Deploy a copy of @target_deployment */ diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index 5df4923c..d67de791 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -57,64 +57,55 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *refspec; - g_autoptr(GOptionContext) context = NULL; - g_autoptr(OstreeSysroot) sysroot = NULL; - g_autoptr(GKeyFile) origin = NULL; - g_autoptr(OstreeRepo) repo = NULL; - g_autoptr(OstreeDeployment) new_deployment = NULL; - g_autoptr(OstreeDeployment) merge_deployment = NULL; - g_autofree char *revision = NULL; __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; - context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); + g_autoptr(GOptionContext) context = + g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); + g_autoptr(OstreeSysroot) sysroot = NULL; if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (argc < 2) { ot_util_usage_error (context, "REF/REV must be specified", error); - goto out; + return FALSE; } - refspec = argv[1]; + const char *refspec = argv[1]; if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) - goto out; + return FALSE; + OstreeRepo *repo = ostree_sysroot_repo (sysroot); /* Find the currently booted deployment, if any; we will ensure it * is present in the new deployment list. */ if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, cancellable, error)) - { - g_prefix_error (error, "Looking for booted deployment: "); - goto out; - } + return glnx_prefix_error (error, "Looking for booted deployment"); + g_autoptr(GKeyFile) origin = NULL; if (opt_origin_path) { origin = g_key_file_new (); - + if (!g_key_file_load_from_file (origin, opt_origin_path, 0, error)) - goto out; + return FALSE; } else { origin = ostree_sysroot_origin_new_from_refspec (sysroot, refspec); } + g_autofree char *revision = NULL; if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error)) - goto out; + return FALSE; - merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); + g_autoptr(OstreeDeployment) merge_deployment = + ostree_sysroot_get_merge_deployment (sysroot, opt_osname); /* Here we perform cleanup of any leftover data from previous * partial failures. This avoids having to call @@ -124,10 +115,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro * we find it. */ if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error)) - { - g_prefix_error (error, "Performing initial cleanup: "); - goto out; - } + return glnx_prefix_error (error, "Performing initial cleanup"); kargs = _ostree_kernel_args_new (); @@ -137,7 +125,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro if (opt_kernel_proc_cmdline) { if (!_ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error)) - goto out; + return FALSE; } else if (merge_deployment) { @@ -160,21 +148,20 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro { g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs); + g_autoptr(OstreeDeployment) new_deployment = NULL; if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment, kargs_strv, &new_deployment, cancellable, error)) - goto out; + return FALSE; } if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment, merge_deployment, opt_retain ? OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN : 0, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } From 9342be6e34b26891c38b671ec285bdcbc9107acd Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Wed, 23 Aug 2017 12:15:46 -0400 Subject: [PATCH 20/83] ostree-sysroot: make simple_write_deployment smarter This is a follow-up to https://github.com/ostreedev/ostree/pull/1097. We make simple_write_deployment smart enough so that it can be used for rpm-ostree's purposes. This is mostly an upstreaming of logic that already existed there. Notably we correctly append NOT_DEFAULT deployments *after* the booted deployment and we now support RETAIN_PENDING and RETAIN_ROLLBACK flags to have more granularity on deployment pruning. Expose these new flags on the CLI using new options (as well as expose the previously existing NOT_DEFAULT flag as --not-as-default). I couldn't add tests for --retain-pending because the merge deployment is always the topmost one. Though I did check that it worked in a VM. Closes: #1110 Approved by: cgwalters --- bash/ostree | 3 ++ man/ostree-admin-deploy.xml | 24 ++++++++++ src/libostree/ostree-sysroot.c | 66 ++++++++++++++++++++-------- src/libostree/ostree-sysroot.h | 2 + src/ostree/ot-admin-builtin-deploy.c | 42 +++++++++++------- tests/admin-test.sh | 35 ++++++++++++++- tests/test-admin-deploy-grub2.sh | 4 +- tests/test-admin-deploy-syslinux.sh | 4 +- tests/test-admin-deploy-uboot.sh | 4 +- 9 files changed, 143 insertions(+), 41 deletions(-) diff --git a/bash/ostree b/bash/ostree index f4305f69..fadb054d 100644 --- a/bash/ostree +++ b/bash/ostree @@ -253,6 +253,9 @@ _ostree_admin_deploy() { local boolean_options=" $main_boolean_options --retain + --retain-pending + --retain-rollback + --not-as-default --karg-proc-cmdline " diff --git a/man/ostree-admin-deploy.xml b/man/ostree-admin-deploy.xml index 347a4ba9..ec705b93 100644 --- a/man/ostree-admin-deploy.xml +++ b/man/ostree-admin-deploy.xml @@ -89,6 +89,30 @@ Boston, MA 02111-1307, USA. + + + + + Do not delete pending deployments. + + + + + + + + Do not delete rollback deployments. + + + + + + + + Append rather than prepend new deployment. + + + diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 65cfb7c3..8e6c475c 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -1487,6 +1487,12 @@ ostree_sysroot_init_osname (OstreeSysroot *self, * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is * specified, then all current deployments will be kept. * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING is + * specified, then pending deployments will be kept. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK is + * specified, then rollback deployments will be kept. + * * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is * specified, then instead of prepending, the new deployment will be * added right after the booted or merge deployment, instead of first. @@ -1507,10 +1513,14 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, { const gboolean postclean = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0; - const gboolean retain = - (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; const gboolean make_default = !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0); + const gboolean retain_pending = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING) > 0; + const gboolean retain_rollback = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK) > 0; + gboolean retain = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); @@ -1526,34 +1536,54 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, added_new = TRUE; } + /* without a booted and a merge deployment, retain_pending/rollback become meaningless; + * let's just retain all deployments in that case */ + if (!booted_deployment && !merge_deployment && (retain_pending || retain_rollback)) + retain = TRUE; + + /* tracks when we come across the booted deployment */ + gboolean before_booted = TRUE; + gboolean before_merge = TRUE; for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; - const gboolean is_merge_or_booted = - ostree_deployment_equal (deployment, booted_deployment) || - ostree_deployment_equal (deployment, merge_deployment); + const gboolean osname_matches = + (osname == NULL || g_str_equal (ostree_deployment_get_osname (deployment), osname)); + const gboolean is_booted = ostree_deployment_equal (deployment, booted_deployment); + const gboolean is_merge = ostree_deployment_equal (deployment, merge_deployment); - /* Keep deployments with different osnames, as well as the - * booted and merge deployments + if (is_booted) + before_booted = FALSE; + if (is_merge) + before_merge = FALSE; + + /* use the booted deployment as the "crossover" point between pending and rollback + * deployments, fall back on merge deployment */ + const gboolean passed_crossover = booted_deployment ? !before_booted : !before_merge; + + /* Retain deployment if: + * - we're explicitly asked to, or + * - the deployment is for another osname, or + * - we're keeping pending deployments and this is a pending deployment, or + * - this is the merge or boot deployment, or + * - we're keeping rollback deployments and this is a rollback deployment */ - if (retain || - (osname != NULL && strcmp (ostree_deployment_get_osname (deployment), osname) != 0) || - is_merge_or_booted) - { - g_ptr_array_add (new_deployments, g_object_ref (deployment)); - } + if (retain + || !osname_matches + || (retain_pending && !passed_crossover) + || (is_booted || is_merge) + || (retain_rollback && passed_crossover)) + g_ptr_array_add (new_deployments, g_object_ref (deployment)); - if ((!added_new) && is_merge_or_booted) + /* add right after booted/merge deployment */ + if (!added_new && passed_crossover) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); added_new = TRUE; } } - /* In this non-default case , an improvement in the future would be - * to put the new deployment right after the current default in the - * order. - */ + /* add it last if no crossover defined (or it's the first deployment in the sysroot) */ if (!added_new) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h index 3d2446f9..f2573d6b 100644 --- a/src/libostree/ostree-sysroot.h +++ b/src/libostree/ostree-sysroot.h @@ -207,6 +207,8 @@ typedef enum { OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN = (1 << 0), OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT = (1 << 1), OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN = (1 << 2), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING = (1 << 3), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK = (1 << 4), } OstreeSysrootSimpleWriteDeploymentFlags; _OSTREE_PUBLIC diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index d67de791..fa588f87 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -33,6 +33,9 @@ #include static gboolean opt_retain; +static gboolean opt_retain_pending; +static gboolean opt_retain_rollback; +static gboolean opt_not_as_default; static char **opt_kernel_argv; static char **opt_kernel_argv_append; static gboolean opt_kernel_proc_cmdline; @@ -47,7 +50,10 @@ static char *opt_origin_path; static GOptionEntry options[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, { "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" }, - { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployment", NULL }, + { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployments", NULL }, + { "retain-pending", 0, 0, G_OPTION_ARG_NONE, &opt_retain_pending, "Do not delete pending deployments", NULL }, + { "retain-rollback", 0, 0, G_OPTION_ARG_NONE, &opt_retain_rollback, "Do not delete rollback deployments", NULL }, + { "not-as-default", 0, 0, G_OPTION_ARG_NONE, &opt_not_as_default, "Append rather than prepend new deployment", NULL }, { "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" }, @@ -145,22 +151,28 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro _ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append); } - { - g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs); - g_autoptr(OstreeDeployment) new_deployment = NULL; - if (!ostree_sysroot_deploy_tree (sysroot, - opt_osname, revision, origin, - merge_deployment, kargs_strv, - &new_deployment, - cancellable, error)) - return FALSE; - } + g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs); + if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment, + kargs_strv, &new_deployment, cancellable, error)) + return FALSE; - if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, - new_deployment, merge_deployment, - opt_retain ? OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN : 0, - cancellable, error)) + OstreeSysrootSimpleWriteDeploymentFlags flags = 0; + if (opt_retain) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN; + else + { + if (opt_retain_pending) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING; + if (opt_retain_rollback) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK; + } + + if (opt_not_as_default) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT; + + if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment, + merge_deployment, flags, cancellable, error)) return FALSE; return TRUE; diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 55de7235..d5566959 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -19,6 +19,8 @@ set -euo pipefail +echo "1..$((21 + ${extra_admin_tests:-0}))" + function validate_bootloader() { cd ${test_tmpdir}; bootloader="" @@ -130,6 +132,8 @@ rm -r sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/testdirectory rm sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile ln -s /ENOENT sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/a-new-broken-symlink ${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 linktarget=$(readlink sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-broken-symlink) test "${linktarget}" = /ENOENT assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' @@ -138,9 +142,36 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-c assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile ${CMD_PREFIX} ostree admin status validate_bootloader - echo "ok deploy with modified /etc" +# we now have 5 deployments, let's bring that back down to 1 +for i in $(seq 4); do + ${CMD_PREFIX} ostree admin undeploy 0 +done +assert_has_file sysroot/boot/loader/entries/ostree-testos-0.conf +assert_not_has_file sysroot/boot/loader/entries/ostree-testos-1.conf +assert_not_has_file sysroot/boot/loader/entries/ostree-otheros-1.conf +${CMD_PREFIX} ostree admin deploy --not-as-default --os=otheros testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/loader.0 +assert_not_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-testos-0.conf +assert_has_file sysroot/boot/loader/entries/ostree-otheros-1.conf +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok deploy --not-as-default" + +${CMD_PREFIX} ostree admin deploy --retain-rollback --os=otheros testos:testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-otheros-0.conf +assert_has_file sysroot/boot/loader/entries/ostree-testos-1.conf +assert_has_file sysroot/boot/loader/entries/ostree-otheros-2.conf +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok deploy --retain-rollback" + os_repository_new_commit ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos:testos/buildmaster/x86_64-runtime) @@ -153,7 +184,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-r assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/a-new-default-config-file "a new default config file" assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/new-default-dir/moo "a new default dir and file" # And persist /etc changes from before -assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile ${CMD_PREFIX} ostree admin status validate_bootloader diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh index 6f785df5..60c7d05f 100755 --- a/tests/test-admin-deploy-grub2.sh +++ b/tests/test-admin-deploy-grub2.sh @@ -19,11 +19,11 @@ set -euo pipefail -echo "1..19" - . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. setup_os_repository "archive-z2" "grub2 ostree-grub-generator" +extra_admin_tests=0 + . $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index 3516c478..08f26b5e 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -19,13 +19,13 @@ set -euo pipefail -echo "1..22" - . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. setup_os_repository "archive-z2" "syslinux" +extra_admin_tests=3 + . $(dirname $0)/admin-test.sh # Test the legacy dirs diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index c7a6c751..55059b34 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -20,13 +20,13 @@ set -euo pipefail -echo "1..20" - . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. setup_os_repository "archive-z2" "uboot" +extra_admin_tests=1 + . $(dirname $0)/admin-test.sh cd ${test_tmpdir} From 5e30bbd1b9a1db6402425d5e0aa13fd61c6b539f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 25 Aug 2017 10:30:44 -0400 Subject: [PATCH 21/83] bin/commit: Add --selinux-policy option This was really straightforward to implement, and is useful for dev/test scenarios mainly like we have in rpm-ostree at least. Closes: https://github.com/ostreedev/ostree/issues/1113 Closes: #1114 Approved by: jlebon --- src/ostree/ot-builtin-commit.c | 19 ++++++++++++++++- tests/installed/itest-label-selinux.sh | 29 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100755 tests/installed/itest-label-selinux.sh diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 6d1ce060..9967f6dd 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -47,6 +47,7 @@ static gboolean opt_link_checkout_speedup; static gboolean opt_skip_if_unchanged; static gboolean opt_tar_autocreate_parents; static gboolean opt_no_xattrs; +static char *opt_selinux_policy; static gboolean opt_canonical_permissions; static char **opt_trees; static gint opt_owner_uid = -1; @@ -93,6 +94,7 @@ static GOptionEntry options[] = { { "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" }, { "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL }, { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL }, + { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" }, { "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL }, { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL }, @@ -395,6 +397,7 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError g_autoptr(GHashTable) mode_overrides = NULL; g_autoptr(GHashTable) skip_list = NULL; OstreeRepoCommitModifierFlags flags = 0; + g_autoptr(OstreeSePolicy) policy = NULL; OstreeRepoCommitModifier *modifier = NULL; OstreeRepoTransactionStats stats; struct CommitFilterData filter_data = { 0, }; @@ -459,12 +462,26 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError || opt_owner_gid >= 0 || opt_statoverride_file != NULL || opt_skiplist_file != NULL - || opt_no_xattrs) + || opt_no_xattrs + || opt_selinux_policy) { filter_data.mode_adds = mode_adds; filter_data.skip_list = skip_list; modifier = ostree_repo_commit_modifier_new (flags, commit_filter, &filter_data, NULL); + if (opt_selinux_policy) + { + glnx_fd_close int rootfs_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error)) + { + g_prefix_error (error, "selinux-policy: "); + goto out; + } + policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error); + if (!policy) + goto out; + ostree_repo_commit_modifier_set_sepolicy (modifier, policy); + } } if (opt_parent) diff --git a/tests/installed/itest-label-selinux.sh b/tests/installed/itest-label-selinux.sh new file mode 100755 index 00000000..1a2b4aaf --- /dev/null +++ b/tests/installed/itest-label-selinux.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Test commit --selinux-policy + +set -xeuo pipefail + +dn=$(dirname $0) +. ${dn}/libinsttest.sh + +cd /ostree/repo/tmp +rm co -rf +ostree checkout -H ${host_refspec} co +testbin=co/usr/bin/foo-a-generic-binary +assert_not_has_file "${testbin}" +# Make a test binary that we label as shell_exec_t on disk, but should be +# reset by --selinux-policy back to bin_t +echo 'test foo' > ${testbin} +chcon --reference co/usr/bin/true ${testbin} +oldcon=$(getfattr --only-values -m security.selinux ${testbin}) +chcon --reference co/usr/bin/bash ${testbin} +newcon=$(getfattr --only-values -m security.selinux ${testbin}) +assert_not_streq "${oldcon}" "${newcon}" +ostree --repo=/ostree/repo commit -b testbranch --link-checkout-speedup \ + --selinux-policy co --tree=dir=co +ostree --repo=/ostree/repo ls -X testbranch /usr/bin/foo-a-generic-binary > ls.txt +assert_file_has_content ls.txt ${oldcon} + +ostree --repo=/ostree/repo refs --delete testbranch +rm co -rf From 5f8e339e45314174dd49221fcf09197e8d1e7ba4 Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Thu, 24 Aug 2017 14:56:48 -0700 Subject: [PATCH 22/83] lib/repo-refs: Fix typos in last commit This fixes a whitespace error and a mistake that made it into the last commit, 7ed881baa, at the last minute. Closes: #1112 Approved by: cgwalters --- src/libostree/ostree-repo-refs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index 04c99a03..f8af3c43 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -1215,10 +1215,10 @@ ostree_repo_list_collection_refs (OstreeRepo *self, continue; } - if (match_collection_id != NULL && g_strcmp0 (match_collection_id, current_collection_id) != 0) + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, remote_collection_id) != 0) continue; else - current_collection_id = remote_collection_id; + current_collection_id = remote_collection_id; } if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &subdir_fd, error)) From 760ff2f66ec5058b0ddf82fc7dbdd9ffbae44c6b Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 29 Aug 2017 16:46:19 +0100 Subject: [PATCH 23/83] test-libarchive-import: Skip if extended attributes are unsupported This is the case at build-time on some (all?) Debian autobuilders. Signed-off-by: Simon McVittie Closes: #1120 Approved by: cgwalters --- tests/test-libarchive-import.c | 57 +++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/test-libarchive-import.c b/tests/test-libarchive-import.c index 8f884a66..6047d359 100644 --- a/tests/test-libarchive-import.c +++ b/tests/test-libarchive-import.c @@ -35,6 +35,7 @@ typedef struct { int fd; int fd_empty; char *tmpd; + GError *skip_all; } TestData; static void @@ -136,7 +137,13 @@ test_data_init (TestData *td) g_assert_cmpint (0, ==, mkdir ("repo", 0755)); ostree_repo_create (td->repo, OSTREE_REPO_MODE_BARE_USER, NULL, &error); - g_assert_no_error (error); + + /* G_IO_ERROR_NOT_SUPPORTED probably means no extended attribute support */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) + g_propagate_prefixed_error (&td->skip_all, g_steal_pointer (&error), + "Unable to set up repository: "); + else + g_assert_no_error (error); } } @@ -169,6 +176,12 @@ test_libarchive_noautocreate_empty (gconstpointer data) OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + test_archive_setup (td->fd_empty, a); (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); @@ -185,6 +198,12 @@ test_libarchive_autocreate_empty (gconstpointer data) OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + opts.autocreate_parents = 1; test_archive_setup (td->fd_empty, a); @@ -203,6 +222,12 @@ test_libarchive_error_device_file (gconstpointer data) OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + test_archive_setup (td->fd, a); (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); @@ -276,6 +301,12 @@ test_libarchive_ignore_device_file (gconstpointer data) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + test_archive_setup (td->fd, a); opts.ignore_unsupported_content = TRUE; @@ -338,6 +369,12 @@ test_libarchive_ostree_convention (gconstpointer data) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + test_archive_setup (td->fd, a); opts.autocreate_parents = TRUE; @@ -382,6 +419,12 @@ test_libarchive_xattr_callback (gconstpointer data) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); ostree_repo_commit_modifier_set_xattr_callback (modifier, xattr_cb, NULL, NULL); @@ -437,6 +480,12 @@ entry_pathname_test_helper (gconstpointer data, gboolean on) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); ostree_repo_commit_modifier_set_xattr_callback (modifier, path_cb, NULL, &met_etc_file); @@ -500,6 +549,12 @@ test_libarchive_selinux (gconstpointer data) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + { glnx_unref_object GFile *root = g_file_new_for_path ("/"); From 1d755977c89c9bd360c61e988b9d445d1d5a4d43 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 29 Aug 2017 17:01:41 +0100 Subject: [PATCH 24/83] test-pull-bareuser.sh: This test uses bare-user, hence needs xattrs Signed-off-by: Simon McVittie Closes: #1120 Approved by: cgwalters --- tests/test-pull-bareuser.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-pull-bareuser.sh b/tests/test-pull-bareuser.sh index 0729247f..2e357234 100755 --- a/tests/test-pull-bareuser.sh +++ b/tests/test-pull-bareuser.sh @@ -21,6 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh +skip_without_user_xattrs setup_fake_remote_repo1 "archive" repo_mode=bare-user From a7686a0c400524afeb3fad14e04c65105eaf7cdf Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 29 Aug 2017 17:02:18 +0100 Subject: [PATCH 25/83] libtest: Allow skipping single checks without user xattrs Signed-off-by: Simon McVittie Closes: #1120 Approved by: cgwalters --- tests/libtest.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/libtest.sh b/tests/libtest.sh index 4db8b730..73e88891 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -511,6 +511,17 @@ os_repository_new_commit () cd ${test_tmpdir} } +# Usage: if ! skip_one_without_user_xattrs; then ... more tests ...; fi +skip_one_without_user_xattrs () { + touch test-xattrs + if ! setfattr -n user.testvalue -v somevalue test-xattrs; then + echo "ok # SKIP - this test requires xattr support" + return 0 + else + return 1 + fi +} + skip_without_user_xattrs () { touch test-xattrs setfattr -n user.testvalue -v somevalue test-xattrs || \ From 41e6871e514dda1392354f642edb3484cf79af47 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 29 Aug 2017 17:02:43 +0100 Subject: [PATCH 26/83] basic-test: Skip explicit uses of bare-user if no user xattrs Signed-off-by: Simon McVittie Closes: #1120 Approved by: cgwalters --- tests/basic-test.sh | 138 ++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 61 deletions(-) diff --git a/tests/basic-test.sh b/tests/basic-test.sh index 9ae26f47..de4bd445 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -106,19 +106,23 @@ echo "ok shortened checksum" (cd repo && ${CMD_PREFIX} ostree rev-parse test2) echo "ok repo-in-cwd" -rm test-repo -rf -ostree_repo_init test-repo --mode=bare-user -ostree_repo_init test-repo --mode=bare-user -rm test-repo -rf -echo "ok repo-init on existing repo" +if ! skip_one_without_user_xattrs; then + rm test-repo -rf + ostree_repo_init test-repo --mode=bare-user + ostree_repo_init test-repo --mode=bare-user + rm test-repo -rf + echo "ok repo-init on existing repo" +fi -rm test-repo -rf -ostree_repo_init test-repo --mode=bare-user -${CMD_PREFIX} ostree --repo=test-repo refs -rm -rf test-repo/tmp -${CMD_PREFIX} ostree --repo=test-repo refs -assert_has_dir test-repo/tmp -echo "ok autocreate tmp" +if ! skip_one_without_user_xattrs; then + rm test-repo -rf + ostree_repo_init test-repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=test-repo refs + rm -rf test-repo/tmp + ${CMD_PREFIX} ostree --repo=test-repo refs + assert_has_dir test-repo/tmp + echo "ok autocreate tmp" +fi rm checkout-test2 -rf $OSTREE checkout test2 checkout-test2 @@ -262,27 +266,31 @@ cd ${test_tmpdir} assert_file_has_content diff-test2-2 'M */four$' echo "ok diff file changing type" -cd ${test_tmpdir} -mkdir repo2 -# Use a different mode to test hardlinking metadata only -if grep -q 'mode=archive' repo/config || is_bare_user_only_repo repo; then - opposite_mode=bare-user -else - opposite_mode=archive +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + mkdir repo2 + # Use a different mode to test hardlinking metadata only + if grep -q 'mode=archive' repo/config || is_bare_user_only_repo repo; then + opposite_mode=bare-user + else + opposite_mode=archive + fi + ostree_repo_init repo2 --mode=$opposite_mode + ${CMD_PREFIX} ostree --repo=repo2 pull-local repo + test2_commitid=$(${CMD_PREFIX} ostree --repo=repo rev-parse test2) + test2_commit_relpath=/objects/${test2_commitid:0:2}/${test2_commitid:2}.commit + assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath} + echo "ok pull-local (hardlinking metadata)" fi -ostree_repo_init repo2 --mode=$opposite_mode -${CMD_PREFIX} ostree --repo=repo2 pull-local repo -test2_commitid=$(${CMD_PREFIX} ostree --repo=repo rev-parse test2) -test2_commit_relpath=/objects/${test2_commitid:0:2}/${test2_commitid:2}.commit -assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath} -echo "ok pull-local (hardlinking metadata)" -cd ${test_tmpdir} -rm repo2 -rf && mkdir repo2 -ostree_repo_init repo2 --mode=$opposite_mode -${CMD_PREFIX} ostree --repo=repo2 pull-local --bareuseronly-files repo test2 -${CMD_PREFIX} ostree --repo=repo2 fsck -q -echo "ok pull-local --bareuseronly-files" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo2 -rf && mkdir repo2 + ostree_repo_init repo2 --mode=$opposite_mode + ${CMD_PREFIX} ostree --repo=repo2 pull-local --bareuseronly-files repo test2 + ${CMD_PREFIX} ostree --repo=repo2 fsck -q + echo "ok pull-local --bareuseronly-files" +fi # This is mostly a copy of the suid test in test-basic-user-only.sh, # but for the `pull --bareuseronly-files` case. @@ -303,11 +311,13 @@ fi assert_file_has_content err.txt 'object.*\.file: invalid mode.*with bits 040.*' echo "ok pull-local (bareuseronly files)" -cd ${test_tmpdir} -${CMD_PREFIX} ostree --repo=repo2 checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone -cd test2-checkout-from-local-clone -assert_file_has_content yet/another/tree/green 'leaf' -echo "ok local clone checkout" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=repo2 checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone + cd test2-checkout-from-local-clone + assert_file_has_content yet/another/tree/green 'leaf' + echo "ok local clone checkout" +fi $OSTREE checkout -U test2 checkout-user-test2 echo "ok user checkout" @@ -496,24 +506,28 @@ cd ${test_tmpdir} $OSTREE checkout test2 --allow-noent --subpath /enoent 2>/dev/null echo "ok subdir noent" -cd ${test_tmpdir} -mkdir repo3 -ostree_repo_init repo3 --mode=bare-user -${CMD_PREFIX} ostree --repo=repo3 pull-local --remote=aremote repo test2 -${CMD_PREFIX} ostree --repo=repo3 rev-parse aremote/test2 -echo "ok pull-local with --remote arg" - -cd ${test_tmpdir} -${CMD_PREFIX} ostree --repo=repo3 prune -find repo3/objects -name '*.commit' > objlist-before-prune -rm repo3/refs/heads/* repo3/refs/mirrors/* repo3/refs/remotes/* -rf -${CMD_PREFIX} ostree --repo=repo3 prune --refs-only -find repo3/objects -name '*.commit' > objlist-after-prune -if cmp -s objlist-before-prune objlist-after-prune; then - fatal "Prune didn't delete anything!" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + mkdir repo3 + ostree_repo_init repo3 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo3 pull-local --remote=aremote repo test2 + ${CMD_PREFIX} ostree --repo=repo3 rev-parse aremote/test2 + echo "ok pull-local with --remote arg" +fi + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=repo3 prune + find repo3/objects -name '*.commit' > objlist-before-prune + rm repo3/refs/heads/* repo3/refs/mirrors/* repo3/refs/remotes/* -rf + ${CMD_PREFIX} ostree --repo=repo3 prune --refs-only + find repo3/objects -name '*.commit' > objlist-after-prune + if cmp -s objlist-before-prune objlist-after-prune; then + fatal "Prune didn't delete anything!" + fi + rm repo3 objlist-before-prune objlist-after-prune -rf + echo "ok prune" fi -rm repo3 objlist-before-prune objlist-after-prune -rf -echo "ok prune" cd ${test_tmpdir} rm repo3 -rf @@ -597,14 +611,16 @@ $OSTREE show --print-detached-metadata-key=SIGNATURE test2 > test2-meta assert_file_has_content test2-meta "HANCOCK" echo "ok metadata commit with strings" -cd ${test_tmpdir} -rm repo2 -rf -mkdir repo2 -ostree_repo_init repo2 --mode=bare-user -${CMD_PREFIX} ostree --repo=repo2 pull-local repo -${CMD_PREFIX} ostree --repo=repo2 show --print-detached-metadata-key=SIGNATURE test2 > test2-meta -assert_file_has_content test2-meta "HANCOCK" -echo "ok pull-local after commit metadata" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo2 -rf + mkdir repo2 + ostree_repo_init repo2 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo2 pull-local repo + ${CMD_PREFIX} ostree --repo=repo2 show --print-detached-metadata-key=SIGNATURE test2 > test2-meta + assert_file_has_content test2-meta "HANCOCK" + echo "ok pull-local after commit metadata" +fi cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo remote --set=tls-permissive=true add aremote http://remote.example.com/repo testos/buildmaster/x86_64-runtime From 3fcd81df86b66c5abb61118d2ef3822304cb5da3 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 29 Aug 2017 17:03:37 +0100 Subject: [PATCH 27/83] test-basic-user-only: Skip final step if no user xattrs We don't want to skip the entire test, because the whole point of bare-user-only is that it works in the absence of xattrs; but we do need to skip this last stage, which explicitly uses a bare-user repository. Signed-off-by: Simon McVittie Closes: #1120 Approved by: cgwalters --- tests/test-basic-user-only.sh | 36 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/test-basic-user-only.sh b/tests/test-basic-user-only.sh index fb071fe4..ce69e49e 100755 --- a/tests/test-basic-user-only.sh +++ b/tests/test-basic-user-only.sh @@ -72,21 +72,23 @@ $CMD_PREFIX ostree --repo=repo checkout -U -H content-with-dir-world-writable di assert_file_has_mode dir-co/worldwritable-dir 775 echo "ok didn't make world-writable dir" -cd ${test_tmpdir} -rm repo-input -rf -rm repo -rf -ostree_repo_init repo init --mode=bare-user-only -ostree_repo_init repo-input init --mode=bare-user -rm files -rf && mkdir files -echo afile > files/afile -ln -s afile files/afile-link -$CMD_PREFIX ostree --repo=repo-input commit --canonical-permissions -b testtree --tree=dir=files -afile_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile) -afile_link_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile-link) -$CMD_PREFIX ostree pull-local --repo=repo repo-input -assert_files_hardlinked repo/${afile_relobjpath} repo-input/${afile_relobjpath} -if files_are_hardlinked repo/${afile_link_relobjpath} repo-input/${afile_link_relobjpath}; then - assert_not_reached "symlinks hardlinked across bare-user?" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo-input -rf + rm repo -rf + ostree_repo_init repo init --mode=bare-user-only + ostree_repo_init repo-input init --mode=bare-user + rm files -rf && mkdir files + echo afile > files/afile + ln -s afile files/afile-link + $CMD_PREFIX ostree --repo=repo-input commit --canonical-permissions -b testtree --tree=dir=files + afile_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile) + afile_link_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile-link) + $CMD_PREFIX ostree pull-local --repo=repo repo-input + assert_files_hardlinked repo/${afile_relobjpath} repo-input/${afile_relobjpath} + if files_are_hardlinked repo/${afile_link_relobjpath} repo-input/${afile_link_relobjpath}; then + assert_not_reached "symlinks hardlinked across bare-user?" + fi + $OSTREE fsck -q + echo "ok hardlink pull from bare-user" fi -$OSTREE fsck -q -echo "ok hardlink pull from bare-user" From 355e8516b04801caf50b0b8a218fc8f6321d8d05 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 29 Aug 2017 17:05:16 +0100 Subject: [PATCH 28/83] Remove shebang from bash completions bash completions are to be sourced. It makes little sense to execute them. Detected by Debian's Lintian tool, which warns about non-executable files that appear to be #! scripts. Signed-off-by: Simon McVittie Closes: #1119 Approved by: cgwalters --- bash/ostree | 2 -- 1 file changed, 2 deletions(-) diff --git a/bash/ostree b/bash/ostree index fadb054d..f12d88b7 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1,5 +1,3 @@ -#!/bin/bash -# # bash completion file for ostree commands # # This script provides completion of: From 138c4d7aaea9956ea686fb8d6fe13557e0ac4d6e Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 22 Aug 2017 21:52:24 -0400 Subject: [PATCH 29/83] libarchive: Add support for translating paths during commit For rpm-ostree, I want to move RPM files in `/boot` to `/usr/lib/ostree-boot`. This is currently impossible without forking the libarchive code. Supporting this is pretty straightforward; we already had pathname translation in the libarchive code, we just need to expose it as an option. On the command line side, I chose to wrap this as a regexp. That should be good enough for a lot of use cases; sophisticated users should as always be making use of the API. Note that this required some new `#ifdef LIBARCHIVE` bits to use the new API. Following previous patterns here, we use the new API only if a relevant option is enabled, ensuring unit test coverage of both paths. For the test cases, I ended up changing the accounting to avoid having to multiply the test count. Closes: #1105 Approved by: jlebon --- src/libostree/ostree-libarchive-private.h | 22 ++++++ src/libostree/ostree-repo-libarchive.c | 67 +++++++++-------- src/libostree/ostree-repo.h | 31 +++++++- src/ostree/ot-builtin-commit.c | 74 +++++++++++++++++-- tests/test-libarchive.sh | 88 ++++++++++++++++++----- 5 files changed, 229 insertions(+), 53 deletions(-) diff --git a/src/libostree/ostree-libarchive-private.h b/src/libostree/ostree-libarchive-private.h index 870ddf82..2797fbac 100644 --- a/src/libostree/ostree-libarchive-private.h +++ b/src/libostree/ostree-libarchive-private.h @@ -38,6 +38,28 @@ typedef struct archive OtAutoArchiveWrite; G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveWrite, archive_write_free) typedef struct archive OtAutoArchiveRead; G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveRead, archive_read_free) + +static inline OtAutoArchiveRead * +ot_open_archive_read (const char *path, GError **error) +{ + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + +#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL + archive_read_support_filter_all (a); +#else + archive_read_support_compression_all (a); +#endif + archive_read_support_format_all (a); + if (archive_read_open_filename (a, path, 8192) != ARCHIVE_OK) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", archive_error_string (a)); + return NULL; + } + + return g_steal_pointer (&a); +} + #endif G_END_DECLS diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c index 8d9e8969..b34e4871 100644 --- a/src/libostree/ostree-repo-libarchive.c +++ b/src/libostree/ostree-repo-libarchive.c @@ -123,24 +123,30 @@ squash_trailing_slashes (char *path) *endp = '\0'; } +/* Like archive_entry_stat(), but since some archives only store the permission + * mode bits in hardlink entries, so let's just make it into a regular file. + * Yes, this hack will work even if it's a hardlink to a symlink. + */ +static void +read_archive_entry_stat (struct archive_entry *entry, + struct stat *stbuf) +{ + const struct stat *st = archive_entry_stat (entry); + + *stbuf = *st; + if (archive_entry_hardlink (entry)) + stbuf->st_mode |= S_IFREG; +} + +/* Create a GFileInfo from archive_entry_stat() */ static GFileInfo * file_info_from_archive_entry (struct archive_entry *entry) { - const struct stat *st = archive_entry_stat (entry); - struct stat st_copy; + struct stat stbuf; + read_archive_entry_stat (entry, &stbuf); - /* Some archives only store the permission mode bits in hardlink entries, so - * let's just make it into a regular file. Yes, this hack will work even if - * it's a hardlink to a symlink. */ - if (archive_entry_hardlink (entry)) - { - st_copy = *st; - st_copy.st_mode |= S_IFREG; - st = &st_copy; - } - - g_autoptr(GFileInfo) info = _ostree_stbuf_to_gfileinfo (st); - if (S_ISLNK (st->st_mode)) + g_autoptr(GFileInfo) info = _ostree_stbuf_to_gfileinfo (&stbuf); + if (S_ISLNK (stbuf.st_mode)) g_file_info_set_attribute_byte_string (info, "standard::symlink-target", archive_entry_symlink (entry)); @@ -247,7 +253,18 @@ aic_get_final_path (OstreeRepoArchiveImportContext *ctx, const char *path, GError **error) { - if (ctx->opts->use_ostree_convention) + if (ctx->opts->translate_pathname) + { + struct stat stbuf; + path = path_relative (path, error); + read_archive_entry_stat (ctx->entry, &stbuf); + char *ret = ctx->opts->translate_pathname (ctx->repo, &stbuf, path, + ctx->opts->translate_pathname_user_data); + if (ret) + return ret; + /* Fall through */ + } + else if (ctx->opts->use_ostree_convention) return path_relative_ostree (path, error); return g_strdup (path_relative (path, error)); } @@ -258,7 +275,6 @@ aic_get_final_entry_pathname (OstreeRepoArchiveImportContext *ctx, { const char *pathname = archive_entry_pathname (ctx->entry); g_autofree char *final = aic_get_final_path (ctx, pathname, error); - if (final == NULL) return NULL; @@ -642,17 +658,17 @@ aic_import_entry (OstreeRepoArchiveImportContext *ctx, GCancellable *cancellable, GError **error) { - g_autoptr(GFileInfo) fi = NULL; - g_autoptr(OstreeMutableTree) parent = NULL; g_autofree char *path = aic_get_final_entry_pathname (ctx, error); if (path == NULL) return FALSE; + g_autoptr(GFileInfo) fi = NULL; if (aic_apply_modifier_filter (ctx, path, &fi) == OSTREE_REPO_COMMIT_FILTER_SKIP) return TRUE; + g_autoptr(OstreeMutableTree) parent = NULL; if (!aic_get_parent_dir (ctx, path, &parent, cancellable, error)) return FALSE; @@ -907,18 +923,9 @@ ostree_repo_write_archive_to_mtree (OstreeRepo *self, g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; -#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL - archive_read_support_filter_all (a); -#else - archive_read_support_compression_all (a); -#endif - archive_read_support_format_all (a); - if (archive_read_open_filename (a, gs_file_get_path_cached (archive), 8192) != ARCHIVE_OK) - { - propagate_libarchive_error (error, a); - goto out; - } - + a = ot_open_archive_read (gs_file_get_path_cached (archive), error); + if (!a) + goto out; opts.autocreate_parents = !!autocreate_parents; if (!ostree_repo_import_archive_to_mtree (self, &opts, a, mtree, modifier, cancellable, error)) diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 73da31e8..ab037020 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -22,6 +22,8 @@ #pragma once +#include + #include "ostree-core.h" #include "ostree-types.h" #include "ostree-async-progress.h" @@ -688,6 +690,31 @@ gboolean ostree_repo_write_archive_to_mtree (OstreeRepo * GCancellable *cancellable, GError **error); +/** + * OstreeRepoImportArchiveTranslatePathname: + * @repo: Repo + * @stbuf: Stat buffer + * @src_path: Path in the archive + * @user_data: User data + * + * Possibly change a pathname while importing an archive. If %NULL is returned, + * then @src_path will be used unchanged. Otherwise, return a new pathname which + * will be freed via `g_free()`. + * + * This pathname translation will be performed *before* any processing from an + * active `OstreeRepoCommitModifier`. Will be invoked for all directory and file + * types, first with outer directories, then their sub-files and directories. + * + * Note that enabling pathname translation will always override the setting for + * `use_ostree_convention`. + * + * Since: 2017.11 + */ +typedef char *(*OstreeRepoImportArchiveTranslatePathname) (OstreeRepo *repo, + const struct stat *stbuf, + const char *src_path, + gpointer user_data); + /** * OstreeRepoImportArchiveOptions: (skip) * @@ -703,7 +730,9 @@ typedef struct { guint reserved : 28; guint unused_uint[8]; - gpointer unused_ptrs[8]; + OstreeRepoImportArchiveTranslatePathname translate_pathname; + gpointer translate_pathname_user_data; + gpointer unused_ptrs[6]; } OstreeRepoImportArchiveOptions; _OSTREE_PUBLIC diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 9967f6dd..f07b95e2 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -30,6 +30,7 @@ #include "ot-tool-util.h" #include "parse-datetime.h" #include "ostree-repo-private.h" +#include "ostree-libarchive-private.h" static char *opt_subject; static char *opt_body; @@ -46,6 +47,7 @@ static char **opt_detached_metadata_strings; static gboolean opt_link_checkout_speedup; static gboolean opt_skip_if_unchanged; static gboolean opt_tar_autocreate_parents; +static char *opt_tar_pathname_filter; static gboolean opt_no_xattrs; static char *opt_selinux_policy; static gboolean opt_canonical_permissions; @@ -97,6 +99,7 @@ static GOptionEntry options[] = { { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" }, { "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL }, { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, + { "tar-pathname-filter", 0, 0, G_OPTION_ARG_STRING, &opt_tar_pathname_filter, "When loading tar archives, use REGEX,REPLACEMENT against path names", "REGEX,REPLACEMENT" }, { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL }, { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &opt_statoverride_file, "File containing list of modifications to make to permissions", "PATH" }, { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" }, @@ -221,6 +224,28 @@ commit_filter (OstreeRepo *self, return OSTREE_REPO_COMMIT_FILTER_ALLOW; } +typedef struct { + GRegex *regex; + const char *replacement; +} TranslatePathnameData; + +/* Implement --tar-pathname-filter */ +static char * +handle_translate_pathname (OstreeRepo *repo, + const struct stat *stbuf, + const char *path, + gpointer user_data) +{ + TranslatePathnameData *tpdata = user_data; + g_autoptr(GError) tmp_error = NULL; + char *ret = + g_regex_replace (tpdata->regex, path, -1, 0, + tpdata->replacement, 0, &tmp_error); + g_assert_no_error (tmp_error); + g_assert (ret); + return ret; +} + static gboolean commit_editor (OstreeRepo *repo, const char *branch, @@ -568,11 +593,50 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError } else if (strcmp (tree_type, "tar") == 0) { - object_to_commit = g_file_new_for_path (tree); - if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, - opt_tar_autocreate_parents, - cancellable, error)) - goto out; + if (!opt_tar_pathname_filter) + { + object_to_commit = g_file_new_for_path (tree); + if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, + opt_tar_autocreate_parents, + cancellable, error)) + goto out; + } + else + { +#ifdef HAVE_LIBARCHIVE + const char *comma = strchr (opt_tar_pathname_filter, ','); + if (!comma) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing ',' in --tar-pathname-filter"); + goto out; + } + const char *replacement = comma + 1; + g_autofree char *regexp_text = g_strndup (opt_tar_pathname_filter, comma - opt_tar_pathname_filter); + /* Use new API if we have a pathname filter */ + OstreeRepoImportArchiveOptions opts = { 0, }; + opts.autocreate_parents = opt_tar_autocreate_parents; + opts.translate_pathname = handle_translate_pathname; + g_autoptr(GRegex) regexp = g_regex_new (regexp_text, 0, 0, error); + TranslatePathnameData tpdata = { regexp, replacement }; + if (!regexp) + { + g_prefix_error (error, "--tar-pathname-filter: "); + goto out; + } + opts.translate_pathname_user_data = &tpdata; + g_autoptr(OtAutoArchiveRead) archive = ot_open_archive_read (tree, error); + if (!archive) + goto out; + if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, mtree, + modifier, cancellable, error)) + goto out; + } +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + return FALSE; +#endif } else if (strcmp (tree_type, "ref") == 0) { diff --git a/tests/test-libarchive.sh b/tests/test-libarchive.sh index 6653fa6a..c839ba91 100755 --- a/tests/test-libarchive.sh +++ b/tests/test-libarchive.sh @@ -26,14 +26,14 @@ fi . $(dirname $0)/libtest.sh -echo "1..21" +echo "1..13" setup_test_repository "bare" cd ${test_tmpdir} mkdir foo cd foo -mkdir -p usr/bin +mkdir -p usr/bin usr/lib echo contents > usr/bin/foo touch usr/bin/foo0 ln usr/bin/foo usr/bin/bar @@ -45,8 +45,12 @@ ln usr/bin/foo0 usr/local/bin/baz0 ln usr/bin/sl usr/local/bin/slhl touch usr/bin/setuidme touch usr/bin/skipme +echo "a library" > usr/lib/libfoo.so +echo "another library" > usr/lib/libbar.so +# Create a tar archive tar -c -z -f ../foo.tar.gz . +# Create a cpio archive find . | cpio -o -H newc > ../foo.cpio cd .. @@ -71,10 +75,17 @@ $OSTREE commit -s "from cpio" -b test-cpio \ echo "ok cpio commit" assert_valid_checkout () { - cd ${test_tmpdir} - $OSTREE checkout test-$1 test-$1-checkout - cd test-$1-checkout + ref=$1 + rm test-${ref}-checkout -rf + $OSTREE checkout test-${ref} test-${ref}-checkout + assert_valid_content test-${ref}-checkout + rm -rf test-${ref}-checkout +} + +assert_valid_content () { + dn=$1 + cd ${dn} # basic content check assert_file_has_content usr/bin/foo contents assert_file_has_content usr/bin/bar contents @@ -82,39 +93,35 @@ assert_valid_checkout () { assert_file_empty usr/bin/foo0 assert_file_empty usr/bin/bar0 assert_file_empty usr/local/bin/baz0 - echo "ok $1 contents" + assert_file_has_content usr/lib/libfoo.so 'a library' + assert_file_has_content usr/lib/libbar.so 'another library' # hardlinks assert_files_hardlinked usr/bin/foo usr/bin/bar assert_files_hardlinked usr/bin/foo usr/local/bin/baz - echo "ok $1 hardlink" assert_files_hardlinked usr/bin/foo0 usr/bin/bar0 assert_files_hardlinked usr/bin/foo0 usr/local/bin/baz0 - echo "ok $1 hardlink to empty files" # symlinks assert_symlink_has_content usr/bin/sl foo assert_file_has_content usr/bin/sl contents - echo "ok $1 symlink" # ostree checkout doesn't care if two symlinks are actually hardlinked # together (which is fine). checking that it's also a symlink is good enough. assert_symlink_has_content usr/local/bin/slhl foo - echo "ok $1 hardlink to symlink" # stat override test -u usr/bin/setuidme - echo "ok $1 setuid" # skip list test ! -f usr/bin/skipme - echo "ok $1 file skip" cd ${test_tmpdir} - rm -rf test-$1-checkout } assert_valid_checkout tar +echo "ok tar contents" assert_valid_checkout cpio +echo "ok cpio contents" cd ${test_tmpdir} mkdir multicommit-files @@ -155,12 +162,59 @@ cd partial-checkout assert_file_has_content subdir/original "original" echo "ok tar partial commit contents" -cd ${test_tmpdir} -tar -cf empty.tar.gz -T /dev/null uid=$(id -u) gid=$(id -g) -$OSTREE commit -b tar-empty --tar-autocreate-parents \ - --owner-uid=${uid} --owner-gid=${gid} --tree=tar=empty.tar.gz +autocreate_args="--tar-autocreate-parents --owner-uid=${uid} --owner-gid=${gid}" + +cd ${test_tmpdir} +tar -cf empty.tar.gz -T /dev/null +$OSTREE commit -b tar-empty ${autocreate_args} --tree=tar=empty.tar.gz $OSTREE ls tar-empty > ls.txt assert_file_has_content ls.txt "d00755 ${uid} ${gid} 0 /" echo "ok tar autocreate with owner uid/gid" + +# noop pathname filter +cd ${test_tmpdir} +$OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter='^nosuchfile/,nootherfile/' \ + --statoverride=statoverride.txt \ + --skip-list=skiplist.txt \ + --tree=tar=foo.tar.gz +rm test-tar-co -rf +$OSTREE checkout test-tar test-tar-co +assert_valid_content ${test_tmpdir}/test-tar-co +echo "ok tar pathname filter prefix (noop)" + +# Add a prefix +cd ${test_tmpdir} +# Update the metadata overrides matching our pathname filter +for f in statoverride.txt skiplist.txt; do + sed -i -e 's,/usr/,/foo/usr/,' $f +done +$OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter='^,foo/' \ + --statoverride=statoverride.txt \ + --skip-list=skiplist.txt \ + --tree=tar=foo.tar.gz +rm test-tar-co -rf +$OSTREE checkout test-tar test-tar-co +assert_has_dir test-tar-co/foo +assert_valid_content ${test_tmpdir}/test-tar-co/foo +echo "ok tar pathname filter prefix" + +# Test anchored and not-anchored +for filter in '^usr/bin/,usr/sbin/' '/bin/,/sbin/'; do + cd ${test_tmpdir} + $OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter=$filter \ + --tree=tar=foo.tar.gz + rm test-tar-co -rf + $OSTREE checkout test-tar test-tar-co + cd test-tar-co + # Check that we just had usr/bin → usr/sbin + assert_not_has_file usr/bin/foo + assert_file_has_content usr/sbin/foo contents + assert_not_has_file usr/sbin/libfoo.so + assert_file_has_content usr/lib/libfoo.so 'a library' + echo "ok tar pathname filter modification: ${filter}" +done From 93d2590c35c6e302c52a4bfce23712a06ed732f2 Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Wed, 30 Aug 2017 12:06:45 -0700 Subject: [PATCH 30/83] tests: Make the deployment mutable in test-sysroot.js We attempt to make deployments mutable in the test suite (as opposed to immutable which is the default) to make it easier to chmod and clean up the tmp files after each test. This is normally accomplished by setting OSTREE_SYSROOT_DEBUG=mutable-deployments in libtest.sh, but that only affects the environment variables for that bash instance, not the process running gjs. So in test-sysroot.js OSTREE_SYSROOT_DEBUG wasn't set when sysroot.deploy_tree() was called, which means the deployment was made immutable which eventually causes the test to fail. This only occurs when the test is run by the root user because for non-root users _ostree_linuxfs_fd_alter_immutable_flag() would silently fail and the deployment would be mutable. This commit fixes this issue by setting the environment variable in tests/test-sysroot.js. Closes: #1122 Approved by: cgwalters --- tests/test-sysroot.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test-sysroot.js b/tests/test-sysroot.js index d7d3dab3..4da55d0f 100755 --- a/tests/test-sysroot.js +++ b/tests/test-sysroot.js @@ -42,6 +42,8 @@ print('1..1') libtestExec('setup_os_repository archive-z2 syslinux'); +GLib.setenv("OSTREE_SYSROOT_DEBUG", "mutable-deployments", true); + let upstreamRepo = OSTree.Repo.new(Gio.File.new_for_path('testos-repo')); upstreamRepo.open(null); From 12114ce3828936ed170adaa71a4c6e948764b127 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Wed, 30 Aug 2017 15:20:31 -0400 Subject: [PATCH 31/83] commit: filter out selinux label before commit The new --selinux-policy added in [0] exposed a subtle issue in the way we handle labeling during commit. The CI system in rpm-ostree hit this when trying to make use of it[1]. Basically, because of the way we use a GVariant to represent xattrs, if a file to be committed already has an SELinux label, the xattr object ends up with *two* label entries. This of course throws off fsck later on, since the checksum will have gone over both entries, even though the on-disk file will only have a single label (in which the second entry wins). I confirmed that the `fsck` added in the installed test fails without the rest of this patch. [0] https://github.com/ostreedev/ostree/pull/1114 [1] https://github.com/projectatomic/rpm-ostree/pull/953 Closes: #1121 Approved by: cgwalters --- src/libostree/ostree-repo-commit.c | 11 +++++++++++ tests/installed/itest-label-selinux.sh | 1 + 2 files changed, 12 insertions(+) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index dd63bf1a..078b289d 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -34,6 +34,7 @@ #include "ostree.h" #include "ostree-core-private.h" #include "ostree-repo-private.h" +#include "ostree-sepolicy-private.h" #include "ostree-repo-file-enumerator.h" #include "ostree-checksum-input-stream.h" #include "ostree-varint.h" @@ -2484,6 +2485,16 @@ get_modified_xattrs (OstreeRepo *self, { g_autoptr(GVariantBuilder) builder = NULL; + if (ret_xattrs) + { + /* drop out any existing SELinux policy from the set, so we don't end up + * counting it twice in the checksum */ + g_autoptr(GVariant) new_ret_xattrs = NULL; + new_ret_xattrs = _ostree_filter_selinux_xattr (ret_xattrs); + g_variant_unref (ret_xattrs); + ret_xattrs = g_steal_pointer (&new_ret_xattrs); + } + /* ret_xattrs may be NULL */ builder = ot_util_variant_builder_from_variant (ret_xattrs, G_VARIANT_TYPE ("a(ayay)")); diff --git a/tests/installed/itest-label-selinux.sh b/tests/installed/itest-label-selinux.sh index 1a2b4aaf..1218a8bc 100755 --- a/tests/installed/itest-label-selinux.sh +++ b/tests/installed/itest-label-selinux.sh @@ -24,6 +24,7 @@ ostree --repo=/ostree/repo commit -b testbranch --link-checkout-speedup \ --selinux-policy co --tree=dir=co ostree --repo=/ostree/repo ls -X testbranch /usr/bin/foo-a-generic-binary > ls.txt assert_file_has_content ls.txt ${oldcon} +ostree --repo=/ostree/repo fsck ostree --repo=/ostree/repo refs --delete testbranch rm co -rf From f07432d4cefcea7fb8c602b9ab78e83236127d8f Mon Sep 17 00:00:00 2001 From: Ruixin Date: Thu, 31 Aug 2017 15:44:35 +0000 Subject: [PATCH 32/83] checkout: add an extra checkout_overwrite mode This is for issue projectatomic/rpm-ostree#365, an extra option of overwrite mode is added to the checkout command so that when there is "non-directory" file already exist during checkout, the error will be handled. Some tests are added for regression Closes: #1116 Approved by: cgwalters --- bash/ostree | 1 + man/ostree-checkout.xml | 8 ++++++++ src/libostree/ostree-repo-checkout.c | 3 ++- src/libostree/ostree-repo.h | 2 ++ src/ostree/ot-builtin-checkout.c | 18 +++++++++++++++++- tests/basic-test.sh | 28 +++++++++++++++++++++++++++- 6 files changed, 57 insertions(+), 3 deletions(-) diff --git a/bash/ostree b/bash/ostree index f12d88b7..4ebe22c3 100644 --- a/bash/ostree +++ b/bash/ostree @@ -696,6 +696,7 @@ _ostree_checkout() { --require-hardlinks -H --union --union-add + --disjoint-union --user-mode -U --whiteouts " diff --git a/man/ostree-checkout.xml b/man/ostree-checkout.xml index c8585878..07d44b34 100644 --- a/man/ostree-checkout.xml +++ b/man/ostree-checkout.xml @@ -97,6 +97,14 @@ Boston, MA 02111-1307, USA. + + + + + When layering checkouts, error out if a file would be replaced, but add new files and directories + + + diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 3deaa297..4fbbee7d 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -654,7 +654,8 @@ checkout_tree_at_recurse (OstreeRepo *self, { if (errno == EEXIST && (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES - || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES)) + || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES + || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES)) did_exist = TRUE; else return glnx_throw_errno (error); diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index ab037020..58b1a1dc 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -832,11 +832,13 @@ typedef enum { * @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories * @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories + * @OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES: When layering checkouts, error out if a file would be replaced, but add new files and directories */ typedef enum { OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1, OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES = 2, /* Since: 2017.3 */ + OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES = 3 /* Since: 2017.11 */ } OstreeRepoCheckoutOverwriteMode; _OSTREE_PUBLIC diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index a31d3685..a3494ae3 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -37,6 +37,7 @@ static gboolean opt_disable_cache; static char *opt_subpath; static gboolean opt_union; static gboolean opt_union_add; +static gboolean opt_disjoint_union; static gboolean opt_whiteouts; static gboolean opt_from_stdin; static char *opt_from_file; @@ -72,6 +73,7 @@ static GOptionEntry options[] = { { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, { "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL }, + { "disjoint-union", 0, 0, G_OPTION_ARG_NONE, &opt_disjoint_union, "When layering checkouts, error out if a file would be replaced, but add new files and directories", NULL }, { "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL }, { "allow-noent", 0, 0, G_OPTION_ARG_NONE, &opt_allow_noent, "Do nothing if specified path does not exist", NULL }, { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL }, @@ -99,7 +101,7 @@ process_one_checkout (OstreeRepo *repo, * convenient infrastructure for testing C APIs with data. */ if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || - opt_union_add || opt_force_copy || opt_bareuseronly_dirs) + opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_disjoint_union) { OstreeRepoCheckoutAtOptions options = { 0, }; @@ -112,6 +114,18 @@ process_one_checkout (OstreeRepo *repo, "Cannot specify both --union and --union-add"); goto out; } + if (opt_union && opt_disjoint_union) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union and --disjoint-union"); + goto out; + } + if (opt_union_add && opt_disjoint_union) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union-add and --disjoint-union "); + goto out; + } if (opt_require_hardlinks && opt_force_copy) { glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy"); @@ -121,6 +135,8 @@ process_one_checkout (OstreeRepo *repo, options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; else if (opt_union_add) options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES; + else if (opt_disjoint_union) + options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES; if (opt_whiteouts) options.process_whiteouts = TRUE; if (subpath) diff --git a/tests/basic-test.sh b/tests/basic-test.sh index de4bd445..6b43ca90 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..$((70 + ${extra_basic_tests:-0}))" +echo "1..$((72 + ${extra_basic_tests:-0}))" $CMD_PREFIX ostree --version > version.yaml python -c 'import yaml; yaml.safe_load(open("version.yaml"))' @@ -469,6 +469,32 @@ assert_file_has_content checkout-test-union-add/union-add-test 'existing file fo assert_file_has_content checkout-test-union-add/union-add-test2 'another file for union add testing' echo "ok checkout union add" +# Create some new files for testing +cd ${test_tmpdir} +mkdir disjoint-union-test +mkdir disjoint-union-test/test_one +chmod a+w disjoint-union-test/test_one +echo 'file for add dirs testing' > disjoint-union-test/test_one/test_file +$OSTREE commit ${COMMIT_ARGS} -b test-disjoint-union --tree=dir=disjoint-union-test +$OSTREE checkout --disjoint-union test-disjoint-union checkout-test-disjoint-union +echo "ok adding new directories and new file" +# Make a new file, and try the checkout again +echo 'second test file' > disjoint-union-test/test_one/test_second_file +$OSTREE commit ${COMMIT_ARGS} -b test-disjoint-union --tree=dir=disjoint-union-test +# Check out the latest commit, should fail due to presence of existing files +if $OSTREE checkout --disjoint-union test-disjoint-union checkout-test-disjoint-union 2> err.txt; then + assert_not_reached "checking out files unexpectedly succeeded!" +fi +assert_file_has_content err.txt 'File exists' +# Verify that Union mode still functions properly +rm checkout-test-disjoint-union/test_one/test_file +echo 'file for testing union mode alongwith disjoint-union mode' > checkout-test-disjoint-union/test_one/test_file +$OSTREE checkout --union test-disjoint-union checkout-test-disjoint-union +assert_has_file checkout-test-disjoint-union/test_one/test_second_file +# This shows the file with same name has been successfully overwriten +assert_file_has_content checkout-test-disjoint-union/test_one/test_file 'file for add dirs testing' +echo "ok checkout disjoint union" + cd ${test_tmpdir} rm files -rf && mkdir files mkdir files/worldwritable-dir From 88b25dc65c5e2392a732c157cf43fa3dfac5e191 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 16:15:33 -0400 Subject: [PATCH 33/83] tree-wide: Replace archive-z2 with archive In almost all places. There are just a few exceptions; one tricky bit for example is that the repo config must still have `mode=archive-z2`, since `archive` used to mean something else. (We could very likely just get rid of that check, but eh, later). I also added a test that one can still do `ostree repo init --mode=archive-z2`. Closes: #1125 Approved by: jlebon --- man/ostree-init.xml | 10 +++++++--- man/ostree-pull.xml | 2 +- man/ostree.repo-config.xml | 2 +- src/libostree/ostree-core.c | 2 +- src/libostree/ostree-repo-pull.c | 2 +- src/libostree/ostree-repo-static-delta-processing.c | 2 +- src/ostree/ot-builtin-commit.c | 2 +- src/ostree/ot-builtin-init.c | 2 +- tests/libostreetest.c | 4 ++-- tests/test-admin-deploy-2.sh | 2 +- tests/test-admin-deploy-bootid-gc.sh | 2 +- tests/test-admin-deploy-clean.sh | 2 +- tests/test-admin-deploy-etcmerge-cornercases.sh | 2 +- tests/test-admin-deploy-grub2.sh | 2 +- tests/test-admin-deploy-karg.sh | 2 +- tests/test-admin-deploy-switch.sh | 2 +- tests/test-admin-deploy-syslinux.sh | 2 +- tests/test-admin-deploy-uboot.sh | 2 +- tests/test-admin-instutil-set-kargs.sh | 2 +- tests/test-admin-locking.sh | 2 +- tests/test-admin-pull-deploy-commit.sh | 2 +- tests/test-admin-pull-deploy-split.sh | 2 +- tests/test-admin-upgrade-endoflife.sh | 2 +- tests/test-admin-upgrade-not-backwards.sh | 2 +- tests/test-admin-upgrade-unconfigured.sh | 2 +- tests/test-archivez.sh | 7 +++++-- tests/test-basic-c.c | 4 ++-- tests/test-commit-sign.sh | 2 +- tests/test-delta.sh | 2 +- tests/test-demo-buildsystem.sh | 2 +- tests/test-export.sh | 2 +- tests/test-gpg-signed-commit.sh | 2 +- tests/test-local-pull-depth.sh | 4 ++-- tests/test-local-pull.sh | 12 ++++++------ tests/test-oldstyle-partial.sh | 2 +- tests/test-parent.sh | 2 +- tests/test-prune.sh | 2 +- tests/test-pull-commit-only.sh | 2 +- tests/test-pull-contenturl.sh | 2 +- tests/test-pull-corruption.sh | 2 +- tests/test-pull-depth.sh | 2 +- tests/test-pull-large-metadata.sh | 2 +- tests/test-pull-metalink.sh | 2 +- tests/test-pull-mirror-summary.sh | 12 ++++++------ tests/test-pull-mirrorlist.sh | 2 +- tests/test-pull-override-url.sh | 4 ++-- tests/test-pull-repeated.sh | 4 ++-- tests/test-pull-resume.sh | 2 +- tests/test-pull-subpath.sh | 2 +- tests/test-pull-summary-sigs.sh | 6 +++--- tests/test-refs.sh | 2 +- tests/test-remote-cookies.sh | 2 +- tests/test-remote-gpg-import.sh | 2 +- tests/test-reset-nonlinear.sh | 2 +- tests/test-summary-view.sh | 4 ++-- tests/test-sysroot.js | 2 +- tests/test-xattrs.sh | 2 +- 57 files changed, 85 insertions(+), 78 deletions(-) diff --git a/man/ostree-init.xml b/man/ostree-init.xml index fb35c0da..2ec1b67a 100644 --- a/man/ostree-init.xml +++ b/man/ostree-init.xml @@ -67,9 +67,13 @@ Boston, MA 02111-1307, USA. ="MODE" - - Initialize repository in given mode (bare, bare-user, archive-z2). Default is "bare". - + Initialize repository in given mode + (bare, bare-user, + archive). The default is + bare. Note that for + archive the repository configuration file + will actually have archive-z2, as that's the + historical name. diff --git a/man/ostree-pull.xml b/man/ostree-pull.xml index 9c970714..a3d0b7a0 100644 --- a/man/ostree-pull.xml +++ b/man/ostree-pull.xml @@ -157,7 +157,7 @@ Boston, MA 02111-1307, USA. Perform a complete mirror of the remote. (This is likely most useful if your repository is also - archive-z2 mode) + archive mode) $ ostree --repo=repo pull remote_name exampleos/x86_64/standard diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index cf0bf7c0..8ae6ad42 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -76,7 +76,7 @@ Boston, MA 02111-1307, USA. mode - One of bare, bare-user or archive-z2. + One of bare, bare-user or archive-z2 (note that archive is used everywhere else.) diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index 4118cf7e..7d34278a 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -312,7 +312,7 @@ _ostree_file_header_new (GFileInfo *file_info, * @file_info: a #GFileInfo * @xattrs: (allow-none): Optional extended attribute array * - * Returns: (transfer full): A new #GVariant containing file header for an archive-z2 repository + * Returns: (transfer full): A new #GVariant containing file header for an archive repository */ GVariant * _ostree_zlib_file_header_new (GFileInfo *file_info, diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 0bb1bc04..98fb96b4 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -3631,7 +3631,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, } - /* We can't use static deltas if pulling into an archive-z2 repo. */ + /* We can't use static deltas if pulling into an archive repo. */ if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2) { if (pull_data->require_static_deltas) diff --git a/src/libostree/ostree-repo-static-delta-processing.c b/src/libostree/ostree-repo-static-delta-processing.c index 6b1dc337..2e75ea28 100644 --- a/src/libostree/ostree-repo-static-delta-processing.c +++ b/src/libostree/ostree-repo-static-delta-processing.c @@ -608,7 +608,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo, } else { - /* Slower path, for symlinks and unpacking deltas into archive-z2 */ + /* Slower path, for symlinks and unpacking deltas into archive */ g_autoptr(GFileInfo) finfo = _ostree_mode_uidgid_to_gfileinfo (state->mode, state->uid, state->gid); diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index f07b95e2..3b9e3630 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -780,7 +780,7 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError if (!ostree_repo_commit_transaction (repo, &stats, cancellable, error)) goto out; - /* The default for this option is FALSE, even for archive-z2 repos, + /* The default for this option is FALSE, even for archive repos, * because ostree supports multiple processes committing to the same * repo (but different refs) concurrently, and in fact gnome-continuous * actually does this. In that context it's best to update the summary diff --git a/src/ostree/ot-builtin-init.c b/src/ostree/ot-builtin-init.c index 28f96829..c77f6972 100644 --- a/src/ostree/ot-builtin-init.c +++ b/src/ostree/ot-builtin-init.c @@ -37,7 +37,7 @@ static char *opt_collection_id = NULL; */ static GOptionEntry options[] = { - { "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, archive-z2)", NULL }, + { "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, archive)", NULL }, #ifdef OSTREE_ENABLE_EXPERIMENTAL_API { "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id, "Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" }, diff --git a/tests/libostreetest.c b/tests/libostreetest.c index 2fb83f51..bc4c49f6 100644 --- a/tests/libostreetest.c +++ b/tests/libostreetest.c @@ -70,7 +70,7 @@ ot_test_setup_repo (GCancellable *cancellable, g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); glnx_unref_object OstreeRepo* ret_repo = NULL; - if (!ot_test_run_libtest ("setup_test_repository archive-z2", error)) + if (!ot_test_run_libtest ("setup_test_repository archive", error)) goto out; ret_repo = ostree_repo_new (repo_path); @@ -94,7 +94,7 @@ ot_test_setup_sysroot (GCancellable *cancellable, glnx_unref_object OstreeSysroot *ret_sysroot = NULL; struct statfs stbuf; - if (!ot_test_run_libtest ("setup_os_repository \"archive-z2\" \"syslinux\"", error)) + if (!ot_test_run_libtest ("setup_os_repository \"archive\" \"syslinux\"", error)) goto out; { g_autoptr(GString) buf = g_string_new ("mutable-deployments"); diff --git a/tests/test-admin-deploy-2.sh b/tests/test-admin-deploy-2.sh index 79e253bb..3e00c670 100755 --- a/tests/test-admin-deploy-2.sh +++ b/tests/test-admin-deploy-2.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..3" diff --git a/tests/test-admin-deploy-bootid-gc.sh b/tests/test-admin-deploy-bootid-gc.sh index 29360e38..d96438c1 100755 --- a/tests/test-admin-deploy-bootid-gc.sh +++ b/tests/test-admin-deploy-bootid-gc.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..1" diff --git a/tests/test-admin-deploy-clean.sh b/tests/test-admin-deploy-clean.sh index 58283108..4dc19f41 100755 --- a/tests/test-admin-deploy-clean.sh +++ b/tests/test-admin-deploy-clean.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..1" diff --git a/tests/test-admin-deploy-etcmerge-cornercases.sh b/tests/test-admin-deploy-etcmerge-cornercases.sh index 10e7a438..8da6d16c 100755 --- a/tests/test-admin-deploy-etcmerge-cornercases.sh +++ b/tests/test-admin-deploy-etcmerge-cornercases.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..2" diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh index 60c7d05f..c91ba8a5 100755 --- a/tests/test-admin-deploy-grub2.sh +++ b/tests/test-admin-deploy-grub2.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "grub2 ostree-grub-generator" +setup_os_repository "archive" "grub2 ostree-grub-generator" extra_admin_tests=0 diff --git a/tests/test-admin-deploy-karg.sh b/tests/test-admin-deploy-karg.sh index 643aef78..bbd7af33 100755 --- a/tests/test-admin-deploy-karg.sh +++ b/tests/test-admin-deploy-karg.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..3" diff --git a/tests/test-admin-deploy-switch.sh b/tests/test-admin-deploy-switch.sh index 0157e27b..6c27649f 100755 --- a/tests/test-admin-deploy-switch.sh +++ b/tests/test-admin-deploy-switch.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..4" diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index 08f26b5e..7c1535b6 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" extra_admin_tests=3 diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index 55059b34..f04af4ab 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -23,7 +23,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "uboot" +setup_os_repository "archive" "uboot" extra_admin_tests=1 diff --git a/tests/test-admin-instutil-set-kargs.sh b/tests/test-admin-instutil-set-kargs.sh index 132c9336..fb08c24b 100755 --- a/tests/test-admin-instutil-set-kargs.sh +++ b/tests/test-admin-instutil-set-kargs.sh @@ -23,7 +23,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..5" diff --git a/tests/test-admin-locking.sh b/tests/test-admin-locking.sh index 01814f9f..3466ce99 100755 --- a/tests/test-admin-locking.sh +++ b/tests/test-admin-locking.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" # If parallel is not installed, skip the test if ! parallel --gnu /bin/true /dev/null 2>&1; then diff --git a/tests/test-admin-pull-deploy-commit.sh b/tests/test-admin-pull-deploy-commit.sh index e1f7def6..f128fd0b 100755 --- a/tests/test-admin-pull-deploy-commit.sh +++ b/tests/test-admin-pull-deploy-commit.sh @@ -25,7 +25,7 @@ set -euo pipefail echo "1..1" -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo diff --git a/tests/test-admin-pull-deploy-split.sh b/tests/test-admin-pull-deploy-split.sh index 7a6750e2..fa10b784 100755 --- a/tests/test-admin-pull-deploy-split.sh +++ b/tests/test-admin-pull-deploy-split.sh @@ -25,7 +25,7 @@ set -euo pipefail echo "1..1" -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo diff --git a/tests/test-admin-upgrade-endoflife.sh b/tests/test-admin-upgrade-endoflife.sh index a58c64ce..c5a05da6 100755 --- a/tests/test-admin-upgrade-endoflife.sh +++ b/tests/test-admin-upgrade-endoflife.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" # This does: # - init ostree repo in testos-repo # - create system files in osdata and commit twice those contents into testos-repo diff --git a/tests/test-admin-upgrade-not-backwards.sh b/tests/test-admin-upgrade-not-backwards.sh index 491b8bbc..10fd25c9 100755 --- a/tests/test-admin-upgrade-not-backwards.sh +++ b/tests/test-admin-upgrade-not-backwards.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..2" diff --git a/tests/test-admin-upgrade-unconfigured.sh b/tests/test-admin-upgrade-unconfigured.sh index c952356e..63885642 100755 --- a/tests/test-admin-upgrade-unconfigured.sh +++ b/tests/test-admin-upgrade-unconfigured.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..2" diff --git a/tests/test-archivez.sh b/tests/test-archivez.sh index 836e9180..d6faab6c 100755 --- a/tests/test-archivez.sh +++ b/tests/test-archivez.sh @@ -21,12 +21,15 @@ set -euo pipefail . $(dirname $0)/libtest.sh -echo '1..11' +echo '1..12' -setup_test_repository "archive-z2" +setup_test_repository "archive" . ${test_srcdir}/archive-test.sh +${CMD_PREFIX} ostree --repo=repo-archive-z2 init --mode=archive-z2 +echo "ok did an init with archive-z2 alias" + cd ${test_tmpdir} mkdir repo2 ostree_repo_init repo2 diff --git a/tests/test-basic-c.c b/tests/test-basic-c.c index dc6d33f2..d8800763 100644 --- a/tests/test-basic-c.c +++ b/tests/test-basic-c.c @@ -55,7 +55,7 @@ input_stream_to_bytes (GInputStream *input) } static void -test_raw_file_to_archive_z2_stream (gconstpointer data) +test_raw_file_to_archive_stream (gconstpointer data) { OstreeRepo *repo = OSTREE_REPO (data); g_autofree gchar *commit_checksum = NULL; @@ -249,7 +249,7 @@ int main (int argc, char **argv) goto out; g_test_add_data_func ("/repo-not-system", repo, test_repo_is_not_system); - g_test_add_data_func ("/raw-file-to-archive-z2-stream", repo, test_raw_file_to_archive_z2_stream); + g_test_add_data_func ("/raw-file-to-archive-stream", repo, test_raw_file_to_archive_stream); g_test_add_data_func ("/objectwrites", repo, test_object_writes); g_test_add_func ("/remotename", test_validate_remotename); diff --git a/tests/test-commit-sign.sh b/tests/test-commit-sign.sh index 96608e88..755818c8 100755 --- a/tests/test-commit-sign.sh +++ b/tests/test-commit-sign.sh @@ -33,7 +33,7 @@ oldpwd=`pwd` mkdir ostree-srv cd ostree-srv mkdir gnomerepo -ostree_repo_init gnomerepo --mode="archive-z2" +ostree_repo_init gnomerepo --mode="archive" mkdir gnomerepo-files cd gnomerepo-files echo first > firstfile diff --git a/tests/test-delta.sh b/tests/test-delta.sh index a59ee8e5..97d94391 100755 --- a/tests/test-delta.sh +++ b/tests/test-delta.sh @@ -29,7 +29,7 @@ morebindatafiles="false ls" echo '1..12' mkdir repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive mkdir files for bin in ${bindatafiles}; do diff --git a/tests/test-demo-buildsystem.sh b/tests/test-demo-buildsystem.sh index 99ddc505..4b2d86f1 100755 --- a/tests/test-demo-buildsystem.sh +++ b/tests/test-demo-buildsystem.sh @@ -68,7 +68,7 @@ packages="bash systemd" mkdir build-repo ostree_repo_init build-repo --mode=bare-user mkdir repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive # Our FUSE mount point mkdir mnt diff --git a/tests/test-export.sh b/tests/test-export.sh index 856c4073..7cba3bd7 100755 --- a/tests/test-export.sh +++ b/tests/test-export.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_test_repository "archive-z2" +setup_test_repository "archive" echo '1..5' diff --git a/tests/test-gpg-signed-commit.sh b/tests/test-gpg-signed-commit.sh index ad022b2b..69f0cb20 100755 --- a/tests/test-gpg-signed-commit.sh +++ b/tests/test-gpg-signed-commit.sh @@ -29,7 +29,7 @@ fi echo "1..1" -setup_test_repository "archive-z2" +setup_test_repository "archive" export OSTREE_GPG_SIGN="${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME}" diff --git a/tests/test-local-pull-depth.sh b/tests/test-local-pull-depth.sh index fef2f2dc..2dfb735d 100755 --- a/tests/test-local-pull-depth.sh +++ b/tests/test-local-pull-depth.sh @@ -21,13 +21,13 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_test_repository "archive-z2" +setup_test_repository "archive" echo "1..1" cd ${test_tmpdir} mkdir repo2 -ostree_repo_init repo2 --mode="archive-z2" +ostree_repo_init repo2 --mode="archive" ${CMD_PREFIX} ostree --repo=repo2 pull-local repo find repo2/objects -name '*.commit' | wc -l > commitcount diff --git a/tests/test-local-pull.sh b/tests/test-local-pull.sh index 1c9767f6..f9ac63b6 100755 --- a/tests/test-local-pull.sh +++ b/tests/test-local-pull.sh @@ -28,7 +28,7 @@ skip_without_user_xattrs echo "1..8" -setup_test_repository "archive-z2" +setup_test_repository "archive" echo "ok setup" cd ${test_tmpdir} @@ -40,7 +40,7 @@ ${CMD_PREFIX} ostree --repo=repo2 fsck echo "ok pull-local z2 to bare-user" mkdir repo3 -ostree_repo_init repo3 --mode="archive-z2" +ostree_repo_init repo3 --mode="archive" ${CMD_PREFIX} ostree --repo=repo3 pull-local repo2 ${CMD_PREFIX} ostree --repo=repo3 fsck echo "ok pull-local bare-user to z2" @@ -62,7 +62,7 @@ cmp checkout1.files checkout3.files echo "ok checkouts same" mkdir repo4 -ostree_repo_init repo4 --mode="archive-z2" +ostree_repo_init repo4 --mode="archive" ${CMD_PREFIX} ostree --repo=repo4 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo if ${CMD_PREFIX} ostree --repo=repo4 pull-local --remote=origin --gpg-verify repo test2 2>&1; then assert_not_reached "GPG verification unexpectedly succeeded" @@ -72,13 +72,13 @@ echo "ok --gpg-verify with no signature" ${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME} test2 ${TEST_GPG_KEYID_1} mkdir repo5 -ostree_repo_init repo5 --mode="archive-z2" +ostree_repo_init repo5 --mode="archive" ${CMD_PREFIX} ostree --repo=repo5 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo ${CMD_PREFIX} ostree --repo=repo5 pull-local --remote=origin --gpg-verify repo test2 echo "ok --gpg-verify" mkdir repo6 -ostree_repo_init repo6 --mode="archive-z2" +ostree_repo_init repo6 --mode="archive" ${CMD_PREFIX} ostree --repo=repo6 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then assert_not_reached "GPG summary verification with no summary unexpectedly succeeded" @@ -97,7 +97,7 @@ ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summar echo "ok --gpg-verify-summary" mkdir repo7 -ostree_repo_init repo7 --mode="archive-z2" +ostree_repo_init repo7 --mode="archive" ${CMD_PREFIX} ostree --repo=repo7 pull-local repo ${CMD_PREFIX} ostree --repo=repo7 fsck for src_object in `find repo/objects -name '*.filez'`; do diff --git a/tests/test-oldstyle-partial.sh b/tests/test-oldstyle-partial.sh index 08be69d3..35344c39 100755 --- a/tests/test-oldstyle-partial.sh +++ b/tests/test-oldstyle-partial.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-parent.sh b/tests/test-parent.sh index 4d5520dd..9abdcf2d 100755 --- a/tests/test-parent.sh +++ b/tests/test-parent.sh @@ -25,7 +25,7 @@ skip_without_user_xattrs echo '1..2' -setup_test_repository "archive-z2" +setup_test_repository "archive" export OSTREE_GPG_SIGN="${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME}" diff --git a/tests/test-prune.sh b/tests/test-prune.sh index 0781b543..afcfbb52 100755 --- a/tests/test-prune.sh +++ b/tests/test-prune.sh @@ -23,7 +23,7 @@ set -euo pipefail skip_without_user_xattrs -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..5' diff --git a/tests/test-pull-commit-only.sh b/tests/test-pull-commit-only.sh index 0cbdebc8..ff71d487 100755 --- a/tests/test-pull-commit-only.sh +++ b/tests/test-pull-commit-only.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-pull-contenturl.sh b/tests/test-pull-contenturl.sh index 5d72fb23..8f703923 100755 --- a/tests/test-pull-contenturl.sh +++ b/tests/test-pull-contenturl.sh @@ -28,7 +28,7 @@ if has_gpgme; then COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" fi -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # create a summary ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo \ diff --git a/tests/test-pull-corruption.sh b/tests/test-pull-corruption.sh index 89d89b75..9dc7d62b 100755 --- a/tests/test-pull-corruption.sh +++ b/tests/test-pull-corruption.sh @@ -27,7 +27,7 @@ fi . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..2' diff --git a/tests/test-pull-depth.sh b/tests/test-pull-depth.sh index 372bef49..2e82c3a9 100755 --- a/tests/test-pull-depth.sh +++ b/tests/test-pull-depth.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-pull-large-metadata.sh b/tests/test-pull-large-metadata.sh index 2fdf0d91..219c519e 100755 --- a/tests/test-pull-large-metadata.sh +++ b/tests/test-pull-large-metadata.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-pull-metalink.sh b/tests/test-pull-metalink.sh index 171c8d4b..7dbc4bf0 100755 --- a/tests/test-pull-metalink.sh +++ b/tests/test-pull-metalink.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..9' diff --git a/tests/test-pull-mirror-summary.sh b/tests/test-pull-mirror-summary.sh index 883c0245..71f917fc 100755 --- a/tests/test-pull-mirror-summary.sh +++ b/tests/test-pull-mirror-summary.sh @@ -24,7 +24,7 @@ set -euo pipefail echo "1..5" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # Now, setup multiple branches mkdir ${test_tmpdir}/ostree-srv/other-files @@ -41,7 +41,7 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u prev_dir=`pwd` cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull --mirror origin assert_has_file repo/summary @@ -69,13 +69,13 @@ cd $prev_dir cd ${test_tmpdir} rm -rf repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo echo "ok pull mirror without checking signed summary" cd ${test_tmpdir} rm -rf repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo if ${OSTREE} --repo=repo pull --mirror origin 2>err.txt; then assert_not_reached "Mirroring unexpectedly succeeded" @@ -86,7 +86,7 @@ ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} cd ${test_tmpdir} rm -rf repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo ${OSTREE} --repo=repo pull --mirror origin assert_has_file repo/summary @@ -99,7 +99,7 @@ truncate --size=1 ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig cd ${test_tmpdir} rm -rf repo mkdir repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo ${OSTREE} --repo=repo pull --mirror origin assert_has_file repo/summary diff --git a/tests/test-pull-mirrorlist.sh b/tests/test-pull-mirrorlist.sh index 35320506..22d3950b 100755 --- a/tests/test-pull-mirrorlist.sh +++ b/tests/test-pull-mirrorlist.sh @@ -23,7 +23,7 @@ set -euo pipefail echo "1..3" -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" setup_mirror () { name=$1; shift diff --git a/tests/test-pull-override-url.sh b/tests/test-pull-override-url.sh index 16f79a02..6b72440f 100755 --- a/tests/test-pull-override-url.sh +++ b/tests/test-pull-override-url.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' @@ -34,7 +34,7 @@ gnomerepo_url="$(cat httpd-address)/ostree/gnomerepo" mkdir mirror-srv cd mirror-srv mkdir gnomerepo -ostree_repo_init gnomerepo --mode "archive-z2" +ostree_repo_init gnomerepo --mode "archive" ${CMD_PREFIX} ostree --repo=gnomerepo remote add --set=gpg-verify=false origin ${gnomerepo_url} ${CMD_PREFIX} ostree --repo=gnomerepo pull --mirror --depth=-1 origin main diff --git a/tests/test-pull-repeated.sh b/tests/test-pull-repeated.sh index 108c2057..30d0e03b 100755 --- a/tests/test-pull-repeated.sh +++ b/tests/test-pull-repeated.sh @@ -24,10 +24,10 @@ set -euo pipefail echo "1..1" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" --random-500s=50 +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" --random-500s=50 cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo for x in $(seq 200); do if ${CMD_PREFIX} ostree --repo=repo pull --mirror origin main 2>err.txt; then diff --git a/tests/test-pull-resume.sh b/tests/test-pull-resume.sh index 51746b9c..c6d268f4 100755 --- a/tests/test-pull-resume.sh +++ b/tests/test-pull-resume.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" "" "--force-range-requests" +setup_fake_remote_repo1 "archive" "" "--force-range-requests" echo '1..1' diff --git a/tests/test-pull-subpath.sh b/tests/test-pull-subpath.sh index 27eb64be..eb103004 100755 --- a/tests/test-pull-subpath.sh +++ b/tests/test-pull-subpath.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..4' diff --git a/tests/test-pull-summary-sigs.sh b/tests/test-pull-summary-sigs.sh index 016ee4b9..b6b17500 100755 --- a/tests/test-pull-summary-sigs.sh +++ b/tests/test-pull-summary-sigs.sh @@ -24,7 +24,7 @@ set -euo pipefail echo "1..7" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # Now, setup multiple branches mkdir ${test_tmpdir}/ostree-srv/other-files @@ -41,7 +41,7 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u prev_dir=`pwd` cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull --mirror origin assert_has_file repo/summary @@ -66,7 +66,7 @@ repo_reinit () { cd ${test_tmpdir} rm -rf repo mkdir repo - ostree_repo_init repo --mode=archive-z2 + ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo } diff --git a/tests/test-refs.sh b/tests/test-refs.sh index e48784aa..da45605c 100755 --- a/tests/test-refs.sh +++ b/tests/test-refs.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..2' diff --git a/tests/test-remote-cookies.sh b/tests/test-remote-cookies.sh index 14e3dd12..352bd7f6 100755 --- a/tests/test-remote-cookies.sh +++ b/tests/test-remote-cookies.sh @@ -24,7 +24,7 @@ echo '1..4' . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" "" \ +setup_fake_remote_repo1 "archive" "" \ "--expected-cookies foo=bar --expected-cookies baz=badger" assert_fail (){ diff --git a/tests/test-remote-gpg-import.sh b/tests/test-remote-gpg-import.sh index a5803785..7f5423a6 100755 --- a/tests/test-remote-gpg-import.sh +++ b/tests/test-remote-gpg-import.sh @@ -24,7 +24,7 @@ set -euo pipefail # We don't want OSTREE_GPG_HOME used for these tests. unset OSTREE_GPG_HOME -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo "1..4" diff --git a/tests/test-reset-nonlinear.sh b/tests/test-reset-nonlinear.sh index 735f1523..65e7505e 100755 --- a/tests/test-reset-nonlinear.sh +++ b/tests/test-reset-nonlinear.sh @@ -23,7 +23,7 @@ echo "1..1" . $(dirname $0)/libtest.sh -setup_test_repository "archive-z2" +setup_test_repository "archive" cd ${test_tmpdir}/files $OSTREE commit -b testx -s "Another Commit" cd ${test_tmpdir} diff --git a/tests/test-summary-view.sh b/tests/test-summary-view.sh index 60855eb1..52ac8926 100755 --- a/tests/test-summary-view.sh +++ b/tests/test-summary-view.sh @@ -27,7 +27,7 @@ set -euo pipefail echo "1..2" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # Set up a second branch. mkdir ${test_tmpdir}/ostree-srv/other-files @@ -41,7 +41,7 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u # Check out the repository. prev_dir=`pwd` cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull --mirror origin diff --git a/tests/test-sysroot.js b/tests/test-sysroot.js index 4da55d0f..40397fe9 100755 --- a/tests/test-sysroot.js +++ b/tests/test-sysroot.js @@ -40,7 +40,7 @@ function libtestExec(shellCode) { print('1..1') -libtestExec('setup_os_repository archive-z2 syslinux'); +libtestExec('setup_os_repository archive syslinux'); GLib.setenv("OSTREE_SYSROOT_DEBUG", "mutable-deployments", true); diff --git a/tests/test-xattrs.sh b/tests/test-xattrs.sh index ae7ae39f..5ec0cba8 100755 --- a/tests/test-xattrs.sh +++ b/tests/test-xattrs.sh @@ -28,7 +28,7 @@ skip_without_user_xattrs echo "1..2" -setup_test_repository "archive-z2" +setup_test_repository "archive" cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo checkout test2 test2-checkout1 From 75f24b3d86ebcad4e34632275210d19988982411 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 15:24:44 -0400 Subject: [PATCH 34/83] bin/prune: Port to new style No functional changes, all straightforward. Prep for https://github.com/ostreedev/ostree/issues/1115 Closes: #1124 Approved by: jlebon --- src/ostree/ot-builtin-prune.c | 121 ++++++++++------------------------ 1 file changed, 36 insertions(+), 85 deletions(-) diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c index fd00e5fd..2f66334e 100644 --- a/src/ostree/ot-builtin-prune.c +++ b/src/ostree/ot-builtin-prune.c @@ -59,25 +59,15 @@ delete_commit (OstreeRepo *repo, const char *commit_to_delete, GCancellable *can #ifdef OSTREE_ENABLE_EXPERIMENTAL_API g_autoptr(GHashTable) collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ - GHashTableIter hashiter; - gpointer hashkey, hashvalue; - gboolean ret = FALSE; /* Check refs which are not in a collection. */ if (!ostree_repo_list_refs (repo, NULL, &refs, cancellable, error)) - goto out; + return FALSE; - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH_KV(refs, const char *, ref, const char *, commit) { - const char *ref = hashkey; - const char *commit = hashvalue; if (g_strcmp0 (commit_to_delete, commit) == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Commit '%s' is referenced by '%s'", commit_to_delete, ref); - goto out; - } + return glnx_throw (error, "Commit '%s' is referenced by '%s'", commit_to_delete, ref); } #ifdef OSTREE_ENABLE_EXPERIMENTAL_API @@ -85,33 +75,24 @@ delete_commit (OstreeRepo *repo, const char *commit_to_delete, GCancellable *can if (!ostree_repo_list_collection_refs (repo, NULL, &collection_refs, OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) - goto out; + return FALSE; - g_hash_table_iter_init (&hashiter, collection_refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH_KV (collection_refs, const OstreeCollectionRef*, ref, + const char *, commit) { - const OstreeCollectionRef *ref = hashkey; - const char *commit = hashvalue; if (g_strcmp0 (commit_to_delete, commit) == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Commit '%s' is referenced by (%s, %s)", - commit_to_delete, ref->collection_id, ref->ref_name); - goto out; - } + return glnx_throw (error, "Commit '%s' is referenced by (%s, %s)", + commit_to_delete, ref->collection_id, ref->ref_name); } #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ if (!ot_enable_tombstone_commits (repo, error)) - goto out; + return FALSE; if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, commit_to_delete, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - - out: - return ret; + return TRUE; } static gboolean @@ -121,7 +102,6 @@ traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, GCancellable *cancellable, GError **error) { g_autofree char *next_checksum = g_strdup (checksum); - g_autoptr(GVariant) commit = NULL; /* This is the first commit in our loop, which has a ref pointing to it. We * don't want to auto-prune it. @@ -132,16 +112,14 @@ traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, while (TRUE) { - guint64 commit_timestamp; - + g_autoptr(GVariant) commit = NULL; if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_COMMIT, next_checksum, &commit, error)) return FALSE; - if (!commit) break; /* This commit was pruned, so we're done */ - commit_timestamp = ostree_commit_get_timestamp (commit); + guint64 commit_timestamp = ostree_commit_get_timestamp (commit); /* Is this commit newer than our --keep-younger-than spec? */ if (commit_timestamp >= ts->tv_sec) { @@ -167,22 +145,13 @@ traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, gboolean ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GOptionContext) context = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("- Search for unreachable objects"); g_autoptr(OstreeRepo) repo = NULL; - g_autofree char *formatted_freed_size = NULL; - OstreeRepoPruneFlags pruneflags = 0; - gint n_objects_total; - gint n_objects_pruned; - guint64 objsize_total; - - context = g_option_context_new ("- Search for unreachable objects"); - if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) - goto out; + return FALSE; if (!opt_no_prune && !ostree_ensure_repo_writable (repo, error)) - goto out; + return FALSE; /* Special handling for explicit commit deletion here - we do this * first. @@ -192,17 +161,18 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * if (opt_no_prune) { ot_util_usage_error (context, "Cannot specify both --delete-commit and --no-prune", error); - goto out; + return FALSE; } if (opt_static_deltas_only) { if(!ostree_repo_prune_static_deltas (repo, opt_delete_commit, cancellable, error)) - goto out; + return FALSE; } else if (!delete_commit (repo, opt_delete_commit, cancellable, error)) - goto out; + return FALSE; } + OstreeRepoPruneFlags pruneflags = 0; if (opt_refs_only) pruneflags |= OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY; if (opt_no_prune) @@ -212,12 +182,15 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * * prune API - both to avoid code duplication, and to keep it run from the * test suite. */ + gint n_objects_total; + gint n_objects_pruned; + guint64 objsize_total; if (!(opt_retain_branch_depth || opt_keep_younger_than)) { if (!ostree_repo_prune (repo, pruneflags, opt_depth, &n_objects_total, &n_objects_pruned, &objsize_total, cancellable, error)) - goto out; + return FALSE; } else { @@ -234,11 +207,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * if (opt_keep_younger_than) { if (!parse_datetime (&keep_younger_than_ts, opt_keep_younger_than, NULL)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Could not parse '%s'", opt_keep_younger_than); - goto out; - } + return glnx_throw (error, "Could not parse '%s'", opt_keep_younger_than); } for (char **iter = opt_retain_branch_depth; iter && *iter; iter++) @@ -246,34 +215,19 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * /* bd should look like BRANCH=DEPTH where DEPTH is an int */ const char *bd = *iter; const char *eq = strchr (bd, '='); - const char *depthstr; - gint64 depth; - char *endptr; - if (!eq) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid value %s, must specify BRANCH=DEPTH", - bd); - goto out; - } - depthstr = eq + 1; + return glnx_throw (error, "Invalid value %s, must specify BRANCH=DEPTH", bd); + + const char *depthstr = eq + 1; errno = EPERM; - depth = g_ascii_strtoll (depthstr, &endptr, 10); + char *endptr; + gint64 depth = g_ascii_strtoll (depthstr, &endptr, 10); if (depth == 0) { if (errno == EINVAL) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Out of range depth %s", depthstr); - goto out; - } + return glnx_throw (error, "Out of range depth %s", depthstr); else if (endptr == depthstr) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid depth %s", depthstr); - goto out; - } + return glnx_throw (error, "Invalid depth %s", depthstr); } g_hash_table_insert (retain_branch_depth, g_strndup (bd, eq - bd), GINT_TO_POINTER ((int)depth)); @@ -304,7 +258,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * &keep_younger_than_ts, reachable, cancellable, error)) - goto out; + return FALSE; /* Okay, we handled the younger-than case; the other * two fall through to plain depth-based handling below. @@ -327,12 +281,11 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * &n_objects_pruned, &objsize_total, cancellable, error)) - goto out; + return FALSE; } } - formatted_freed_size = g_format_size_full (objsize_total, 0); - + g_autofree char *formatted_freed_size = g_format_size_full (objsize_total, 0); g_print ("Total objects: %u\n", n_objects_total); if (n_objects_pruned == 0) g_print ("No unreachable objects\n"); @@ -343,7 +296,5 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * g_print ("Deleted %u objects, %s freed\n", n_objects_pruned, formatted_freed_size); - ret = TRUE; - out: - return ret; + return TRUE; } From b71fdbcb5c4a6f1ca7ac1a0054ed1ecdd0ad9e78 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 14:41:07 -0400 Subject: [PATCH 35/83] bin/admin: Port switch,upgrade to new style Was pretty easy. Prep for future work. Closes: #1123 Approved by: jlebon --- src/ostree/ot-admin-builtin-switch.c | 88 +++++++++++---------------- src/ostree/ot-admin-builtin-upgrade.c | 44 ++++++-------- 2 files changed, 54 insertions(+), 78 deletions(-) diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c index f85e39e1..3b54ea85 100644 --- a/src/ostree/ot-admin-builtin-switch.c +++ b/src/ostree/ot-admin-builtin-switch.c @@ -47,54 +47,41 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GOptionContext) context = NULL; + g_autoptr(GOptionContext) context = + g_option_context_new ("REF - Construct new tree from REF and deploy it"); g_autoptr(OstreeSysroot) sysroot = NULL; - const char *new_provided_refspec = NULL; - g_autoptr(OstreeRepo) repo = NULL; - g_autofree char *origin_refspec = NULL; - g_autofree char *origin_remote = NULL; - g_autofree char *origin_ref = NULL; - g_autofree char *new_remote = NULL; - g_autofree char *new_ref = NULL; - g_autofree char *new_refspec = NULL; - const char* remote; - g_autoptr(OstreeSysrootUpgrader) upgrader = NULL; - g_autoptr(OstreeAsyncProgress) progress = NULL; - gboolean changed; - GKeyFile *old_origin; - g_autoptr(GKeyFile) new_origin = NULL; - - context = g_option_context_new ("REF - Construct new tree from REF and deploy it"); - if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (argc < 2) { ot_util_usage_error (context, "REF must be specified", error); - goto out; + return FALSE; } - new_provided_refspec = argv[1]; + const char *new_provided_refspec = argv[1]; if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; + return FALSE; - upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname, - OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, - cancellable, error); + g_autoptr(OstreeSysrootUpgrader) upgrader = + ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname, + OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, + cancellable, error); if (!upgrader) - goto out; + return FALSE; - old_origin = ostree_sysroot_upgrader_get_origin (upgrader); - origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); - + GKeyFile *old_origin = ostree_sysroot_upgrader_get_origin (upgrader); + g_autofree char *origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error)) - goto out; + return FALSE; + g_autofree char *new_remote = NULL; + g_autofree char *new_ref = NULL; /* Allow just switching remotes */ if (g_str_has_suffix (new_provided_refspec, ":")) { @@ -105,14 +92,11 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro else { if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error)) - goto out; + return FALSE; } - if (!new_remote) - remote = origin_remote; - else - remote = new_remote; - + const char* remote = new_remote ?: origin_remote; + g_autofree char *new_refspec = NULL; if (remote) new_refspec = g_strconcat (remote, ":", new_ref, NULL); else @@ -122,54 +106,52 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Old and new refs are equal: %s", new_refspec); - goto out; + return FALSE; } - new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); + g_autoptr(GKeyFile) new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error)) - goto out; + return FALSE; { g_auto(GLnxConsoleRef) console = { 0, }; glnx_console_lock (&console); + g_autoptr(OstreeAsyncProgress) progress = NULL; if (console.is_tty) progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); /* Always allow older...there's not going to be a chronological * relationship necessarily. */ + gboolean changed; if (!ostree_sysroot_upgrader_pull (upgrader, 0, OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER, progress, &changed, cancellable, error)) - goto out; + return FALSE; if (progress) ostree_async_progress_finish (progress); } if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) - goto out; - - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) - goto out; + return FALSE; + OstreeRepo *repo = ostree_sysroot_repo (sysroot); if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) - goto out; + return FALSE; g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref); ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL); - + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) - goto out; - + return FALSE; + if (opt_reboot) { if (!ot_admin_execve_reboot (sysroot, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c index b939278c..77be95d2 100644 --- a/src/ostree/ot-admin-builtin-upgrade.c +++ b/src/ostree/ot-admin-builtin-upgrade.c @@ -57,44 +57,37 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GOptionContext) context = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed"); + g_autoptr(OstreeSysroot) sysroot = NULL; - g_autoptr(OstreeSysrootUpgrader) upgrader = NULL; - g_autoptr(GKeyFile) origin = NULL; - g_autoptr(OstreeAsyncProgress) progress = NULL; - gboolean changed; - OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; - - context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed"); - if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (opt_pull_only && opt_deploy_only) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot simultaneously specify --pull-only and --deploy-only"); - goto out; + return FALSE; } else if (opt_pull_only && opt_reboot) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot simultaneously specify --pull-only and --reboot"); - goto out; + return FALSE; } if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; + return FALSE; - upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, - cancellable, error); + g_autoptr(OstreeSysrootUpgrader) upgrader = + ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, + cancellable, error); if (!upgrader) - goto out; + return FALSE; - origin = ostree_sysroot_upgrader_dup_origin (upgrader); + g_autoptr(GKeyFile) origin = ostree_sysroot_upgrader_dup_origin (upgrader); if (origin != NULL) { gboolean origin_changed = FALSE; @@ -122,16 +115,19 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr { /* XXX GCancellable parameter is not used. */ if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, NULL, error)) - goto out; + return FALSE; } } + gboolean changed; + OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; if (opt_deploy_only) upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC; { g_auto(GLnxConsoleRef) console = { 0, }; glnx_console_lock (&console); + g_autoptr(OstreeAsyncProgress) progress = NULL; if (console.is_tty) progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); @@ -152,7 +148,7 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr */ if (opt_pull_only) (void) ostree_sysroot_cleanup (sysroot, NULL, NULL); - goto out; + return FALSE; } if (progress) @@ -168,17 +164,15 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr if (!opt_pull_only) { if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) - goto out; + return FALSE; } if (opt_reboot) { if (!ot_admin_execve_reboot (sysroot, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } From aef5a7331e112f4d8c3ce7ccc4abcc4b6c2a2c76 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 14:43:33 -0400 Subject: [PATCH 36/83] bin/admin: Check for booted deployment to see if we should reboot Rather than calling `ostree_sysroot_get_path()`, which I'd like to deprecate for the same reason as `ostree_repo_get_path()`. Closes: #1123 Approved by: jlebon --- src/ostree/ot-admin-functions.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c index a0a66b6a..6a99db04 100644 --- a/src/ostree/ot-admin-functions.c +++ b/src/ostree/ot-admin-functions.c @@ -151,13 +151,15 @@ ot_admin_sysroot_lock (OstreeSysroot *sysroot, gboolean ot_admin_execve_reboot (OstreeSysroot *sysroot, GError **error) { - g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/"); + OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); - if (g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot)) - { - if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0) - return glnx_throw_errno (error); - } + /* If the sysroot isn't booted, we shouldn't reboot, even if somehow the user + * asked for it; might accidentally be specified in a build script, etc. + */ + if (!booted) + return TRUE; + if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0) + return glnx_throw_errno_prefix (error, "execve(systemctl reboot)"); return TRUE; } From 517dd9c9648f6d1508343429086ac5a471bea7ec Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 14:57:53 -0400 Subject: [PATCH 37/83] bin/admin: Change init-fs to stop loading a sysroot to init one This is exactly analogous to the `ostree init` case where we have `OSTREE_BUILTIN_FLAG_NO_REPO` to avoid trying to load a repo when we're creating one. Let's avoid the pointless sysroot for `init-fs`; among other things this will then let us do `ostree_sysroot_load()` inside the argument parsing, and drop it from every other user. Closes: #1123 Approved by: jlebon --- src/ostree/ot-admin-builtin-init-fs.c | 54 ++++++++++++--------------- src/ostree/ot-main.c | 7 ++++ src/ostree/ot-main.h | 5 ++- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/ostree/ot-admin-builtin-init-fs.c b/src/ostree/ot-admin-builtin-init-fs.c index c1fa16b0..a92d67dc 100644 --- a/src/ostree/ot-admin-builtin-init-fs.c +++ b/src/ostree/ot-admin-builtin-init-fs.c @@ -41,57 +41,51 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GError **error) { - g_autoptr(GOptionContext) context = NULL; - g_autoptr(OstreeSysroot) sysroot = NULL; - gboolean ret = FALSE; - glnx_fd_close int root_dfd = -1; - g_autoptr(OstreeSysroot) target_sysroot = NULL; - guint i; - const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"}; - - context = g_option_context_new ("PATH - Initialize a root filesystem"); + g_autoptr(GOptionContext) context = g_option_context_new ("PATH - Initialize a root filesystem"); if (!ostree_admin_option_context_parse (context, options, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, - &sysroot, cancellable, error)) - goto out; + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED | + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, + NULL, cancellable, error)) + return FALSE; if (argc < 2) { ot_util_usage_error (context, "PATH must be specified", error); - goto out; + return FALSE; } - if (!glnx_opendirat (AT_FDCWD, argv[1], TRUE, &root_dfd, error)) - goto out; - { g_autoptr(GFile) dir = g_file_new_for_path (argv[1]); - target_sysroot = ostree_sysroot_new (dir); - } + const char *sysroot_path = argv[1]; - for (i = 0; i < G_N_ELEMENTS(normal_toplevels); i++) + glnx_fd_close int root_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, sysroot_path, TRUE, &root_dfd, error)) + return FALSE; + + const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"}; + for (guint i = 0; i < G_N_ELEMENTS (normal_toplevels); i++) { if (!glnx_shutil_mkdir_p_at (root_dfd, normal_toplevels[i], 0755, cancellable, error)) - goto out; + return FALSE; } - + if (!glnx_shutil_mkdir_p_at (root_dfd, "root", 0700, cancellable, error)) - goto out; + return FALSE; if (!glnx_shutil_mkdir_p_at (root_dfd, "tmp", 01777, cancellable, error)) - goto out; + return FALSE; if (fchmodat (root_dfd, "tmp", 01777, 0) == -1) { glnx_set_prefix_error_from_errno (error, "chmod: %s", "tmp"); - goto out; + return FALSE; } + g_autoptr(GFile) dir = g_file_new_for_path (sysroot_path); + g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (dir); + if (!ostree_sysroot_ensure_initialized (sysroot, cancellable, error)) + return FALSE; - if (!ostree_sysroot_ensure_initialized (target_sysroot, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index c8c3490e..48281c26 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -377,6 +377,13 @@ ostree_admin_option_context_parse (GOptionContext *context, if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) return FALSE; + if (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT) + { + g_assert_null (out_sysroot); + /* Early return if no sysroot is requested */ + return TRUE; + } + g_autoptr(GFile) sysroot_path = NULL; if (opt_sysroot != NULL) sysroot_path = g_file_new_for_path (opt_sysroot); diff --git a/src/ostree/ot-main.h b/src/ostree/ot-main.h index c7db4a07..ddf52959 100644 --- a/src/ostree/ot-main.h +++ b/src/ostree/ot-main.h @@ -33,8 +33,9 @@ typedef enum { typedef enum { OSTREE_ADMIN_BUILTIN_FLAG_NONE = 0, - OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER = 1 << 0, - OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED = 1 << 1 + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER = (1 << 0), + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED = (1 << 1), + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT = (1 << 2), } OstreeAdminBuiltinFlags; typedef struct { From 4bd63dd91998288d51f32cbe6c773ba89f234575 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 15:01:18 -0400 Subject: [PATCH 38/83] bin/admin: Do sysroot loading during argument parsing Followup from previous patch - we can now centralize the sysroot loading. Besides the obvious cleanup value, this is also prep for dropping an `ostree_sysroot_get_path()` user. Closes: #1123 Approved by: jlebon --- src/ostree/ot-admin-builtin-cleanup.c | 3 --- src/ostree/ot-admin-builtin-deploy.c | 2 -- src/ostree/ot-admin-builtin-diff.c | 3 --- src/ostree/ot-admin-builtin-set-origin.c | 3 --- src/ostree/ot-admin-builtin-status.c | 3 --- src/ostree/ot-admin-builtin-switch.c | 3 --- src/ostree/ot-admin-builtin-undeploy.c | 2 -- src/ostree/ot-admin-builtin-unlock.c | 3 --- src/ostree/ot-admin-builtin-upgrade.c | 3 --- ...ot-admin-instutil-builtin-grub2-generate.c | 3 --- ...-instutil-builtin-selinux-ensure-labeled.c | 3 --- .../ot-admin-instutil-builtin-set-kargs.c | 3 --- src/ostree/ot-main.c | 20 +++++++++---------- 13 files changed, 10 insertions(+), 44 deletions(-) diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c index 13caa7f4..a3b0a880 100644 --- a/src/ostree/ot-admin-builtin-cleanup.c +++ b/src/ostree/ot-admin-builtin-cleanup.c @@ -52,9 +52,6 @@ ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GErr &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index fa588f87..e46ad025 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -82,8 +82,6 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro const char *refspec = argv[1]; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; OstreeRepo *repo = ostree_sysroot_repo (sysroot); /* Find the currently booted deployment, if any; we will ensure it diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c index 0419f2e1..99672866 100644 --- a/src/ostree/ot-admin-builtin-diff.c +++ b/src/ostree/ot-admin-builtin-diff.c @@ -63,9 +63,6 @@ ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, &sysroot, cancellable, error)) goto out; - - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, cancellable, error)) diff --git a/src/ostree/ot-admin-builtin-set-origin.c b/src/ostree/ot-admin-builtin-set-origin.c index c49f575a..e6020cbe 100644 --- a/src/ostree/ot-admin-builtin-set-origin.c +++ b/src/ostree/ot-admin-builtin-set-origin.c @@ -75,9 +75,6 @@ ot_admin_builtin_set_origin (int argc, char **argv, GCancellable *cancellable, G if (argc > 3) branch = argv[3]; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c index 3dd7aec5..56107974 100644 --- a/src/ostree/ot-admin-builtin-status.c +++ b/src/ostree/ot-admin-builtin-status.c @@ -108,9 +108,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c index 3b54ea85..48fb2726 100644 --- a/src/ostree/ot-admin-builtin-switch.c +++ b/src/ostree/ot-admin-builtin-switch.c @@ -63,9 +63,6 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro const char *new_provided_refspec = argv[1]; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; - g_autoptr(OstreeSysrootUpgrader) upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname, OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c index c0ff89ef..d16c927e 100644 --- a/src/ostree/ot-admin-builtin-undeploy.c +++ b/src/ostree/ot-admin-builtin-undeploy.c @@ -60,8 +60,6 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr return FALSE; } - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; current_deployments = ostree_sysroot_get_deployments (sysroot); deploy_index_str = argv[1]; diff --git a/src/ostree/ot-admin-builtin-unlock.c b/src/ostree/ot-admin-builtin-unlock.c index 05397414..36d99edb 100644 --- a/src/ostree/ot-admin-builtin-unlock.c +++ b/src/ostree/ot-admin-builtin-unlock.c @@ -65,9 +65,6 @@ ot_admin_builtin_unlock (int argc, char **argv, GCancellable *cancellable, GErro goto out; } - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); if (!booted_deployment) { diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c index 77be95d2..8944904b 100644 --- a/src/ostree/ot-admin-builtin-upgrade.c +++ b/src/ostree/ot-admin-builtin-upgrade.c @@ -78,9 +78,6 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr return FALSE; } - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; - g_autoptr(OstreeSysrootUpgrader) upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, cancellable, error); diff --git a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c index 07bd1eaa..8ff0dc47 100644 --- a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c +++ b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c @@ -53,9 +53,6 @@ ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, GCancellable *c &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (argc >= 2) { bootversion = (guint) g_ascii_strtoull (argv[1], NULL, 10); diff --git a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c index c754b18a..cbca7db3 100644 --- a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c +++ b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c @@ -204,9 +204,6 @@ ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, GCancel &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) { diff --git a/src/ostree/ot-admin-instutil-builtin-set-kargs.c b/src/ostree/ot-admin-instutil-builtin-set-kargs.c index 1a37022c..7a98feb7 100644 --- a/src/ostree/ot-admin-instutil-builtin-set-kargs.c +++ b/src/ostree/ot-admin-instutil-builtin-set-kargs.c @@ -66,9 +66,6 @@ ot_admin_instutil_builtin_set_kargs (int argc, char **argv, GCancellable *cancel &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) { diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 48281c26..cd7f0f4c 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -391,6 +391,16 @@ ostree_admin_option_context_parse (GOptionContext *context, g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_path); g_signal_connect (sysroot, "journal-msg", G_CALLBACK (on_sysroot_journal_msg), NULL); + if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0) + { + /* Released when sysroot is finalized, or on process exit */ + if (!ot_admin_sysroot_lock (sysroot, error)) + return FALSE; + } + + if (!ostree_sysroot_load (sysroot, cancellable, error)) + return FALSE; + if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) { GFile *path = ostree_sysroot_get_path (sysroot); @@ -411,9 +421,6 @@ ostree_admin_option_context_parse (GOptionContext *context, g_autoptr(GFile) deployment_file = NULL; g_autofree char *deployment_path = NULL; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; - deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) return glnx_throw (error, "Unable to find a deployment in sysroot"); @@ -433,13 +440,6 @@ ostree_admin_option_context_parse (GOptionContext *context, exit (EXIT_SUCCESS); } - if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0) - { - /* Released when sysroot is finalized, or on process exit */ - if (!ot_admin_sysroot_lock (sysroot, error)) - return FALSE; - } - if (out_sysroot) *out_sysroot = g_steal_pointer (&sysroot); From 0fb8686ccc5bb5de7f9a0d7ea9823963c872ebe8 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Sep 2017 15:03:02 -0400 Subject: [PATCH 39/83] bin/admin: Check for booted sysroot for root-required commands Drops a use of `ostree_sysroot_get_path()`, prep for `ostree_sysroot_new_at()`. Closes: #1123 Approved by: jlebon --- src/ostree/ot-main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index cd7f0f4c..011ae16c 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -403,10 +403,12 @@ ostree_admin_option_context_parse (GOptionContext *context, if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) { - GFile *path = ostree_sysroot_get_path (sysroot); + OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); - /* If sysroot path is "/" then user must be root. */ - if (!g_file_has_parent (path, NULL) && getuid () != 0) + /* Only require root if we're manipulating a booted sysroot. (Mostly + * useful for the test suite) + */ + if (booted && getuid () != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "You must be root to perform this command"); From 5cf128052f78a5c6c726357951c574ae7dcfd58f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 12:42:51 -0400 Subject: [PATCH 40/83] ci: Hackaround Fedora rpm/libdb/glibc issue Not sure I want to wait a few days for a new container, so let's give this a shot now. See https://bugzilla.redhat.com/show_bug.cgi?id=1483553 Closes: #1143 Approved by: jlebon --- .papr.yml | 7 +------ ci/build.sh | 4 ++++ ci/ci-commitmessage-submodules.sh | 5 +++++ ci/flatpak.sh | 4 ++++ ci/libbuild.sh | 14 ++++++++++++++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.papr.yml b/.papr.yml index 0a4e04ee..75ace5da 100644 --- a/.papr.yml +++ b/.papr.yml @@ -8,8 +8,6 @@ context: f26-primary container: image: registry.fedoraproject.org/fedora:26 -packages: - - git env: # Enable all the sanitizers for this primary build. @@ -36,8 +34,6 @@ context: c7-primary inherit: true required: true -packages: - host: distro: centos/7/atomic @@ -55,10 +51,9 @@ context: f26-rust inherit: true container: image: registry.fedoraproject.org/fedora:26 -packages: - - cargo env: CONFIGOPTS: '--enable-rust' + CI_PKGS: cargo tests: - ci/build.sh diff --git a/ci/build.sh b/ci/build.sh index 22071764..26e2ff37 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -6,12 +6,16 @@ set -xeuo pipefail dn=$(dirname $0) . ${dn}/libbuild.sh +pkg_upgrade pkg_install_builddeps ostree # Until this propagates farther pkg_install 'pkgconfig(libcurl)' 'pkgconfig(openssl)' pkg_install sudo which attr fuse \ libubsan libasan libtsan PyYAML redhat-rpm-config \ elfutils +if test -n "${CI_PKGS:-}"; then + pkg_install ${CI_PKGS} +fi pkg_install_if_os fedora gjs gnome-desktop-testing parallel coccinelle clang # always fail on warnings; https://github.com/ostreedev/ostree/pull/971 diff --git a/ci/ci-commitmessage-submodules.sh b/ci/ci-commitmessage-submodules.sh index aeccc24d..2dc9b764 100755 --- a/ci/ci-commitmessage-submodules.sh +++ b/ci/ci-commitmessage-submodules.sh @@ -16,6 +16,8 @@ set -euo pipefail # if running under PAPR, use the branch/PR HEAD actually # being tested rather than the merge sha HEAD=${PAPR_COMMIT:-HEAD} +dn=$(dirname $0) +. ${dn}/libbuild.sh tmpd=$(mktemp -d) touch ${tmpd}/.tmpdir @@ -27,6 +29,9 @@ cleanup_tmp() { } trap cleanup_tmp EXIT +pkg_upgrade +pkg_install git + gitdir=$(realpath $(pwd)) # Create a temporary copy of this (using cp not git clone) so git doesn't # try to read the submodules from the Internet again. If we wanted to diff --git a/ci/flatpak.sh b/ci/flatpak.sh index 7d98ff05..16812480 100755 --- a/ci/flatpak.sh +++ b/ci/flatpak.sh @@ -3,6 +3,9 @@ set -xeuo pipefail +dn=$(dirname $0) +. ${dn}/libbuild.sh + build() { env NOCONFIGURE=1 ./autogen.sh ./configure --prefix=/usr --libdir=/usr/lib64 "$@" @@ -11,6 +14,7 @@ build() { codedir=$(pwd) +pkg_upgrade # Core prep yum -y install dnf-plugins-core @buildsys-build 'dnf-command(builddep)' # build+install ostree, and build deps for both, so that our diff --git a/ci/libbuild.sh b/ci/libbuild.sh index fef9d3ae..0e024063 100644 --- a/ci/libbuild.sh +++ b/ci/libbuild.sh @@ -1,5 +1,19 @@ #!/usr/bin/bash +pkg_upgrade() { + # https://bugzilla.redhat.com/show_bug.cgi?id=1483553 + if ! yum -y upgrade 2>err.txt; then + ecode=$? + if grep -q -F -e "BDB1539 Build signature doesn't match environment" err.txt; then + rpm --rebuilddb + yum -y upgrade + else + cat err.txt + exit ${ecode} + fi + fi +} + make() { /usr/bin/make -j $(getconf _NPROCESSORS_ONLN) "$@" } From 8ec76cf024c09b0d4f00cccb74555785cf6ccf93 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 10:24:56 -0400 Subject: [PATCH 41/83] lib/repo: Add apidoc for repo properties However, they weren't showing up in the output HTML and I have no idea why; I looked at what we're doing and it looks close enough to what's going on in `GDBusConnection` that I was using as a reference. I'm not going to spend a lot of time to debug it right now. Closes: #1140 Approved by: jlebon --- apidoc/ostree-sections.txt | 1 + src/libostree/ostree-repo.c | 38 +++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index 90bec167..5f061c00 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -268,6 +268,7 @@ ostree_mutable_tree_get_type
ostree-repo +OstreeRepo OstreeRepo OstreeRepoMode ostree_repo_mode_from_string diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index ba33a018..430f6631 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -76,7 +76,7 @@ G_STATIC_ASSERT(sizeof(OstreeRepoPruneOptions) == /** * SECTION:ostree-repo - * @title: Content-addressed object store + * @title: OstreeRepo: Content-addressed object store * @short_description: A git-like storage system for operating system binaries * * The #OstreeRepo is like git, a content-addressed object store. @@ -583,14 +583,32 @@ ostree_repo_class_init (OstreeRepoClass *klass) object_class->set_property = ostree_repo_set_property; object_class->finalize = ostree_repo_finalize; + /** + * OstreeRepo:path: + * + * Path to repository. Note that if this repository was created + * via `ostree_repo_new_at()`, this value will refer to a value in + * the Linux kernel's `/proc/self/fd` directory. Generally, you + * should avoid using this property at all; you can gain a reference + * to the repository's directory fd via `ostree_repo_get_dfd()` and + * use file-descriptor relative operations. + */ g_object_class_install_property (object_class, PROP_PATH, - g_param_spec_object ("path", - "", - "", + g_param_spec_object ("path", "Path", "Path", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - + /** + * OstreeRepo:sysroot-path: + * + * A system using libostree for the host has a "system" repository; this + * property will be set for repositories referenced via + * `ostree_sysroot_repo()` for example. + * + * You should avoid using this property; if your code is operating + * on a system repository, use `OstreeSysroot` and access the repository + * object via `ostree_sysroot_repo()`. + */ g_object_class_install_property (object_class, PROP_SYSROOT_PATH, g_param_spec_object ("sysroot-path", @@ -598,7 +616,15 @@ ostree_repo_class_init (OstreeRepoClass *klass) "", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - + /** + * OstreeRepo:remotes-config-dir: + * + * Path to directory containing remote definitions. The default is `NULL`. + * If a `sysroot-path` property is defined, this value will default to + * `${sysroot_path}/etc/ostree/remotes.d`. + * + * This value will only be used for system repositories. + */ g_object_class_install_property (object_class, PROP_REMOTES_CONFIG_DIR, g_param_spec_string ("remotes-config-dir", From 732891efc28ade8b0f273c3b2cdb4262af54c277 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Sep 2017 12:06:46 -0400 Subject: [PATCH 42/83] lib/repo: Add error prefixing during hardlink object import I happened to have a repo with a missing commit object, and got an unprefixed error during a pull-local. Closes: #1129 Approved by: jlebon --- src/libostree/ostree-repo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 430f6631..70672ae0 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -3350,6 +3350,9 @@ import_one_object_link (OstreeRepo *self, GCancellable *cancellable, GError **error) { + const char *errprefix = glnx_strjoina ("Importing ", checksum, ".", + ostree_object_type_to_string (objtype)); + GLNX_AUTO_PREFIX_ERROR (errprefix, error); char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; _ostree_loose_path (loose_path_buf, checksum, objtype, self->mode); @@ -3396,7 +3399,7 @@ import_one_object_link (OstreeRepo *self, return TRUE; } else - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "linkat"); } if (objtype == OSTREE_OBJECT_TYPE_COMMIT) From 9c4106f166e3b2fe40f9a3df5169df0d927974b1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Sep 2017 15:01:12 -0400 Subject: [PATCH 43/83] bin/local-pull: Clarify docs, add more tests for corrupted local pulls I was reading the pull-local command docs and realized it was somewhat unclear that `--untrusted` *only* applied to local repo pulls; in other words that we always treat non-local pulls as untrusted. Tweak the docstring, and add tests that verify this explicitly. Closes: #1130 Approved by: jlebon --- src/ostree/ot-builtin-pull-local.c | 2 +- src/ostree/ot-builtin-pull.c | 2 +- tests/test-pull-corruption.sh | 43 +++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index a4595768..34115a01 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -47,7 +47,7 @@ static int opt_depth = 0; static GOptionEntry options[] = { { "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" }, { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, - { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust source", NULL }, + { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not verify checksums of local sources (always enabled for HTTP pulls)", NULL }, { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, { "gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify, "GPG verify commits (must specify --remote)", NULL }, diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index ebcde49d..119e6656 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -57,7 +57,7 @@ static GOptionEntry options[] = { { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror and fetches all refs if none provided", NULL }, { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL }, - { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL }, + { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not verify checksums of local sources (always enabled for HTTP pulls)", NULL }, { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, { "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL }, { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" }, diff --git a/tests/test-pull-corruption.sh b/tests/test-pull-corruption.sh index 9dc7d62b..3696acc4 100755 --- a/tests/test-pull-corruption.sh +++ b/tests/test-pull-corruption.sh @@ -29,7 +29,7 @@ fi setup_fake_remote_repo1 "archive" -echo '1..2' +echo '1..3' repopath=${test_tmpdir}/ostree-srv/gnomerepo cp -a ${repopath} ${repopath}.orig @@ -59,3 +59,44 @@ gjs $(dirname $0)/corrupt-repo-ref.js ${repopath} main || true assert_file_has_content corrupted-status.txt 'Changed byte' do_corrupt_pull_test echo "ok corruption" + +if ! skip_one_without_user_xattrs; then + # Set up a corrupted commit object + rm ostree-srv httpd repo -rf + setup_fake_remote_repo1 "archive" + rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main) + corruptrev=$(echo ${rev} hello | sha256sum | cut -f 1 -d ' ') + assert_not_streq ${rev} ${corruptrev} + rev_path=ostree-srv/gnomerepo/objects/${rev:0:2}/${rev:2}.commit + corruptrev_path=ostree-srv/gnomerepo/objects/${corruptrev:0:2}/${corruptrev:2}.commit + mkdir -p $(dirname ${corruptrev_path}) + mv ${rev_path} ${corruptrev_path} + echo ${corruptrev} > ostree-srv/gnomerepo/refs/heads/main + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + if ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo fsck 2>err.txt; then + assert_not_reached "fsck with corrupted commit worked?" + fi + assert_file_has_content err.txt "corrupted object ${corruptrev}\.commit" + + # Do a pull-local; this should succeed since we don't verify checksums + # for local repos by default. + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo pull-local ostree-srv/gnomerepo main + + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + if ${CMD_PREFIX} ostree --repo=repo pull-local --untrusted ostree-srv/gnomerepo main 2>err.txt; then + assert_not_reached "pull-local --untrusted worked?" + fi + assert_file_has_content err.txt "Corrupted commit object ${corruptrev}.*actual checksum is ${rev}" + + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull unexpectedly succeeded!" + fi + assert_file_has_content err.txt "Corrupted commit object ${corruptrev}.*actual checksum is ${rev}" + echo "ok pull commit corruption" +fi From 1f6fc009f7344365ba3b4d6fcdf6178be38b3171 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Sep 2017 15:24:07 -0400 Subject: [PATCH 44/83] lib/sysroot: A bit more new style porting A few things not done in the last pass; prep for `ostree_sysroot_new_at()` work. Closes: #1131 Approved by: jlebon --- src/libostree/ostree-sysroot-cleanup.c | 124 +++++++++++-------------- 1 file changed, 56 insertions(+), 68 deletions(-) diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index 79663b66..de313930 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -201,73 +201,70 @@ list_all_boot_directories (OstreeSysroot *self, return ret; } +/* A sysroot has at most one active "boot version" (pair of version,subversion) + * out of a total of 4 possible. This function deletes from the filesystem the 3 + * other versions that aren't active. + */ static gboolean cleanup_other_bootversions (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int cleanup_bootversion; - int cleanup_subbootversion; + int cleanup_bootversion = self->bootversion == 0 ? 1 : 0; + int cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; + g_autoptr(GFile) cleanup_boot_dir = NULL; - - cleanup_bootversion = self->bootversion == 0 ? 1 : 0; - cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion); if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; + return FALSE; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d", cleanup_bootversion); if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; + return FALSE; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.0", cleanup_bootversion); if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; + return FALSE; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.1", cleanup_bootversion); if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; + return FALSE; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion); if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; + return FALSE; g_clear_object (&cleanup_boot_dir); - ret = TRUE; - out: - return ret; + return TRUE; } +/* As the bootloader configuration changes, we will have leftover deployments + * on disk. This function deletes all deployments which aren't actively + * referenced. + */ static gboolean cleanup_old_deployments (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; + /* Gather the device/inode of the rootfs, so we can double + * check we won't delete it. + */ struct stat root_stbuf; - guint i; - g_autoptr(GHashTable) active_deployment_dirs = NULL; - g_autoptr(GHashTable) active_boot_checksums = NULL; - g_autoptr(GPtrArray) all_deployment_dirs = NULL; - g_autoptr(GPtrArray) all_boot_dirs = NULL; + if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error)) + return FALSE; - if (stat ("/", &root_stbuf) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } - - active_deployment_dirs = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); - active_boot_checksums = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); - - for (i = 0; i < self->deployments->len; i++) + /* Load all active deployments referenced by bootloader configuration. */ + g_autoptr(GHashTable) active_deployment_dirs = + g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); + g_autoptr(GHashTable) active_boot_checksums = + g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); + for (guint i = 0; i < self->deployments->len; i++) { OstreeDeployment *deployment = self->deployments->pdata[i]; char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); @@ -277,11 +274,12 @@ cleanup_old_deployments (OstreeSysroot *self, g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum); } + /* Find all deployment directories, both active and inactive */ + g_autoptr(GPtrArray) all_deployment_dirs = NULL; if (!list_all_deployment_directories (self, &all_deployment_dirs, cancellable, error)) - goto out; - - for (i = 0; i < all_deployment_dirs->len; i++) + return FALSE; + for (guint i = 0; i < all_deployment_dirs->len; i++) { OstreeDeployment *deployment = all_deployment_dirs->pdata[i]; g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); @@ -294,13 +292,10 @@ cleanup_old_deployments (OstreeSysroot *self, if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_fd, error)) - goto out; + return FALSE; - if (fstat (deployment_fd, &stbuf) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + if (!glnx_fstat (deployment_fd, &stbuf, error)) + return FALSE; /* This shouldn't happen, because higher levels should * disallow having the booted deployment not in the active @@ -309,22 +304,24 @@ cleanup_old_deployments (OstreeSysroot *self, stbuf.st_ino == root_stbuf.st_ino) continue; + /* This deployment wasn't referenced, so delete it */ if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE, cancellable, error)) - goto out; - - if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error)) - goto out; + return FALSE; if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error)) - goto out; + return FALSE; + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error)) + return FALSE; } } + /* Clean up boot directories */ + g_autoptr(GPtrArray) all_boot_dirs = NULL; if (!list_all_boot_directories (self, &all_boot_dirs, cancellable, error)) - goto out; - - for (i = 0; i < all_boot_dirs->len; i++) + return FALSE; + + for (guint i = 0; i < all_boot_dirs->len; i++) { GFile *bootdir = all_boot_dirs->pdata[i]; g_autofree char *osname = NULL; @@ -338,14 +335,16 @@ cleanup_old_deployments (OstreeSysroot *self, continue; if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (bootdir), cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } +/* libostree holds a ref for each deployment's exact checksum to avoid it being + * GC'd even if the origin ref changes. This function resets those refs + * to match active deployments. + */ static gboolean cleanup_ref_prefix (OstreeRepo *repo, int bootversion, @@ -354,23 +353,17 @@ cleanup_ref_prefix (OstreeRepo *repo, GError **error) { gboolean ret = FALSE; - g_autofree char *prefix = NULL; + g_autofree char *prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion); + g_autoptr(GHashTable) refs = NULL; - GHashTableIter hashiter; - gpointer hashkey, hashvalue; - - prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion); - if (!ostree_repo_list_refs_ext (repo, prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) goto out; if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) goto out; - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH (refs, const char *, ref) { - const char *ref = hashkey; ostree_repo_transaction_set_refspec (repo, ref, NULL); } @@ -442,12 +435,10 @@ prune_repo (OstreeRepo *repo, gint n_objects_total; gint n_objects_pruned; guint64 freed_space; - gboolean ret = FALSE; - if (!ostree_repo_prune (repo, OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY, 0, &n_objects_total, &n_objects_pruned, &freed_space, cancellable, error)) - goto out; + return FALSE; if (freed_space > 0) { @@ -455,10 +446,7 @@ prune_repo (OstreeRepo *repo, g_print ("Freed objects: %s\n", freed_space_str); } - ret = TRUE; - -out: - return ret; + return TRUE; } /** From 6578c362fe7d1a18c6622c2ba4eb8ab9257cc45e Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Sep 2017 21:03:18 -0400 Subject: [PATCH 45/83] lib/gpg: Use nicer helper for gpg error messages The vast majority of invocations of `ot_gpgme_error_to_gio_error()` were paired with `g_prefix_error()`; let's combine them for the same reason we do `glnx_throw_errno_prefix()`. For the few cases that don't we might as well add some prefix. I also changed it to `return FALSE` in prep for more style porting. Closes: #1135 Approved by: jlebon --- src/libostree/ostree-gpg-verifier.c | 13 ++++----- src/libostree/ostree-gpg-verify-result.c | 3 +- src/libostree/ostree-repo.c | 35 ++++++++--------------- src/libotutil/ot-gpg-utils.c | 36 +++++++++++------------- src/libotutil/ot-gpg-utils.h | 3 +- 5 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c index 99756e2b..d7778cf0 100644 --- a/src/libostree/ostree-gpg-verifier.c +++ b/src/libostree/ostree-gpg-verifier.c @@ -187,14 +187,14 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, gpg_error = gpgme_data_new_from_fd (&kdata, fd); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); + ot_gpgme_throw (gpg_error, error, "Loading data from fd %i", fd); goto out; } gpg_error = gpgme_op_import (result->context, kdata); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); + ot_gpgme_throw (gpg_error, error, "Failed to import key"); goto out; } } @@ -212,8 +212,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, 0 /* do not copy */); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to read signed data: "); + ot_gpgme_throw (gpg_error, error, "Unable to read signed data"); goto out; } @@ -223,16 +222,14 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, 0 /* do not copy */); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to read signature: "); + ot_gpgme_throw (gpg_error, error, "Unable to read signature"); goto out; } gpg_error = gpgme_op_verify (result->context, signature_buffer, data_buffer, NULL); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to complete signature verification: "); + ot_gpgme_throw (gpg_error, error, "Unable to complete signature verification"); goto out; } diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index f6689e63..8b0c0b17 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -133,8 +133,7 @@ ostree_gpg_verify_result_initable_init (GInitable *initable, gpg_error = gpgme_new (&result->context); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to create context: "); + ot_gpgme_throw (gpg_error, error, "Unable to create context"); goto out; } diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 70672ae0..d9fc65b1 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1465,8 +1465,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_op_import (source_context, data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to import keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to import keys"); goto out; } @@ -1491,8 +1490,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_get_key (source_context, key_ids[ii], &key, 0); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to find key \"%s\": ", key_ids[ii]); + ot_gpgme_throw (gpg_error, error, "Unable to find key \"%s\"", key_ids[ii]); goto out; } @@ -1519,8 +1517,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, if (gpgme_err_code (gpg_error) != GPG_ERR_EOF) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to list keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to list keys"); goto out; } } @@ -1592,8 +1589,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_data_new (&data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to create data buffer: "); + ot_gpgme_throw (gpg_error, error, "Unable to create data buffer"); goto out; } @@ -1602,8 +1598,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to export keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to export keys"); goto out; } @@ -1612,8 +1607,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_op_import (target_context, data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to import keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to import keys"); goto out; } @@ -1628,8 +1622,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, { if (import_status->result != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to import key \"%s\": ", + ot_gpgme_throw (gpg_error, error, "Unable to import key \"%s\"", import_status->fpr); goto out; } @@ -4179,26 +4172,23 @@ sign_data (OstreeRepo *self, } else if (err != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Unable to lookup key ID %s: ", key_id); + ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id); goto out; } /* Add the key to the context as a signer */ if ((err = gpgme_signers_add (context, key)) != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Error signing commit: "); + ot_gpgme_throw (err, error, "Error signing commit"); goto out; } - + { gsize len; const char *buf = g_bytes_get_data (input_data, &len); if ((err = gpgme_data_new_from_mem (&commit_buffer, buf, len, FALSE)) != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Failed to create buffer from commit file: "); + ot_gpgme_throw (err, error, "Failed to create buffer from commit file"); goto out; } } @@ -4208,8 +4198,7 @@ sign_data (OstreeRepo *self, if ((err = gpgme_op_sign (context, commit_buffer, signature_buffer, GPGME_SIG_MODE_DETACH)) != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Failure signing commit file: "); + ot_gpgme_throw (err, error, "Failure signing commit file"); goto out; } diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index 99f4879e..f8a13269 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -26,20 +26,23 @@ #include "libglnx.h" -void -ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, - GError **error) +/* Like glnx_throw_errno_prefix, but takes @gpg_error */ +gboolean +ot_gpgme_throw (gpgme_error_t gpg_error, GError **error, + const char *fmt, ...) { + if (error == NULL) + return FALSE; + GIOErrorEnum errcode; char errbuf[1024]; /* XXX This list is incomplete. Add cases as needed. */ - switch (gpgme_err_code (gpg_error)) { /* special case - shouldn't be here */ case GPG_ERR_NO_ERROR: - g_return_if_reached (); + g_assert_not_reached (); /* special case - abort on out-of-memory */ case GPG_ERR_ENOMEM: @@ -63,6 +66,12 @@ ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, g_set_error (error, G_IO_ERROR, errcode, "%s: %s", gpgme_strsource (gpg_error), errbuf); + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_va (*error, fmt, args); + va_end (args); + + return FALSE; } gboolean @@ -99,7 +108,7 @@ ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, NULL, tmp_home_dir); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); + ot_gpgme_throw (gpg_error, error, "gpgme_ctx_set_engine_info"); goto out; } @@ -376,7 +385,6 @@ ot_gpgme_data_input (GInputStream *input_stream) if (gpg_error != GPG_ERR_NO_ERROR) { g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); - ot_gpgme_error_to_gio_error (gpg_error, NULL); g_assert_not_reached (); } @@ -399,7 +407,6 @@ ot_gpgme_data_output (GOutputStream *output_stream) if (gpg_error != GPG_ERR_NO_ERROR) { g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); - ot_gpgme_error_to_gio_error (gpg_error, NULL); g_assert_not_reached (); } @@ -416,11 +423,7 @@ ot_gpgme_new_ctx (const char *homedir, g_auto(gpgme_ctx_t) context = NULL; if ((err = gpgme_new (&context)) != GPG_ERR_NO_ERROR) - { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Unable to create gpg context: "); - return NULL; - } + return ot_gpgme_throw (err, error, "Unable to create gpg context"), NULL; if (homedir != NULL) { @@ -430,12 +433,7 @@ ot_gpgme_new_ctx (const char *homedir, if ((err = gpgme_ctx_set_engine_info (context, info->protocol, NULL, homedir)) != GPG_ERR_NO_ERROR) - { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Unable to set gpg homedir to '%s': ", - homedir); - return NULL; - } + return ot_gpgme_throw (err, error, "Unable to set gpg homedir to '%s'", homedir), NULL; } return g_steal_pointer (&context); diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h index b639e5ac..bd2810f8 100644 --- a/src/libotutil/ot-gpg-utils.h +++ b/src/libotutil/ot-gpg-utils.h @@ -30,7 +30,8 @@ G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_data_t, gpgme_data_release, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_ctx_t, gpgme_release, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_key_t, gpgme_key_unref, NULL) -void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error); +gboolean ot_gpgme_throw (gpgme_error_t gpg_error, GError **error, + const char *fmt, ...) G_GNUC_PRINTF (3, 4); gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, char **out_tmp_home_dir, From 3c5e37329487584fb4b9c7c4e90415dab61c0b0f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Sep 2017 21:18:59 -0400 Subject: [PATCH 46/83] lib/gpg: Port a few misc gpg functions to new style I'd mostly been skipping the GPG functions due to lack of autoptr for a few things, but I noticed these bits were straightforward. Closes: #1136 Approved by: jlebon --- src/libostree/ostree-gpg-verifier.c | 19 ++++----------- src/libostree/ostree-repo.c | 37 +++++++---------------------- 2 files changed, 14 insertions(+), 42 deletions(-) diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c index d7778cf0..9b731489 100644 --- a/src/libostree/ostree-gpg-verifier.c +++ b/src/libostree/ostree-gpg-verifier.c @@ -365,31 +365,22 @@ _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *self, GCancellable *cancellable, GError **error) { - const char *global_keyring_path = g_getenv ("OSTREE_GPG_HOME"); - g_autoptr(GFile) global_keyring_dir = NULL; - gboolean ret = FALSE; - g_return_val_if_fail (OSTREE_IS_GPG_VERIFIER (self), FALSE); + const char *global_keyring_path = g_getenv ("OSTREE_GPG_HOME"); if (global_keyring_path == NULL) global_keyring_path = DATADIR "/ostree/trusted.gpg.d/"; if (g_file_test (global_keyring_path, G_FILE_TEST_IS_DIR)) { - global_keyring_dir = g_file_new_for_path (global_keyring_path); + g_autoptr(GFile) global_keyring_dir = g_file_new_for_path (global_keyring_path); if (!_ostree_gpg_verifier_add_keyring_dir (self, global_keyring_dir, cancellable, error)) - { - g_prefix_error (error, "Reading keyring directory '%s'", - gs_file_get_path_cached (global_keyring_dir)); - goto out; - } + return glnx_prefix_error (error, "Reading keyring directory '%s'", + gs_file_get_path_cached (global_keyring_dir)); } - ret = TRUE; - -out: - return ret; + return TRUE; } OstreeGpgVerifier* diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index d9fc65b1..2226e8a5 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -4579,32 +4579,23 @@ _ostree_repo_verify_commit_internal (OstreeRepo *self, GCancellable *cancellable, GError **error) { - OstreeGpgVerifyResult *result = NULL; g_autoptr(GVariant) commit_variant = NULL; - g_autoptr(GVariant) metadata = NULL; - g_autoptr(GBytes) signed_data = NULL; - /* Load the commit */ if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit_checksum, &commit_variant, error)) - { - g_prefix_error (error, "Failed to read commit: "); - goto out; - } + return glnx_prefix_error_null (error, "Failed to read commit"); /* Load the metadata */ + g_autoptr(GVariant) metadata = NULL; if (!ostree_repo_read_commit_detached_metadata (self, commit_checksum, &metadata, cancellable, error)) - { - g_prefix_error (error, "Failed to read detached metadata: "); - goto out; - } + return glnx_prefix_error_null (error, "Failed to read detached metadata"); - signed_data = g_variant_get_data_as_bytes (commit_variant); + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit_variant); /* XXX This is a hackish way to indicate to use ALL remote-specific * keyrings in the signature verification. We want this when @@ -4612,17 +4603,10 @@ _ostree_repo_verify_commit_internal (OstreeRepo *self, if (remote_name == NULL) remote_name = OSTREE_ALL_REMOTES; - result = _ostree_repo_gpg_verify_with_metadata (self, - signed_data, - metadata, - remote_name, - keyringdir, - extra_keyring, - cancellable, - error); - -out: - return result; + return _ostree_repo_gpg_verify_with_metadata (self, signed_data, + metadata, remote_name, + keyringdir, extra_keyring, + cancellable, error); } /** @@ -4654,10 +4638,7 @@ ostree_repo_verify_commit (OstreeRepo *self, cancellable, error); if (!ostree_gpg_verify_result_require_valid_signature (result, error)) - { - g_prefix_error (error, "Commit %s: ", commit_checksum); - return FALSE; - } + return glnx_prefix_error (error, "Commit %s", commit_checksum); return TRUE; } From 57509e4d50f916e1dcb5a6afdbcfe921093f965b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 10:39:43 -0400 Subject: [PATCH 47/83] tests/rofiles-fuse: Add tests for chmod/chown Prep for https://github.com/ostreedev/ostree/pull/1137 where we were incorrectly handling `chown()` on symlinks. Closes: #1141 Approved by: jlebon --- tests/test-rofiles-fuse.sh | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/test-rofiles-fuse.sh b/tests/test-rofiles-fuse.sh index 56045c61..a7811b80 100755 --- a/tests/test-rofiles-fuse.sh +++ b/tests/test-rofiles-fuse.sh @@ -26,11 +26,11 @@ skip_without_user_xattrs setup_test_repository "bare-user" -echo "1..6" +echo "1..7" mkdir mnt -$OSTREE checkout -U test2 checkout-test2 +$OSTREE checkout -H -U test2 checkout-test2 rofiles-fuse checkout-test2 mnt cleanup_fuse() { @@ -47,8 +47,20 @@ assert_file_has_content err.txt "Read-only file system" assert_file_has_content mnt/firstfile first assert_file_has_content checkout-test2/firstfile first -echo "ok failed inplace mutation" +echo "ok failed inplace mutation (open O_TRUNCATE)" +# Test chmod + chown +if chmod 0600 mnt/firstfile 2>err.txt; then + assert_not_reached "chmod inplace" +fi +assert_file_has_content err.txt "chmod:.*Read-only file system" +if chown $(id -u) mnt/firstfile 2>err.txt; then + assert_not_reached "chown inplace" +fi +assert_file_has_content err.txt "chown:.*Read-only file system" +echo "ok failed mutation chmod + chown" + +# Test creating new files, using chown + chmod on them as well echo anewfile-for-fuse > mnt/anewfile-for-fuse assert_file_has_content mnt/anewfile-for-fuse anewfile-for-fuse assert_file_has_content checkout-test2/anewfile-for-fuse anewfile-for-fuse @@ -56,9 +68,10 @@ assert_file_has_content checkout-test2/anewfile-for-fuse anewfile-for-fuse mkdir mnt/newfusedir for i in $(seq 5); do echo ${i}-morenewfuse-${i} > mnt/newfusedir/test-morenewfuse.${i} + chmod 0600 mnt/newfusedir/test-morenewfuse.${i} + chown $(id -u) mnt/newfusedir/test-morenewfuse.${i} done assert_file_has_content checkout-test2/newfusedir/test-morenewfuse.3 3-morenewfuse-3 - echo "ok new content" rm mnt/baz/cow From 303320163f2365db9fea67f64dcc1578e034116e Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 11:37:02 -0400 Subject: [PATCH 48/83] tree-wide: Use helpers for unlinkat() We have `ot_ensure_unlinked_at()` for the "ignore ENOENT" case, and `glnx_unlinkat()` otherwise. Port all in-tree callers to one or the other as appropriate. Just noticed an unprefixed error in the refs case and decided to do a tree-wide check. Closes: #1142 Approved by: jlebon --- src/libostree/ostree-repo-checkout.c | 7 ++----- src/libostree/ostree-repo-prune.c | 12 +++--------- src/libostree/ostree-repo-pull.c | 7 ++----- src/libostree/ostree-repo-refs.c | 7 ++----- src/libostree/ostree-repo.c | 18 ++++++------------ src/libotutil/ot-fs-utils.c | 1 + 6 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 4fbbee7d..dbdbf058 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -1121,11 +1121,8 @@ ostree_repo_checkout_gc (OstreeRepo *self, if (stbuf.st_nlink == 1) { - if (unlinkat (dfd_iter.fd, dent->d_name, 0) != 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + if (!glnx_unlinkat (dfd_iter.fd, dent->d_name, 0, error)) + return FALSE; } } } diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c index 2b596ecb..6ea899bc 100644 --- a/src/libostree/ostree-repo-prune.c +++ b/src/libostree/ostree-repo-prune.c @@ -43,13 +43,7 @@ prune_commitpartial_file (OstreeRepo *repo, GError **error) { g_autofree char *path = _ostree_get_commitpartial_path (checksum); - if (unlinkat (repo->repo_dir_fd, path, 0) != 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "unlinkat"); - } - - return TRUE; + return ot_ensure_unlinked_at (repo->repo_dir_fd, path, error); } static gboolean @@ -147,8 +141,8 @@ _ostree_repo_prune_tmp (OstreeRepo *self, if (has_sig_suffix) dent->d_name[len - 4] = '.'; - if (unlinkat (dfd_iter.fd, dent->d_name, 0) < 0) - return glnx_throw_errno_prefix (error, "unlinkat"); + if (!glnx_unlinkat (dfd_iter.fd, dent->d_name, 0, error)) + return FALSE; } } diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 98fb96b4..d233b384 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -1357,11 +1357,8 @@ static_deltapart_fetch_on_complete (GObject *object, goto out; /* From here on, if we fail to apply the delta, we'll re-fetch it */ - if (unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + if (!glnx_unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0, error)) + goto out; in = g_unix_input_stream_new (fd, FALSE); diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index f8af3c43..b9b00896 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -1007,11 +1007,8 @@ _ostree_repo_write_ref (OstreeRepo *self, { if (dfd >= 0) { - if (unlinkat (dfd, ref->ref_name, 0) != 0) - { - if (errno != ENOENT) - return glnx_throw_errno (error); - } + if (!ot_ensure_unlinked_at (dfd, ref->ref_name, error)) + return FALSE; } } else if (rev != NULL) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 2226e8a5..e7807d11 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -3256,15 +3256,12 @@ ostree_repo_delete_object (OstreeRepo *self, _ostree_loose_path (meta_loose, sha256, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); - if (TEMP_FAILURE_RETRY (unlinkat (self->objects_dir_fd, meta_loose, 0)) < 0) - { - if (G_UNLIKELY (errno != ENOENT)) - return glnx_throw_errno_prefix (error, "unlinkat(%s)", meta_loose); - } + if (!ot_ensure_unlinked_at (self->objects_dir_fd, meta_loose, error)) + return FALSE; } - if (TEMP_FAILURE_RETRY (unlinkat (self->objects_dir_fd, loose_path, 0)) < 0) - return glnx_throw_errno_prefix (error, "Deleting object %s.%s", sha256, ostree_object_type_to_string (objtype)); + if (!glnx_unlinkat (self->objects_dir_fd, loose_path, 0, error)) + return glnx_prefix_error (error, "Deleting object %s.%s", sha256, ostree_object_type_to_string (objtype)); /* If the repository is configured to use tombstone commits, create one when deleting a commit. */ if (objtype == OSTREE_OBJECT_TYPE_COMMIT) @@ -5036,11 +5033,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self, error)) return FALSE; - if (unlinkat (self->repo_dir_fd, "summary.sig", 0) < 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "unlinkat"); - } + if (!ot_ensure_unlinked_at (self->repo_dir_fd, "summary.sig", error)) + return FALSE; return TRUE; } diff --git a/src/libotutil/ot-fs-utils.c b/src/libotutil/ot-fs-utils.c index 2f0ae19c..9100b85b 100644 --- a/src/libotutil/ot-fs-utils.c +++ b/src/libotutil/ot-fs-utils.c @@ -90,6 +90,7 @@ ot_openat_read_stream (int dfd, return TRUE; } +/* Like unlinkat() but ignore ENOENT */ gboolean ot_ensure_unlinked_at (int dfd, const char *path, From 11179e30bd55f69b80cd4dfcd5d15770294e6aef Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 17:11:27 -0400 Subject: [PATCH 49/83] lib/commit: Update docs/code style for ostree_repo_scan_hardlinks() Happened to notice this one `goto out` user, and decided to tweak the docs at the same time. Closes: #1144 Approved by: jlebon --- src/libostree/ostree-repo-commit.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 078b289d..960818c8 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -1029,35 +1029,33 @@ devino_cache_lookup (OstreeRepo *self, * @cancellable: Cancellable * @error: Error * - * When ostree builds a mutable tree from directory like in - * ostree_repo_write_directory_to_mtree(), it has to scan all files that you - * pass in and compute their checksums. If your commit contains hardlinks from - * ostree's existing repo, ostree can build a mapping of device numbers and - * inodes to their checksum. + * This function is deprecated in favor of using ostree_repo_devino_cache_new(), + * which allows a precise mapping to be built up between hardlink checkout files + * and their checksums between `ostree_repo_checkout_at()` and + * `ostree_repo_write_directory_to_mtree()`. + * + * When invoking ostree_repo_write_directory_to_mtree(), it has to compute the + * checksum of all files. If your commit contains hardlinks from a checkout, + * this functions builds a mapping of device numbers and inodes to their + * checksum. * * There is an upfront cost to creating this mapping, as this will scan the * entire objects directory. If your commit is composed of mostly hardlinks to * existing ostree objects, then this will speed up considerably, so call it - * before you call ostree_write_directory_to_mtree() or similar. + * before you call ostree_write_directory_to_mtree() or similar. However, + * ostree_repo_devino_cache_new() is better as it avoids scanning all objects. */ gboolean ostree_repo_scan_hardlinks (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_return_val_if_fail (self->in_transaction == TRUE, FALSE); if (!self->loose_object_devino_hash) self->loose_object_devino_hash = (GHashTable*)ostree_repo_devino_cache_new (); g_hash_table_remove_all (self->loose_object_devino_hash); - if (!scan_loose_devino (self, self->loose_object_devino_hash, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return scan_loose_devino (self, self->loose_object_devino_hash, cancellable, error); } /** From db6135f5b3a27fa06116568f769d96c62af78b62 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 21:30:13 -0400 Subject: [PATCH 50/83] lib/pull: Only look for cookie files for non-local remotes Just noticed this while reading an strace. Closes: https://github.com/ostreedev/ostree/issues/1139 Closes: #1145 Approved by: jlebon --- src/libostree/ostree-repo-pull.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index d233b384..4a2a0fcd 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -2743,18 +2743,19 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self, _ostree_fetcher_set_proxy (fetcher, http_proxy); } - { - g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); - /* TODO; port away from this; a bit hard since both libsoup and libcurl - * expect a file. Doing ot_fdrel_to_gfile() works for now though. - */ - GFile*repo_path = ostree_repo_get_path (self); - g_autofree char *jar_path = - g_build_filename (gs_file_get_path_cached (repo_path), cookie_file, NULL); + if (!_ostree_repo_remote_name_is_file (remote_name)) + { + g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); + /* TODO; port away from this; a bit hard since both libsoup and libcurl + * expect a file. Doing ot_fdrel_to_gfile() works for now though. + */ + GFile*repo_path = ostree_repo_get_path (self); + g_autofree char *jar_path = + g_build_filename (gs_file_get_path_cached (repo_path), cookie_file, NULL); - if (g_file_test (jar_path, G_FILE_TEST_IS_REGULAR)) - _ostree_fetcher_set_cookie_jar (fetcher, jar_path); - } + if (g_file_test (jar_path, G_FILE_TEST_IS_REGULAR)) + _ostree_fetcher_set_cookie_jar (fetcher, jar_path); + } success = TRUE; From ea4d3d1ac4e7f8530ef742928a576f5c69e8e506 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 21:44:09 -0400 Subject: [PATCH 51/83] lib/pull: A bit of new style porting A lof of the functions here are async and have nontrivial exits, but these ones are all sync were straightforward ports. Not prep for anything, just chipping away at porting. Closes: #1146 Approved by: jlebon --- src/libostree/ostree-repo-pull.c | 120 +++++++++++-------------------- 1 file changed, 42 insertions(+), 78 deletions(-) diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 4a2a0fcd..92aeb5bc 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -1588,6 +1588,9 @@ verify_bindings (OtPullData *pull_data, return TRUE; } +/* Look at a commit object, and determine whether there are + * more things to fetch. + */ static gboolean scan_commit_object (OtPullData *pull_data, const char *checksum, @@ -1596,19 +1599,8 @@ scan_commit_object (OtPullData *pull_data, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - /* If we found a legacy transaction flag, assume we have to scan. - * We always do a scan of dirtree objects; see - * https://github.com/ostreedev/ostree/issues/543 - */ - OstreeRepoCommitState commitstate; - g_autoptr(GVariant) commit = NULL; - g_autoptr(GVariant) parent_csum = NULL; - const guchar *parent_csum_bytes = NULL; gpointer depthp; gint depth; - gboolean is_partial; - if (g_hash_table_lookup_extended (pull_data->commit_to_depth, checksum, NULL, &depthp)) { @@ -1631,20 +1623,23 @@ scan_commit_object (OtPullData *pull_data, cancellable, error); if (!process_verify_result (pull_data, checksum, result, error)) - goto out; + return FALSE; } + /* If we found a legacy transaction flag, assume we have to scan. + * We always do a scan of dirtree objects; see + * https://github.com/ostreedev/ostree/issues/543 + */ + OstreeRepoCommitState commitstate; + g_autoptr(GVariant) commit = NULL; if (!ostree_repo_load_commit (pull_data->repo, checksum, &commit, &commitstate, error)) - goto out; + return FALSE; /* If ref is non-NULL then the commit we fetched was requested through the * branch, otherwise we requested a commit checksum without specifying a branch. */ if (!verify_bindings (pull_data, commit, ref, error)) - { - g_prefix_error (error, "Commit %s: ", checksum); - goto out; - } + return glnx_prefix_error (error, "Commit %s", checksum); if (pull_data->timestamp_check) { @@ -1661,28 +1656,27 @@ scan_commit_object (OtPullData *pull_data, { if (!ostree_repo_load_commit (pull_data->repo, orig_rev, &orig_commit, NULL, error)) - { - g_prefix_error (error, "Reading %s for timestamp-check: ", ref->ref_name); - goto out; - } + return glnx_prefix_error (error, "Reading %s for timestamp-check", ref->ref_name); guint64 orig_ts = ostree_commit_get_timestamp (orig_commit); guint64 new_ts = ostree_commit_get_timestamp (commit); if (!_ostree_compare_timestamps (orig_rev, orig_ts, checksum, new_ts, error)) - goto out; + return FALSE; } } /* If we found a legacy transaction flag, assume all commits are partial */ - is_partial = commitstate_is_partial (pull_data, commitstate); + gboolean is_partial = commitstate_is_partial (pull_data, commitstate); /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */ + g_autoptr(GVariant) parent_csum = NULL; + const guchar *parent_csum_bytes = NULL; g_variant_get_child (commit, 1, "@ay", &parent_csum); if (g_variant_n_children (parent_csum) > 0) { parent_csum_bytes = ostree_checksum_bytes_peek_validate (parent_csum, error); if (parent_csum_bytes == NULL) - goto out; + return FALSE; } if (parent_csum_bytes != NULL && pull_data->maxdepth == -1) @@ -1698,7 +1692,7 @@ scan_commit_object (OtPullData *pull_data, int parent_depth; ostree_checksum_inplace_from_bytes (parent_csum_bytes, parent_checksum); - + if (g_hash_table_lookup_extended (pull_data->commit_to_depth, parent_checksum, NULL, &parent_depthp)) { @@ -1737,11 +1731,11 @@ scan_commit_object (OtPullData *pull_data, tree_contents_csum_bytes = ostree_checksum_bytes_peek_validate (tree_contents_csum, error); if (tree_contents_csum_bytes == NULL) - goto out; + return FALSE; tree_meta_csum_bytes = ostree_checksum_bytes_peek_validate (tree_meta_csum, error); if (tree_meta_csum_bytes == NULL) - goto out; + return FALSE; queue_scan_one_metadata_object_c (pull_data, tree_contents_csum_bytes, OSTREE_OBJECT_TYPE_DIR_TREE, "/", recursion_depth + 1, NULL); @@ -1750,9 +1744,7 @@ scan_commit_object (OtPullData *pull_data, OSTREE_OBJECT_TYPE_DIR_META, NULL, recursion_depth + 1, NULL); } - ret = TRUE; - out: - return ret; + return TRUE; } static void @@ -2532,22 +2524,11 @@ static gboolean validate_variant_is_csum (GVariant *csum, GError **error) { - gboolean ret = FALSE; - if (!g_variant_is_of_type (csum, G_VARIANT_TYPE ("ay"))) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid checksum variant of type '%s', expected 'ay'", - g_variant_get_type_string (csum)); - goto out; - } + return glnx_throw (error, "Invalid checksum variant of type '%s', expected 'ay'", + g_variant_get_type_string (csum)); - if (!ostree_validate_structureof_csum_v (csum, error)) - goto out; - - ret = TRUE; - out: - return ret; + return ostree_validate_structureof_csum_v (csum, error); } /* Load the summary from the cache if the provided .sig file is the same as the @@ -2560,27 +2541,19 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); - - glnx_fd_close int prev_fd = -1; - g_autoptr(GBytes) old_sig_contents = NULL; - if (self->cache_dir_fd == -1) return TRUE; + const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); + glnx_fd_close int prev_fd = -1; if (!ot_openat_ignore_enoent (self->cache_dir_fd, summary_cache_sig_file, &prev_fd, error)) - goto out; - + return FALSE; if (prev_fd < 0) - { - ret = TRUE; - goto out; - } + return TRUE; /* Note early return */ - old_sig_contents = glnx_fd_readall_bytes (prev_fd, cancellable, error); + g_autoptr(GBytes) old_sig_contents = glnx_fd_readall_bytes (prev_fd, cancellable, error); if (!old_sig_contents) - goto out; + return FALSE; if (g_bytes_compare (old_sig_contents, summary_sig) == 0) { @@ -2595,25 +2568,21 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self, if (errno == ENOENT) { (void) unlinkat (self->cache_dir_fd, summary_cache_sig_file, 0); - ret = TRUE; - goto out; + return TRUE; /* Note early return */ } - glnx_set_error_from_errno (error); - goto out; + return glnx_throw_errno_prefix (error, "openat(%s)", summary_cache_file); } summary_data = glnx_fd_readall_bytes (summary_fd, cancellable, error); if (!summary_data) - goto out; + return FALSE; *summary = summary_data; } - ret = TRUE; - - out: - return ret; + return TRUE; } +/* Replace the current summary+signature with new versions */ static gboolean _ostree_repo_cache_summary (OstreeRepo *self, const char *remote, @@ -2622,36 +2591,31 @@ _ostree_repo_cache_summary (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote); - const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); - if (self->cache_dir_fd == -1) return TRUE; if (!glnx_shutil_mkdir_p_at (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, 0775, cancellable, error)) - goto out; + return FALSE; + const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote); if (!glnx_file_replace_contents_at (self->cache_dir_fd, summary_cache_file, g_bytes_get_data (summary, NULL), g_bytes_get_size (summary), self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW, cancellable, error)) - goto out; + return FALSE; + const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); if (!glnx_file_replace_contents_at (self->cache_dir_fd, summary_cache_sig_file, g_bytes_get_data (summary_sig, NULL), g_bytes_get_size (summary_sig), self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return FALSE; + return TRUE; } static OstreeFetcher * From 3f476ac54705b31093e77f6dfb909effdec351af Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 6 Sep 2017 22:08:55 -0400 Subject: [PATCH 52/83] lib/commit: Add some error prefixing for txn commit/tmpdir To help debug this: https://lists.projectatomic.io/projectatomic-archives/atomic-devel/2017-September/msg00001.html Currently we just get: `error: Commit: unlinkat: Directory not empty` Closes: #1147 Approved by: jlebon --- src/libostree/ostree-repo-commit.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 960818c8..6a5ba9dd 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -1131,6 +1131,7 @@ rename_pending_loose_objects (OstreeRepo *self, GCancellable *cancellable, GError **error) { + GLNX_AUTO_PREFIX_ERROR ("rename pending", error); g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (self->commit_stagedir_fd, ".", FALSE, &dfd_iter, error)) @@ -1223,11 +1224,10 @@ cleanup_tmpdir (OstreeRepo *self, GCancellable *cancellable, GError **error) { + GLNX_AUTO_PREFIX_ERROR ("tmpdir cleanup", error); + const guint64 curtime_secs = g_get_real_time () / 1000000; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - guint64 curtime_secs; - - curtime_secs = g_get_real_time () / 1000000; - if (!glnx_dirfd_iterator_init_at (self->tmp_dir_fd, ".", TRUE, &dfd_iter, error)) return FALSE; @@ -1255,7 +1255,7 @@ cleanup_tmpdir (OstreeRepo *self, { if (errno == ENOENT) /* Did another cleanup win? */ continue; - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fstatat(%s)", dent->d_name); } /* First, if it's a directory which needs locking, but it's @@ -1282,7 +1282,7 @@ cleanup_tmpdir (OstreeRepo *self, * from *other* boots */ if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error)) - return FALSE; + return glnx_prefix_error (error, "Removing %s", dent->d_name); } /* FIXME - move OSTREE_REPO_TMPDIR_FETCHER underneath the * staging/boot-id scheme as well, since all of the "did it get @@ -1307,7 +1307,7 @@ cleanup_tmpdir (OstreeRepo *self, if (delta > self->tmp_expiry_seconds) { if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error)) - return FALSE; + return glnx_prefix_error (error, "Removing %s", dent->d_name); } } } From 1e3f87c34c2f51385aef5aafcdf55e60d42bf426 Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Thu, 7 Sep 2017 11:19:34 -0700 Subject: [PATCH 53/83] tests: Check "refs -c PREFIX" behavior This commit adds tests to check the behavior of "refs -c PREFIX", where prefix is interpreted as a collection ID. Closes: #1149 Approved by: cgwalters --- tests/test-refs-collections.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test-refs-collections.sh b/tests/test-refs-collections.sh index f36fd7b9..5e6b50d7 100755 --- a/tests/test-refs-collections.sh +++ b/tests/test-refs-collections.sh @@ -112,9 +112,16 @@ mkdir -p adir ${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir ${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" ${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit + ${CMD_PREFIX} ostree --repo=repo refs --collections > refs assert_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" +${CMD_PREFIX} ostree --repo=repo refs --collections org.example.RemoteCollection > refs +assert_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" + +${CMD_PREFIX} ostree --repo=repo refs --collections org.example.NonexistentID > refs +assert_not_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" + cd ${test_tmpdir} mkdir no-collection-repo ostree_repo_init no-collection-repo From 2d854368a8e6091ab4bc2ec223868b20c47b677d Mon Sep 17 00:00:00 2001 From: Robert McQueen Date: Thu, 3 Aug 2017 10:00:42 +0100 Subject: [PATCH 54/83] lib/gpg: Add _FINGERPRINT_PRIMARY to OstreeGpgVerifyResult Revert the switch of _FINGERPRINT to giving the primary key ID rather than the signing key ID, and instead add the primary key ID as a new attribute which is available if the key is not missing. Closes: https://github.com/ostreedev/ostree/issues/608 Closes: #1092 Approved by: cgwalters --- src/libostree/ostree-gpg-verify-result.c | 43 ++++++++++++++++++------ src/libostree/ostree-gpg-verify-result.h | 8 ++++- tests/test-gpg-verify-result.c | 2 +- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index 8b0c0b17..ad160bc9 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -63,7 +63,8 @@ static OstreeGpgSignatureAttr all_signature_attrs[] = { OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, - OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY }; static void ostree_gpg_verify_result_initable_iface_init (GInitableIface *iface); @@ -327,9 +328,9 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, * (OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING). */ for (ii = 0; ii < n_attrs; ii++) { - if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT || - attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || - attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL) + if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY) { (void) gpgme_get_key (result->context, signature->fpr, &key, 0); break; @@ -372,11 +373,7 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, break; case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT: - if (key != NULL && key->subkeys != NULL) - v_string = key->subkeys->fpr; - else - v_string = signature->fpr; - child = g_variant_new_string (v_string); + child = g_variant_new_string (signature->fpr); break; case OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP: @@ -417,6 +414,14 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, child = g_variant_new_string (v_string); break; + case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY: + if (key != NULL && key->subkeys != NULL) + v_string = key->subkeys->fpr; + if (v_string == NULL) + v_string = ""; + child = g_variant_new_string (v_string); + break; + default: g_critical ("Invalid signature attribute (%d)", attrs[ii]); g_variant_builder_clear (&builder); @@ -534,6 +539,7 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, gint64 exp_timestamp; const char *type_string; const char *fingerprint; + const char *fingerprint_primary; const char *pubkey_algo; const char *user_name; const char *user_email; @@ -549,7 +555,7 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, /* Verify the variant's type string. This code is * not prepared to handle just any random GVariant. */ type_string = g_variant_get_type_string (variant); - g_return_if_fail (strcmp (type_string, "(bbbbbsxxssss)") == 0); + g_return_if_fail (strcmp (type_string, "(bbbbbsxxsssss)") == 0); /* The default format roughly mimics the verify output generated by * check_sig_and_print() in gnupg/g10/mainproc.c, though obviously @@ -563,6 +569,8 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, "b", &key_missing); g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, "&s", &fingerprint); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, + "&s", &fingerprint_primary); g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, "x", ×tamp); g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, @@ -627,6 +635,21 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, user_name, user_email); } + if (!key_missing && (g_strcmp0 (fingerprint, fingerprint_primary) != 0)) + { + const char *key_id_primary; + + len = strlen (fingerprint_primary); + key_id_primary = (len > 16) ? fingerprint_primary + len - 16 : + fingerprint_primary; + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + g_string_append_printf (output_buffer, + "Primary key ID %s\n", key_id_primary); + } + if (exp_timestamp > 0) { date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); diff --git a/src/libostree/ostree-gpg-verify-result.h b/src/libostree/ostree-gpg-verify-result.h index f5fadd59..3064ed8e 100644 --- a/src/libostree/ostree-gpg-verify-result.h +++ b/src/libostree/ostree-gpg-verify-result.h @@ -64,6 +64,11 @@ typedef struct OstreeGpgVerifyResult OstreeGpgVerifyResult; * @OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL: * [#G_VARIANT_TYPE_STRING] The email address of the signing key's primary * user + * @OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY: + * [#G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key + * (will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the + * the signature is already from the primary key rather than a subkey, + * and will be the empty string if the key is missing.) * * Signature attributes available from an #OstreeGpgVerifyResult. * The attribute's #GVariantType is shown in brackets. @@ -80,7 +85,8 @@ typedef enum { OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, - OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, } OstreeGpgSignatureAttr; _OSTREE_PUBLIC diff --git a/tests/test-gpg-verify-result.c b/tests/test-gpg-verify-result.c index 62b05e33..6d11fac6 100644 --- a/tests/test-gpg-verify-result.c +++ b/tests/test-gpg-verify-result.c @@ -173,7 +173,7 @@ test_attribute_basics (TestFixture *fixture, tuple = ostree_gpg_verify_result_get_all (fixture->result, ii); type_string = g_variant_get_type_string (tuple); - g_assert_cmpstr (type_string, ==, "(bbbbbsxxssss)"); + g_assert_cmpstr (type_string, ==, "(bbbbbsxxsssss)"); /* Check attributes which should be common to all signatures. */ From 6b6408a7d0e3826a26e18529e13f88c5ce5912f4 Mon Sep 17 00:00:00 2001 From: Robert McQueen Date: Thu, 3 Aug 2017 10:23:39 +0100 Subject: [PATCH 55/83] lib/gpg: Correct missing line prefix with bad signatures In the case the signature time was bad, a line prefix was missing from the result of `ostree_gpg_verify_result_describe_variant()`. Closes: #1092 Approved by: cgwalters --- src/libostree/ostree-gpg-verify-result.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index ad160bc9..5be6b2e1 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -652,6 +652,9 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, if (exp_timestamp > 0) { + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); if (date_time_utc == NULL) { @@ -664,9 +667,6 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, date_time_local = g_date_time_to_local (date_time_utc); formatted_date_time = g_date_time_format (date_time_local, "%c"); - if (line_prefix != NULL) - g_string_append (output_buffer, line_prefix); - if (sig_expired) { g_string_append_printf (output_buffer, From 59dff7175eb3f8befec1c5d7532a36d8d5633873 Mon Sep 17 00:00:00 2001 From: Robert McQueen Date: Thu, 3 Aug 2017 10:54:33 +0100 Subject: [PATCH 56/83] lib/gpg: Provide the public key to the duplicate check Add keys from the signing homedir to the GpgVerifier used to look for duplicate signatures. This will allow signatures from subkeys to be canonicalised and recognised as already signed despite the differing key ID, avoiding duplicate signatures. Closes: https://github.com/ostreedev/ostree/issues/608 Closes: #1092 Approved by: cgwalters --- src/libostree/ostree-repo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index e7807d11..7ad2019e 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -4261,11 +4261,14 @@ ostree_repo_sign_commit (OstreeRepo *self, /* The verify operation is merely to parse any existing signatures to * check if the commit has already been signed with the given key ID. - * We want to avoid storing duplicate signatures in the metadata. */ + * We want to avoid storing duplicate signatures in the metadata. We + * pass the homedir so that the signing key can be imported, allowing + * subkey signatures to be recognised. */ g_autoptr(GError) local_error = NULL; + g_autoptr(GFile) verify_keydir = g_file_new_for_path (homedir); g_autoptr(OstreeGpgVerifyResult) result =_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata, - NULL, NULL, NULL, + NULL, verify_keydir, NULL, cancellable, &local_error); if (!result) { From 7afa966198eb783a8fb4177ff71f9e8a6e23856c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 7 Sep 2017 12:11:55 -0400 Subject: [PATCH 57/83] lib/sysroot: Use fd-relative acccess for bootversion cleanup I noticed this was an easy change. Closes: #1148 Approved by: peterbaouoft --- src/libostree/ostree-sysroot-cleanup.c | 44 +++++++++++--------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index de313930..d689f02e 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -210,35 +210,29 @@ cleanup_other_bootversions (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - int cleanup_bootversion = self->bootversion == 0 ? 1 : 0; - int cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; + const int cleanup_bootversion = self->bootversion == 0 ? 1 : 0; + const int cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; + /* Reusable buffer for path */ + g_autoptr(GString) buf = g_string_new (""); - g_autoptr(GFile) cleanup_boot_dir = NULL; - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) + /* These directories are for the other major version */ + g_string_truncate (buf, 0); g_string_append_printf (buf, "boot/loader.%d", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.0", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.1", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) return FALSE; - g_clear_object (&cleanup_boot_dir); - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) + /* And finally the other subbootversion */ + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) return FALSE; - g_clear_object (&cleanup_boot_dir); - - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.0", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - return FALSE; - g_clear_object (&cleanup_boot_dir); - - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.1", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - return FALSE; - g_clear_object (&cleanup_boot_dir); - - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion, - cleanup_subbootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - return FALSE; - g_clear_object (&cleanup_boot_dir); return TRUE; } From c7d0be4fbaf3617b485c53f91acb7b2677641f37 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 7 Sep 2017 15:03:24 -0400 Subject: [PATCH 58/83] tree-wide: Add error prefixing for most remaining syscalls There were some important ones there like a random `syncfs()`. The remaining users are mostly blocked on the "fstatat enoent" case, I'll wait to port those. Closes: #1150 Approved by: jlebon --- src/libostree/ostree-repo-commit.c | 6 +++--- src/libostree/ostree-repo.c | 16 ++++++++-------- src/libostree/ostree-sepolicy.c | 2 +- src/libostree/ostree-sysroot-deploy.c | 4 ++-- src/libostree/ostree-sysroot.c | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 6a5ba9dd..5d28dca8 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -1534,7 +1534,7 @@ ostree_repo_commit_transaction (OstreeRepo *self, if (g_getenv ("OSTREE_SUPPRESS_SYNCFS") == NULL) { if (syncfs (self->tmp_dir_fd) < 0) - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "syncfs"); } if (!rename_pending_loose_objects (self, cancellable, error)) @@ -2798,8 +2798,8 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self, OstreeRepoCommitFilterResult filter_result; struct stat dir_stbuf; - if (fstat (src_dfd_iter->fd, &dir_stbuf) != 0) - return glnx_throw_errno (error); + if (!glnx_fstat (src_dfd_iter->fd, &dir_stbuf, error)) + return FALSE; child_info = _ostree_stbuf_to_gfileinfo (&dir_stbuf); diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 7ad2019e..6971d9b4 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1129,8 +1129,8 @@ impl_repo_remote_delete (OstreeRepo *self, if (remote->file != NULL) { - if (unlink (gs_file_get_path_cached (remote->file)) != 0) - return glnx_throw_errno (error); + if (!glnx_unlinkat (AT_FDCWD, gs_file_get_path_cached (remote->file), 0, error)) + return FALSE; } else { @@ -2362,8 +2362,8 @@ ostree_repo_open (OstreeRepo *self, /* Note - we don't return this error yet! */ } - if (fstat (self->objects_dir_fd, &stbuf) != 0) - return glnx_throw_errno (error); + if (!glnx_fstat (self->objects_dir_fd, &stbuf, error)) + return FALSE; self->owner_uid = stbuf.st_uid; if (stbuf.st_uid != getuid () || stbuf.st_gid != getgid ()) @@ -2749,8 +2749,8 @@ load_metadata_internal (OstreeRepo *self, if (fd != -1) { - if (fstat (fd, &stbuf) < 0) - return glnx_throw_errno (error); + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; if (out_variant) { @@ -3173,7 +3173,7 @@ _ostree_repo_has_loose_object (OstreeRepo *self, if (errno == ENOENT) ; /* Next dfd */ else - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fstatat(%s)", loose_path_buf); } else { @@ -3696,7 +3696,7 @@ ostree_repo_load_commit (OstreeRepo *self, } else if (errno != ENOENT) { - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fstatat(%s)", commitpartial_path); } } diff --git a/src/libostree/ostree-sepolicy.c b/src/libostree/ostree-sepolicy.c index 6012d9da..64670092 100644 --- a/src/libostree/ostree-sepolicy.c +++ b/src/libostree/ostree-sepolicy.c @@ -521,7 +521,7 @@ ostree_sepolicy_get_label (OstreeSePolicy *self, if (errno == ENOENT) *out_label = NULL; else - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "selabel_lookup"); } else { diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index f50f2457..62ebd6b6 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -171,8 +171,8 @@ copy_dir_recurse (int src_parent_dfd, return FALSE; /* Create with mode 0700, we'll fchmod/fchown later */ - if (mkdirat (dest_parent_dfd, name, 0700) != 0) - return glnx_throw_errno (error); + if (!glnx_ensure_dir (dest_parent_dfd, name, 0700, error)) + return FALSE; if (!glnx_opendirat (dest_parent_dfd, name, TRUE, &dest_dfd, error)) return FALSE; diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 8e6c475c..e8e299fe 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -471,8 +471,8 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, if (dent == NULL) break; - if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0) != 0) - return glnx_throw_errno (error); + if (!glnx_fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0, error)) + return FALSE; if (g_str_has_prefix (dent->d_name, "ostree-") && g_str_has_suffix (dent->d_name, ".conf") && From a567b5b47bb2d32d16d202db0d5fbe4035a0e086 Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Tue, 5 Sep 2017 12:03:52 +0300 Subject: [PATCH 59/83] uboot: move system uEnv merge to new function, clean up Split the code that merge the system uEnv to new function. While we're here, clean up the logic to e.g. use `ot_openat_ignore_enoent()`. Closes: #1138 Approved by: cgwalters --- src/libostree/ostree-bootloader-uboot.c | 74 +++++++++++++------------ 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c index 81ea95a6..2fe0f8b6 100644 --- a/src/libostree/ostree-bootloader-uboot.c +++ b/src/libostree/ostree-bootloader-uboot.c @@ -62,6 +62,44 @@ _ostree_bootloader_uboot_get_name (OstreeBootloader *bootloader) return "U-Boot"; } +/* Append system's uEnv.txt, if it exists in $deployment/usr/lib/ostree-boot/ */ +static gboolean +append_system_uenv (OstreeBootloaderUboot *self, + const char *bootargs, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) +{ + glnx_fd_close int uenv_fd = -1; + __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; + const char *uenv_path = NULL; + const char *ostree_arg = NULL; + + kargs = _ostree_kernel_args_from_string (bootargs); + ostree_arg = _ostree_kernel_args_get_last_value (kargs, "ostree"); + if (!ostree_arg) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No ostree= kernel argument found in boot loader configuration file"); + return FALSE; + } + ostree_arg += 1; + uenv_path = glnx_strjoina (ostree_arg, "/usr/lib/ostree-boot/uEnv.txt"); + if (!ot_openat_ignore_enoent (self->sysroot->sysroot_fd, uenv_path, &uenv_fd, error)) + return FALSE; + if (uenv_fd != -1) + { + char *uenv = glnx_fd_readall_utf8 (uenv_fd, NULL, cancellable, error); + if (!uenv) + { + g_prefix_error (error, "Reading %s: ", uenv_path); + return FALSE; + } + g_ptr_array_add (new_lines, uenv); + } + return TRUE; +} + static gboolean create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, int bootversion, @@ -96,43 +134,9 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, val = ostree_bootconfig_parser_get (config, "options"); if (val) { - glnx_fd_close int uenv_fd = -1; - __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; - const char *uenv_path = NULL; - const char *ostree_arg = NULL; - g_ptr_array_add (new_lines, g_strdup_printf ("bootargs=%s", val)); - - /* Append system's uEnv.txt, if it exists in $deployment/usr/lib/ostree-boot/ */ - kargs = _ostree_kernel_args_from_string (val); - ostree_arg = _ostree_kernel_args_get_last_value (kargs, "ostree"); - if (!ostree_arg) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No ostree= kernel argument found in boot loader configuration file"); + if (!append_system_uenv (self, val, new_lines, cancellable, error)) return FALSE; - } - ostree_arg += 1; - uenv_path = glnx_strjoina (ostree_arg, "/usr/lib/ostree-boot/uEnv.txt"); - uenv_fd = openat (self->sysroot->sysroot_fd, uenv_path, O_CLOEXEC | O_RDONLY); - if (uenv_fd != -1) - { - char *uenv = glnx_fd_readall_utf8 (uenv_fd, NULL, cancellable, error); - if (!uenv) - { - g_prefix_error (error, "Reading %s: ", uenv_path); - return FALSE; - } - g_ptr_array_add (new_lines, uenv); - } - else - { - if (errno != ENOENT) - { - g_prefix_error (error, "openat %s: ", uenv_path); - return FALSE; - } - } } return TRUE; From 2a7fdfdbc578eb704476f0fa734eff55864e74f2 Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Tue, 5 Sep 2017 15:59:35 +0300 Subject: [PATCH 60/83] uboot: add non-default deployments to uEnv.txt Include non-default deployments in the uEnv.txt file imported by U-Boot. All the configurations beside the defaults will have numerical suffix E.G. "kernel_image2" or "bootargs2". Those U-Boot environment variables may be used from interactive boot prompt or from "altbootcmd" script. Closes: #1138 Approved by: cgwalters --- src/libostree/ostree-bootloader-uboot.c | 46 +++++++++++++++---------- tests/test-admin-deploy-uboot.sh | 2 ++ 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c index 2fe0f8b6..ce5d516c 100644 --- a/src/libostree/ostree-bootloader-uboot.c +++ b/src/libostree/ostree-bootloader-uboot.c @@ -115,28 +115,36 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, cancellable, error)) return FALSE; - /* U-Boot doesn't support a menu so just pick the first one since the list is ordered */ - config = boot_loader_configs->pdata[0]; - - val = ostree_bootconfig_parser_get (config, "linux"); - if (!val) + for (int i = 0; i < boot_loader_configs->len; i++) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No \"linux\" key in bootloader config"); - return FALSE; - } - g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image=%s", val)); + g_autofree char *index_suffix = NULL; + if (i == 0) + index_suffix = g_strdup (""); + else + index_suffix = g_strdup_printf ("%d", i+1); + config = boot_loader_configs->pdata[i]; - val = ostree_bootconfig_parser_get (config, "initrd"); - if (val) - g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image=%s", val)); + val = ostree_bootconfig_parser_get (config, "linux"); + if (!val) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"linux\" key in bootloader config"); + return FALSE; + } + g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%s", index_suffix, val)); - val = ostree_bootconfig_parser_get (config, "options"); - if (val) - { - g_ptr_array_add (new_lines, g_strdup_printf ("bootargs=%s", val)); - if (!append_system_uenv (self, val, new_lines, cancellable, error)) - return FALSE; + val = ostree_bootconfig_parser_get (config, "initrd"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=%s", index_suffix, val)); + + val = ostree_bootconfig_parser_get (config, "options"); + if (val) + { + g_ptr_array_add (new_lines, g_strdup_printf ("bootargs%s=%s", index_suffix, val)); + if (i == 0) + if (!append_system_uenv (self, val, new_lines, cancellable, error)) + return FALSE; + } } return TRUE; diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index f04af4ab..7791360e 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -42,5 +42,7 @@ ${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buil ${CMD_PREFIX} ostree admin upgrade --os=testos assert_file_has_content sysroot/boot/uEnv.txt "loadfdt=" assert_file_has_content sysroot/boot/uEnv.txt "kernel_image=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image2=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image3=" echo "ok merging uEnv.txt files" From 43c78c90066d855ce44409f5a960385dc60577f4 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Thu, 7 Sep 2017 14:02:51 -0500 Subject: [PATCH 61/83] repo: Fix non-system remotes-config-dir usage Before commit e0346c1, a non-system repo could specify remotes-config-dir and have remotes read from there. However, adding remotes would only be done in the config dir for a system repo. Restore that by respecting remotes-config-dir when no sysroot is found and adding back the ostree_repo_is_system() check when adding remotes. Closes: #1133 Closes: #1151 Approved by: cgwalters --- Makefile-tests.am | 1 + src/libostree/ostree-repo.c | 23 ++++++---- tests/test-remotes-config-dir.js | 73 ++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100755 tests/test-remotes-config-dir.js diff --git a/Makefile-tests.am b/Makefile-tests.am index 82ce7209..6a52faeb 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -186,6 +186,7 @@ endif js_installed_tests = \ tests/test-core.js \ + tests/test-remotes-config-dir.js \ tests/test-sizes.js \ tests/test-sysroot.js \ $(NULL) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 6971d9b4..93c6d62d 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1010,8 +1010,11 @@ impl_repo_remote_add (OstreeRepo *self, remote = ostree_remote_new (name); + /* Only add repos in remotes.d for system repos since that was the + * legacy behavior and non-system repos would not expect it. + */ g_autoptr(GFile) etc_ostree_remotes_d = get_remotes_d_dir (self, sysroot); - if (etc_ostree_remotes_d) + if (etc_ostree_remotes_d && ostree_repo_is_system (self)) { g_autoptr(GError) local_error = NULL; @@ -2040,10 +2043,6 @@ static GFile * get_remotes_d_dir (OstreeRepo *self, GFile *sysroot) { - /* Support explicit override */ - if (self->sysroot_dir != NULL && self->remotes_config_dir != NULL) - return g_file_resolve_relative_path (self->sysroot_dir, self->remotes_config_dir); - g_autoptr(GFile) sysroot_owned = NULL; /* Very complicated sysroot logic; this bit breaks the otherwise mostly clean * layering between OstreeRepo and OstreeSysroot. First, If a sysroot was @@ -2079,10 +2078,18 @@ get_remotes_d_dir (OstreeRepo *self, if (sysroot == NULL && sysroot_ref == NULL) sysroot = self->sysroot_dir; - /* Did we find a sysroot? If not, NULL means use the repo config, otherwise - * return the path in /etc. + /* Was the config directory specified? If so, use that with the + * optional sysroot prepended. If not, return the path in /etc if the + * sysroot was found and NULL otherwise to use the repo config. */ - if (sysroot == NULL) + if (self->remotes_config_dir != NULL) + { + if (sysroot == NULL) + return g_file_new_for_path (self->remotes_config_dir); + else + return g_file_resolve_relative_path (sysroot, self->remotes_config_dir); + } + else if (sysroot == NULL) return NULL; else return g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES); diff --git a/tests/test-remotes-config-dir.js b/tests/test-remotes-config-dir.js new file mode 100755 index 00000000..9de8f01a --- /dev/null +++ b/tests/test-remotes-config-dir.js @@ -0,0 +1,73 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2013 Colin Walters +// Copyright (C) 2017 Dan Nicholson +// +// 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. + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +function assertEquals(a, b) { + if (a != b) + throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b)); +} + +function assertNotEquals(a, b) { + if (a == b) + throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b)); +} + +print('1..3') + +let remotesDir = Gio.File.new_for_path('remotes.d'); +remotesDir.make_directory(null); + +let remoteConfig = GLib.KeyFile.new() +remoteConfig.set_value('remote "foo"', 'url', 'http://foo') + +let remoteConfigFile = remotesDir.get_child('foo.conf') +remoteConfig.save_to_file(remoteConfigFile.get_path()) + +// Use the full Repo constructor to set remotes-config-dir +let repoFile = Gio.File.new_for_path('repo'); +let repo = new OSTree.Repo({path: repoFile, + remotes_config_dir: remotesDir.get_path()}); +repo.create(OSTree.RepoMode.ARCHIVE_Z2, null); +repo.open(null); + +// See if the remotes.d remote exists +let remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('foo'), -1); + +print("ok read-remotes-config-dir"); + +// Adding a remote should not go in the remotes.d dir +repo.remote_add('bar', 'http://bar', null, null); +remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('bar'), -1); +assertEquals(remotesDir.get_child('bar.conf').query_exists(null), false); + +print("ok add-not-in-remotes-config-dir"); + +// Removing the remotes.d remote should delete the conf file +repo.remote_delete('foo', null); +remotes = repo.remote_list() +assertEquals(remotes.indexOf('foo'), -1); +assertEquals(remotesDir.get_child('foo.conf').query_exists(null), false); + +print("ok delete-in-remotes-config-dir"); From 6be4dfe66e713cf9dea32fb8df551c4e8b62d39c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 7 Sep 2017 21:46:10 -0400 Subject: [PATCH 62/83] lib/grub2: Port some to new code style I resisted trying to do anything invasive here like fd-relative porting as our coverage is weak. But this was all straightforward porting to decl-after-stmt style. Closes: #1153 Approved by: jlebon --- src/libostree/ostree-bootloader-grub2.c | 127 +++++++++++------------- 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/src/libostree/ostree-bootloader-grub2.c b/src/libostree/ostree-bootloader-grub2.c index ff83f151..d917281c 100644 --- a/src/libostree/ostree-bootloader-grub2.c +++ b/src/libostree/ostree-bootloader-grub2.c @@ -75,18 +75,17 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); - g_autoptr(GFile) efi_basedir = NULL; + /* Look for the BIOS path first */ if (g_file_query_exists (self->config_path_bios, NULL)) { + /* If we found it, we're done */ *out_is_active = TRUE; - ret = TRUE; - goto out; + return TRUE; } - efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); + g_autoptr(GFile) efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); g_clear_object (&self->config_path_efi); @@ -98,17 +97,16 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) - goto out; + return FALSE; while (TRUE) { GFileInfo *file_info; const char *fname; - g_autofree char *subdir_grub_cfg = NULL; if (!g_file_enumerator_iterate (direnum, &file_info, NULL, cancellable, error)) - goto out; + return FALSE; if (file_info == NULL) break; @@ -119,8 +117,9 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; - subdir_grub_cfg = g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); - + g_autofree char *subdir_grub_cfg = + g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); + if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS)) { self->config_path_efi = g_file_new_for_path (subdir_grub_cfg); @@ -128,20 +127,18 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, } } + /* If we found the EFI path, we're done */ if (self->config_path_efi) { self->is_efi = TRUE; *out_is_active = TRUE; - ret = TRUE; - goto out; + return TRUE; } } else *out_is_active = FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } static const char * @@ -150,6 +147,10 @@ _ostree_bootloader_grub2_get_name (OstreeBootloader *bootloader) return "grub2"; } +/* This implementation is quite complex; see this issue for + * a starting point: + * https://github.com/ostreedev/ostree/issues/717 + */ gboolean _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot, int bootversion, @@ -157,13 +158,6 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GString) output = g_string_new (""); - g_autoptr(GOutputStream) out_stream = NULL; - g_autoptr(GPtrArray) loader_configs = NULL; - guint i; - gsize bytes_written; - gboolean is_efi; /* So... yeah. Just going to hardcode these. */ static const char hardcoded_video[] = "load_video\n" "set gfxpayload=keep\n"; @@ -178,16 +172,18 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot g_assert (grub2_prepare_root_cache != NULL); /* Passed from the parent */ - is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL; + gboolean is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL; - out_stream = g_unix_output_stream_new (target_fd, FALSE); + g_autoptr(GOutputStream) out_stream = g_unix_output_stream_new (target_fd, FALSE); + g_autoptr(GPtrArray) loader_configs = NULL; if (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion, &loader_configs, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < loader_configs->len; i++) + g_autoptr(GString) output = g_string_new (""); + for (guint i = 0; i < loader_configs->len; i++) { OstreeBootconfigParser *config = loader_configs->pdata[i]; const char *title; @@ -217,13 +213,9 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot g_string_append (output, hardcoded_insmods); g_string_append (output, grub2_prepare_root_cache); g_string_append_c (output, '\n'); - + if (!kernel) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No \"linux\" key in bootloader config"); - goto out; - } + return glnx_throw (error, "No \"linux\" key in bootloader config"); g_string_append (output, "linux"); if (is_efi) g_string_append (output, GRUB2_EFI_SUFFIX); @@ -256,13 +248,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot g_string_append (output, "}\n"); } + gsize bytes_written; if (!g_output_stream_write_all (out_stream, output->str, output->len, &bytes_written, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } typedef struct { @@ -271,19 +262,24 @@ typedef struct { gboolean is_efi; } Grub2ChildSetupData; +/* Post-fork, pre-exec child setup for grub2-mkconfig */ static void grub2_child_setup (gpointer user_data) { Grub2ChildSetupData *cdata = user_data; setenv ("_OSTREE_GRUB2_BOOTVERSION", cdata->bootversion_str, TRUE); - /* We have to pass our state to the child */ + /* We have to pass our state (whether or not we're using EFI) to the child */ if (cdata->is_efi) setenv ("_OSTREE_GRUB2_IS_EFI", "1", TRUE); + /* Everything below this is dealing with the chroot case; if + * we're not doing that, return early. + */ if (!cdata->root) return; + /* TODO: investigate replacing this with bwrap */ if (chdir (cdata->root) != 0) { perror ("chdir"); @@ -321,6 +317,7 @@ grub2_child_setup (gpointer user_data) } } +/* Main entrypoint for writing GRUB configuration. */ static gboolean _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, int bootversion, @@ -328,23 +325,13 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, GError **error) { OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); - gboolean ret = FALSE; - g_autoptr(GFile) new_config_path = NULL; - g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion); - g_autoptr(GFile) config_path_efi_dir = NULL; - g_autofree char *grub2_mkconfig_chroot = NULL; - gboolean use_system_grub2_mkconfig = TRUE; - const gchar *grub_exec = NULL; - const char *grub_argv[4] = { NULL, "-o", NULL, NULL}; - GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH; - int grub2_estatus; - Grub2ChildSetupData cdata = { NULL, }; + /* Autotests can set this envvar to select which code path to test, useful for OS installers as well */ + gboolean use_system_grub2_mkconfig = TRUE; #ifdef USE_BUILTIN_GRUB2_MKCONFIG use_system_grub2_mkconfig = FALSE; #endif - /* Autotests can set this envvar to select which code path to test, useful for OS installers as well */ - grub_exec = g_getenv ("OSTREE_GRUB2_EXEC"); + const gchar *grub_exec = g_getenv ("OSTREE_GRUB2_EXEC"); if (grub_exec) { if (g_str_has_suffix (grub_exec, GRUB2_MKCONFIG_PATH)) @@ -355,6 +342,7 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, else grub_exec = use_system_grub2_mkconfig ? GRUB2_MKCONFIG_PATH : TARGET_PREFIX "/lib/ostree/ostree-grub-generator"; + g_autofree char *grub2_mkconfig_chroot = NULL; if (use_system_grub2_mkconfig && ostree_sysroot_get_booted_deployment (self->sysroot) == NULL && g_file_has_parent (self->sysroot->path, NULL)) { @@ -381,13 +369,15 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, grub2_mkconfig_chroot = g_file_get_path (tool_deployment_root); } + g_autoptr(GFile) new_config_path = NULL; + g_autoptr(GFile) config_path_efi_dir = NULL; if (self->is_efi) { config_path_efi_dir = g_file_get_parent (self->config_path_efi); new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new"); /* We use grub2-mkconfig to write to a temporary file first */ if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error)) - goto out; + return FALSE; } else { @@ -395,12 +385,16 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, bootversion); } + const char *grub_argv[4] = { NULL, "-o", NULL, NULL}; + Grub2ChildSetupData cdata = { NULL, }; grub_argv[0] = grub_exec; grub_argv[2] = gs_file_get_path_cached (new_config_path); + GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH; if (!g_getenv ("OSTREE_DEBUG_GRUB2")) grub_spawnflags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; cdata.root = grub2_mkconfig_chroot; + g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion); cdata.bootversion_str = bootversion_str; cdata.is_efi = self->is_efi; /* Note in older versions of the grub2 package, this script doesn't even try @@ -411,54 +405,47 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, Upstream is fixed though. */ + int grub2_estatus; if (!g_spawn_sync (NULL, (char**)grub_argv, NULL, grub_spawnflags, grub2_child_setup, &cdata, NULL, NULL, &grub2_estatus, error)) - goto out; + return FALSE; if (!g_spawn_check_exit_status (grub2_estatus, error)) { g_prefix_error (error, "%s: ", grub_argv[0]); - goto out; + return FALSE; } /* Now let's fdatasync() for the new file */ { glnx_fd_close int new_config_fd = -1; if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error)) - goto out; + return FALSE; if (fdatasync (new_config_fd) < 0) - { - (void)glnx_throw_errno_prefix (error, "fdatasync"); - goto out; - } + return glnx_throw_errno_prefix (error, "fdatasync"); } if (self->is_efi) { g_autoptr(GFile) config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old"); - + /* copy current to old */ if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error)) - goto out; + return FALSE; if (!g_file_copy (self->config_path_efi, config_path_efi_old, G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error)) - goto out; + return FALSE; /* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT; * see https://bugzilla.gnome.org/show_bug.cgi?id=724246 */ if (!ot_gfile_ensure_unlinked (self->config_path_efi, cancellable, error)) - goto out; + return FALSE; if (rename (gs_file_get_path_cached (new_config_path), gs_file_get_path_cached (self->config_path_efi)) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "rename"); } - - ret = TRUE; - out: - return ret; + + return TRUE; } static gboolean From 3594bb2d0f6818a97adc95655bd136267e27fe4c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Sep 2017 15:43:04 -0400 Subject: [PATCH 63/83] lib: Add a private helper to abort txns, use in sysroot cleanup Steal some code from flatpak for this, which allows porting a few more things to new style. I started on a public API version of this but was trying to roll some other things into it and it snowballed. Let's do this version since it's easy for now. While here I changed things so that `generate_deployment_refs()` now just uses `_set_ref_immediate()` rather than requring a txn. Also, AFAICS there was no test coverage of `generate_deployment_refs()`; I tried commenting it out and at least `admin-test.sh` passed. Add some coverage of this - I verified that with this commenting out bits of that function cause the test to fail. Closes: #1132 Approved by: jlebon --- src/libostree/ostree-repo-private.h | 21 +++++++++ src/libostree/ostree-sysroot-cleanup.c | 62 ++++++++++---------------- tests/admin-test.sh | 15 ++++++- 3 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 121c2d52..fdcd8f3f 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -158,6 +158,27 @@ struct OstreeRepo { OstreeRepo *parent_repo; }; +/* Taken from flatpak; may be made into public API later */ +typedef OstreeRepo _OstreeRepoAutoTransaction; +static inline void +_ostree_repo_auto_transaction_cleanup (void *p) +{ + OstreeRepo *repo = p; + if (repo) + (void) ostree_repo_abort_transaction (repo, NULL, NULL); +} + +static inline _OstreeRepoAutoTransaction * +_ostree_repo_auto_transaction_start (OstreeRepo *repo, + GCancellable *cancellable, + GError **error) +{ + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + return NULL; + return (_OstreeRepoAutoTransaction *)repo; +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (_OstreeRepoAutoTransaction, _ostree_repo_auto_transaction_cleanup) + typedef struct { dev_t dev; ino_t ino; diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index d689f02e..da239c78 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -21,6 +21,7 @@ #include "config.h" #include "otutil.h" +#include "ostree-repo-private.h" #include "ostree-linuxfsutil.h" #include "ostree-sysroot-private.h" @@ -335,10 +336,7 @@ cleanup_old_deployments (OstreeSysroot *self, return TRUE; } -/* libostree holds a ref for each deployment's exact checksum to avoid it being - * GC'd even if the origin ref changes. This function resets those refs - * to match active deployments. - */ +/* Delete the ref bindings for a non-active boot version */ static gboolean cleanup_ref_prefix (OstreeRepo *repo, int bootversion, @@ -346,30 +344,24 @@ cleanup_ref_prefix (OstreeRepo *repo, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autofree char *prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion); - g_autoptr(GHashTable) refs = NULL; if (!ostree_repo_list_refs_ext (repo, prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) - goto out; - - if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) - goto out; + return FALSE; GLNX_HASH_TABLE_FOREACH (refs, const char *, ref) { - ostree_repo_transaction_set_refspec (repo, ref, NULL); + if (!ostree_repo_set_ref_immediate (repo, NULL, ref, NULL, cancellable, error)) + return FALSE; } - if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) - goto out; - - ret = TRUE; - out: - ostree_repo_abort_transaction (repo, cancellable, NULL); - return ret; + return TRUE; } +/* libostree holds a ref for each deployment's exact checksum to avoid it being + * GC'd even if the origin ref changes. This function resets those refs + * to match active deployments. + */ static gboolean generate_deployment_refs (OstreeSysroot *self, OstreeRepo *repo, @@ -379,46 +371,38 @@ generate_deployment_refs (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int cleanup_bootversion; - int cleanup_subbootversion; - guint i; - - cleanup_bootversion = (bootversion == 0) ? 1 : 0; - cleanup_subbootversion = (subbootversion == 0) ? 1 : 0; + int cleanup_bootversion = (bootversion == 0) ? 1 : 0; + int cleanup_subbootversion = (subbootversion == 0) ? 1 : 0; if (!cleanup_ref_prefix (repo, cleanup_bootversion, 0, cancellable, error)) - goto out; + return FALSE; if (!cleanup_ref_prefix (repo, cleanup_bootversion, 1, cancellable, error)) - goto out; + return FALSE; if (!cleanup_ref_prefix (repo, bootversion, cleanup_subbootversion, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < deployments->len; i++) + g_autoptr(_OstreeRepoAutoTransaction) txn = + _ostree_repo_auto_transaction_start (repo, cancellable, error); + if (!txn) + return FALSE; + for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; g_autofree char *refname = g_strdup_printf ("ostree/%d/%d/%u", bootversion, subbootversion, i); - if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) - goto out; - ostree_repo_transaction_set_refspec (repo, refname, ostree_deployment_get_csum (deployment)); - - if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) - goto out; } + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + return FALSE; - ret = TRUE; - out: - ostree_repo_abort_transaction (repo, cancellable, NULL); - return ret; + return TRUE; } static gboolean diff --git a/tests/admin-test.sh b/tests/admin-test.sh index d5566959..805a7130 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -35,6 +35,13 @@ function validate_bootloader() { cd - } +# Test generate_deployment_refs() +assert_ostree_deployment_refs() { + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo refs ostree | sort > ostree-refs.txt + (for v in "$@"; do echo $v; done) | sort > ostree-refs-expected.txt + diff -u ostree-refs{-expected,}.txt +} + orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) @@ -55,6 +62,7 @@ assert_file_has_content curdir ^`pwd`/sysroot/ostree/deploy/testos/deploy/${rev} echo "ok --print-current-dir" +# Test layout of bootloader config and refs assert_not_has_dir sysroot/boot/loader.0 assert_has_dir sysroot/boot/loader.1 assert_has_dir sysroot/ostree/boot.1.1 @@ -64,9 +72,8 @@ assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'option assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 1/1/0 ${CMD_PREFIX} ostree admin status - - echo "ok layout" orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) @@ -84,6 +91,7 @@ assert_not_has_dir sysroot/ostree/boot.1.1 assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/boot.0/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 0/1/{0,1} ${CMD_PREFIX} ostree admin status validate_bootloader @@ -96,6 +104,7 @@ assert_not_has_dir sysroot/boot/loader.1 # But swap subbootversion assert_has_dir sysroot/ostree/boot.0.0 assert_not_has_dir sysroot/ostree/boot.0.1 +assert_ostree_deployment_refs 0/0/{0,1} ${CMD_PREFIX} ostree admin status validate_bootloader @@ -110,6 +119,7 @@ assert_has_file sysroot/boot/loader/entries/ostree-testos-1.conf assert_has_file sysroot/boot/loader/entries/ostree-otheros-0.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/deploy/otheros/deploy/${rev}.0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 1/1/{0,1,2} ${CMD_PREFIX} ostree admin status validate_bootloader @@ -123,6 +133,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.2/etc/os-rele assert_has_file sysroot/boot/loader/entries/ostree-testos-2.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin status +assert_ostree_deployment_refs 0/1/{0,1,2,3} validate_bootloader echo "ok fourth deploy (retain)" From 067da211cd63a62cc03dc2745d40b9aa0e64dabc Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 8 Sep 2017 09:31:03 -0400 Subject: [PATCH 64/83] lib/syslinux: Port to new code style There was only one tricky bit here around the ownership of the lines; I made use of `g_steal_pointer()` to consistently track ownership, and converted to a `for` loop while still preserving the loop logic around the last entry. Closes: #1154 Approved by: jlebon --- src/libostree/ostree-bootloader-syslinux.c | 160 ++++++++------------- 1 file changed, 58 insertions(+), 102 deletions(-) diff --git a/src/libostree/ostree-bootloader-syslinux.c b/src/libostree/ostree-bootloader-syslinux.c index 05cb173e..16f287b9 100644 --- a/src/libostree/ostree-bootloader-syslinux.c +++ b/src/libostree/ostree-bootloader-syslinux.c @@ -59,44 +59,33 @@ _ostree_bootloader_syslinux_get_name (OstreeBootloader *bootloader) } static gboolean -append_config_from_boostree_loader_entries (OstreeBootloaderSyslinux *self, - gboolean regenerate_default, - int bootversion, - GPtrArray *new_lines, - GCancellable *cancellable, - GError **error) +append_config_from_loader_entries (OstreeBootloaderSyslinux *self, + gboolean regenerate_default, + int bootversion, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) { - gboolean ret = FALSE; - g_autoptr(GPtrArray) boostree_loader_configs = NULL; - guint i; - - if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &boostree_loader_configs, + g_autoptr(GPtrArray) loader_configs = NULL; + if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &loader_configs, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < boostree_loader_configs->len; i++) + for (guint i = 0; i < loader_configs->len; i++) { - OstreeBootconfigParser *config = boostree_loader_configs->pdata[i]; - const char *val; - - val = ostree_bootconfig_parser_get (config, "title"); + OstreeBootconfigParser *config = loader_configs->pdata[i]; + const char *val = ostree_bootconfig_parser_get (config, "title"); if (!val) val = "(Untitled)"; if (regenerate_default && i == 0) - { - g_ptr_array_add (new_lines, g_strdup_printf ("DEFAULT %s", val)); - } + g_ptr_array_add (new_lines, g_strdup_printf ("DEFAULT %s", val)); g_ptr_array_add (new_lines, g_strdup_printf ("LABEL %s", val)); - + val = ostree_bootconfig_parser_get (config, "linux"); if (!val) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No \"linux\" key in bootloader config"); - goto out; - } + return glnx_throw (error, "No \"linux\" key in bootloader config"); g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", val)); val = ostree_bootconfig_parser_get (config, "initrd"); @@ -108,72 +97,57 @@ append_config_from_boostree_loader_entries (OstreeBootloaderSyslinux *self, g_ptr_array_add (new_lines, g_strdup_printf ("\tAPPEND %s", val)); } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, - int bootversion, - GCancellable *cancellable, - GError **error) + int bootversion, + GCancellable *cancellable, + GError **error) { - gboolean ret = FALSE; OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); - g_autoptr(GFile) new_config_path = NULL; - g_autofree char *config_contents = NULL; - g_autofree char *new_config_contents = NULL; - g_autoptr(GPtrArray) new_lines = NULL; - g_autoptr(GPtrArray) tmp_lines = NULL; + + g_autoptr(GFile) new_config_path = + ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", bootversion); + + /* This should follow the symbolic link to the current bootversion. */ + g_autofree char *config_contents = + glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, + cancellable, error); + if (!config_contents) + return FALSE; + + g_auto(GStrv) lines = g_strsplit (config_contents, "\n", -1); + g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) tmp_lines = g_ptr_array_new_with_free_func (g_free); + g_autofree char *kernel_arg = NULL; gboolean saw_default = FALSE; gboolean regenerate_default = FALSE; gboolean parsing_label = FALSE; - char **lines = NULL; - char **iter; - guint i; - - new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", - bootversion); - - /* This should follow the symbolic link to the current bootversion. */ - config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, - cancellable, error); - if (!config_contents) - goto out; - - lines = g_strsplit (config_contents, "\n", -1); - new_lines = g_ptr_array_new_with_free_func (g_free); - tmp_lines = g_ptr_array_new_with_free_func (g_free); - /* Note special iteration condition here; we want to also loop one * more time at the end where line = NULL to ensure we finish off * processing the last LABEL. */ - iter = lines; - while (TRUE) + for (char **iter = lines; iter; iter++) { - char *line = *iter; + const char *line = *iter; gboolean skip = FALSE; - if (parsing_label && + if (parsing_label && (line == NULL || !g_str_has_prefix (line, "\t"))) { parsing_label = FALSE; if (kernel_arg == NULL) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No KERNEL argument found after LABEL"); - goto out; - } + return glnx_throw (error, "No KERNEL argument found after LABEL"); /* If this is a non-ostree kernel, just emit the lines * we saw. */ if (!g_str_has_prefix (kernel_arg, "/ostree/")) { - for (i = 0; i < tmp_lines->len; i++) + for (guint i = 0; i < tmp_lines->len; i++) { g_ptr_array_add (new_lines, tmp_lines->pdata[i]); tmp_lines->pdata[i] = NULL; /* Transfer ownership */ @@ -211,55 +185,37 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, * the title to hopefully avoid regressions. */ if (g_str_has_prefix (line, "DEFAULT ostree:") || /* old format */ strstr (line, "(ostree") != NULL) /* new format */ - { - regenerate_default = TRUE; - } + regenerate_default = TRUE; skip = TRUE; } - - if (skip) - { - g_free (line); - } - else + + if (!skip) { if (parsing_label) - { - g_ptr_array_add (tmp_lines, line); - } + g_ptr_array_add (tmp_lines, g_strdup (line)); else - { - g_ptr_array_add (new_lines, line); - } + g_ptr_array_add (new_lines, g_strdup (line)); } - /* Transfer ownership */ - *iter = NULL; - iter++; } if (!saw_default) regenerate_default = TRUE; - if (!append_config_from_boostree_loader_entries (self, regenerate_default, - bootversion, new_lines, - cancellable, error)) - goto out; - - new_config_contents = _ostree_sysroot_join_lines (new_lines); - { - g_autoptr(GBytes) new_config_contents_bytes = - g_bytes_new_static (new_config_contents, - strlen (new_config_contents)); - - if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, + if (!append_config_from_loader_entries (self, regenerate_default, + bootversion, new_lines, cancellable, error)) - goto out; - } - - ret = TRUE; - out: - g_free (lines); /* Note we freed elements individually */ - return ret; + return FALSE; + + g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines); + g_autoptr(GBytes) new_config_contents_bytes = + g_bytes_new_static (new_config_contents, + strlen (new_config_contents)); + + if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, + cancellable, error)) + return FALSE; + + return TRUE; } static void From 08eaf668275b965d5a692ad48321a14f8c706360 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 6 Sep 2017 09:31:16 +0200 Subject: [PATCH 65/83] rofiles-fuse: Fix lchown() and hardlink verification for symlinks If you lchown("symlink") then we were incorrectly trying to chown the symlink target, rather than the symlink itself. In particular, this cause cp -a to fail for a broken symlink. Additionally, it was using the symlink target when verifying writability, rather than the symlink itself. To fix this, we need pass AT_SYMLINK_NOFOLLOW in these cases. In general, the kernel itself will always resolve any symlinks for us before calling into the fuse backend, so we should really never do any symlink following in the fuse fs itself. So, we pro-actively add NOFOLLOW flags to a few other places: truncate: In reality this will never be hit, because the kernel will resolve symlinks before calling us. access: It seems the current fuse implementation never calls this (faccessat w/AT_SYMLINK_NOFOLLOW never reaches the fuse fs) but if this ever is implemented this is the correct behaviour. We would ideally do `chmod` but this is not implemented on current kernels. Because we're not multi-threaded, this is OK anyways. Further, our write verification wasn't correctly handling the case of hardlinked symlinks, which can occur for `bare` checkouts but *not* `bare-user` which the tests were using. Change to `bare` mode to verify that. Closes: #1137 Approved by: alexlarsson --- src/rofiles-fuse/main.c | 45 +++++++++++++++++++++++++---------- tests/test-rofiles-fuse.sh | 48 +++++++++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/rofiles-fuse/main.c b/src/rofiles-fuse/main.c index 88cdba6c..6deaa6d0 100644 --- a/src/rofiles-fuse/main.c +++ b/src/rofiles-fuse/main.c @@ -198,26 +198,42 @@ callback_link (const char *from, const char *to) return 0; } -static gboolean -stbuf_is_regfile_hardlinked (struct stat *stbuf) +/* 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) { - return S_ISREG (stbuf->st_mode) && stbuf->st_nlink > 1; + /* 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; + /* If the object isn't hardlinked, it's OK to write */ + if (stbuf->st_nlink <= 1) + return 0; + /* Otherwise, it's a hardlinked file or symlink; it must be + * immutable. + */ + return -EROFS; } +/* 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) { struct stat stbuf; - if (fstatat (basefd, path, &stbuf, 0) == -1) + if (fstatat (basefd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOENT) return 0; else return -errno; } - if (stbuf_is_regfile_hardlinked (&stbuf)) - return -EROFS; - return 0; + return can_write_stbuf (&stbuf); } #define VERIFY_WRITE(path) do { \ @@ -231,6 +247,10 @@ callback_chmod (const char *path, mode_t mode) { path = ENSURE_RELPATH (path); VERIFY_WRITE(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 + */ if (fchmodat (basefd, path, mode, 0) != 0) return -errno; return 0; @@ -241,7 +261,7 @@ callback_chown (const char *path, uid_t uid, gid_t gid) { path = ENSURE_RELPATH (path); VERIFY_WRITE(path); - if (fchownat (basefd, path, uid, gid, 0) != 0) + if (fchownat (basefd, path, uid, gid, AT_SYMLINK_NOFOLLOW) != 0) return -errno; return 0; } @@ -254,7 +274,7 @@ callback_truncate (const char *path, off_t size) path = ENSURE_RELPATH (path); VERIFY_WRITE(path); - fd = openat (basefd, path, O_WRONLY); + fd = openat (basefd, path, O_NOFOLLOW|O_WRONLY); if (fd == -1) return -errno; @@ -312,10 +332,11 @@ do_open (const char *path, mode_t mode, struct fuse_file_info *finfo) return -errno; } - if (stbuf_is_regfile_hardlinked (&stbuf)) + int r = can_write_stbuf (&stbuf); + if (r != 0) { (void) close (fd); - return -EROFS; + return r; } /* Handle O_TRUNC here only after verifying hardlink state */ @@ -433,7 +454,7 @@ callback_access (const char *path, int mode) * before trying to do an unlink. So...we'll just lie about * writable access here. */ - if (faccessat (basefd, path, mode, 0) == -1) + if (faccessat (basefd, path, mode, AT_SYMLINK_NOFOLLOW) == -1) return -errno; return 0; } diff --git a/tests/test-rofiles-fuse.sh b/tests/test-rofiles-fuse.sh index a7811b80..d329d765 100755 --- a/tests/test-rofiles-fuse.sh +++ b/tests/test-rofiles-fuse.sh @@ -24,13 +24,16 @@ set -euo pipefail skip_without_fuse skip_without_user_xattrs -setup_test_repository "bare-user" +setup_test_repository "bare" echo "1..7" +cd ${test_tmpdir} mkdir mnt - -$OSTREE checkout -H -U test2 checkout-test2 +# The default content set amazingly doesn't have a non-broken link +ln -s firstfile files/firstfile-link +$OSTREE commit -b test2 --tree=dir=files +$OSTREE checkout -H test2 checkout-test2 rofiles-fuse checkout-test2 mnt cleanup_fuse() { @@ -40,22 +43,32 @@ trap cleanup_fuse EXIT assert_file_has_content mnt/firstfile first echo "ok mount" -if cp /dev/null mnt/firstfile 2>err.txt; then - assert_not_reached "inplace mutation" -fi -assert_file_has_content err.txt "Read-only file system" -assert_file_has_content mnt/firstfile first -assert_file_has_content checkout-test2/firstfile first - +# Test open(O_TRUNC) directly and via symlink +for path in firstfile{,-link}; do + if cp /dev/null mnt/${path} 2>err.txt; then + assert_not_reached "inplace mutation ${path}" + fi + assert_file_has_content err.txt "Read-only file system" + assert_file_has_content mnt/firstfile first + assert_file_has_content checkout-test2/firstfile first +done echo "ok failed inplace mutation (open O_TRUNCATE)" -# Test chmod + chown +# Test chmod if chmod 0600 mnt/firstfile 2>err.txt; then assert_not_reached "chmod inplace" fi assert_file_has_content err.txt "chmod:.*Read-only file system" -if chown $(id -u) mnt/firstfile 2>err.txt; then - assert_not_reached "chown inplace" +# Test chown with regfiles and symlinks +for path in firstfile baz/alink; do + if chown -h $(id -u) mnt/${path} 2>err.txt; then + assert_not_reached "chown inplace ${path}" + fi + assert_file_has_content err.txt "chown:.*Read-only file system" +done +# And test via dereferencing a symlink +if chown $(id -u) mnt/firstfile-link 2>err.txt; then + assert_not_reached "chown inplace firstfile-link" fi assert_file_has_content err.txt "chown:.*Read-only file system" echo "ok failed mutation chmod + chown" @@ -64,6 +77,13 @@ echo "ok failed mutation chmod + chown" echo anewfile-for-fuse > mnt/anewfile-for-fuse assert_file_has_content mnt/anewfile-for-fuse anewfile-for-fuse assert_file_has_content checkout-test2/anewfile-for-fuse anewfile-for-fuse +ln -s anewfile-for-fuse mnt/anewfile-for-fuse-link +# And also test modifications through a symlink +echo writevialink > mnt/anewfile-for-fuse-link +for path in anewfile-for-fuse{,-link}; do + assert_file_has_content mnt/${path} writevialink +done +chown $(id -u) mnt/anewfile-for-fuse-link mkdir mnt/newfusedir for i in $(seq 5); do @@ -86,7 +106,7 @@ ${CMD_PREFIX} ostree --repo=repo commit -b test2 -s fromfuse --link-checkout-spe echo "ok commit" ${CMD_PREFIX} ostree --repo=repo checkout -U test2 mnt/test2-checkout-copy-fallback -assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse anewfile-for-fuse +assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse writevialink if ${CMD_PREFIX} ostree --repo=repo checkout -UH test2 mnt/test2-checkout-copy-hardlinked 2>err.txt; then assert_not_reached "Checking out via hardlinks across mountpoint unexpectedly succeeded!" From 9f78386819efb45f849467e99877528bac8c3666 Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Fri, 8 Sep 2017 17:41:04 -0700 Subject: [PATCH 66/83] lib/repo: Update outdated comment Closes: #1157 Approved by: cgwalters --- src/libostree/ostree-repo.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 93c6d62d..c0d4a8e7 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -4940,11 +4940,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self, g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC))); } - /* Add refs which have a collection specified. ostree_repo_list_collection_refs() - * is guaranteed to only return refs which are in refs/mirrors, or those which - * are in refs/heads if the repository configuration specifies a collection ID - * (which we put in the main refs map, rather than the collection map, for - * backwards compatibility). */ + /* Add refs which have a collection specified, which could be in refs/mirrors, + * refs/heads, and/or refs/remotes. */ { g_autoptr(GHashTable) collection_refs = NULL; if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, @@ -4983,6 +4980,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self, const char *collection_id = collection_iter->data; GHashTable *ref_map = g_hash_table_lookup (collection_map, collection_id); + /* We put the local repo's collection ID in the main refs map, rather + * than the collection map, for backwards compatibility. */ gboolean is_main_collection_id = (main_collection_id != NULL && g_str_equal (collection_id, main_collection_id)); if (!is_main_collection_id) From ccbbf77c7107e015b5f9ed5084504b6436f2353a Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Fri, 8 Sep 2017 12:09:18 -0500 Subject: [PATCH 67/83] sysroot: Reload config after setting sysroot kind This allows any repo configuration defaults to be set based on whether it's a system repo or not. Closes: #1155 Approved by: cgwalters --- src/libostree/ostree-sysroot.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index e8e299fe..b8c4b4c5 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -772,6 +772,13 @@ ensure_repo (OstreeSysroot *self, */ g_weak_ref_init (&self->repo->sysroot, self); self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT; + + /* Reload the repo config in case any defaults depend on knowing if this is + * a system repo. + */ + if (!ostree_repo_reload_config (self->repo, NULL, error)) + return FALSE; + return TRUE; } From adac42b6effbc748ade9f135a6b3f284a67e9dd4 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Fri, 8 Sep 2017 10:18:10 -0500 Subject: [PATCH 68/83] repo: Add add-remotes-config-dir option This option allows a repo to explicitly opt out of adding new remotes in a remotes configuration directory. This currently defaults to true for system repos and false for non-system repos to maintain legacy behavior that non-system repos don't add remotes in a configuration directory. That would be problematic for flatpak, which specifies a remotes config dir but adds remotes in ways that are incompatible with it. So, what this really does is allow system repos to control whether they want to add remotes in the config dir or not. That's important if your flatpak repo is the system repo like at Endless. Closes: #1134 Closes: #1155 Approved by: cgwalters --- man/ostree.repo-config.xml | 21 +++++++++++++++++++++ src/libostree/ostree-repo-private.h | 1 + src/libostree/ostree-repo.c | 18 +++++++++++++++--- tests/admin-test.sh | 11 ++++++++++- tests/test-remotes-config-dir.js | 18 ++++++++++++++++-- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index 8ae6ad42..388b9e62 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -122,6 +122,27 @@ Boston, MA 02111-1307, USA. keep free. The default value is 3. + + add-remotes-config-dir + + + Boolean value controlling whether new remotes will be added + in the remotes configuration directory. Defaults to + true for system ostree repositories. When + this is false, remotes will be added in + the repository's config file. + + + This only applies to repositories that use a remotes + configuration directory such as system ostree repositories, + which use /etc/ostree/remotes.d. + Non-system repositories do not use a remotes configuration + directory unless one is specified when the repository is + opened. + + + + diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index fdcd8f3f..865cb120 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -154,6 +154,7 @@ struct OstreeRepo { gboolean generate_sizes; guint64 tmp_expiry_seconds; gchar *collection_id; + gboolean add_remotes_config_dir; /* Add new remotes in remotes.d dir */ OstreeRepo *parent_repo; }; diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index c0d4a8e7..b529854e 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1010,11 +1010,12 @@ impl_repo_remote_add (OstreeRepo *self, remote = ostree_remote_new (name); - /* Only add repos in remotes.d for system repos since that was the - * legacy behavior and non-system repos would not expect it. + /* Only add repos in remotes.d if the repo option + * add-remotes-config-dir is true. This is the default for system + * repos. */ g_autoptr(GFile) etc_ostree_remotes_d = get_remotes_d_dir (self, sysroot); - if (etc_ostree_remotes_d && ostree_repo_is_system (self)) + if (etc_ostree_remotes_d && self->add_remotes_config_dir) { g_autoptr(GError) local_error = NULL; @@ -2231,6 +2232,17 @@ reload_core_config (OstreeRepo *self, } } + /* By default, only add remotes in a remotes config directory for + * system repos. This is to preserve legacy behavior for non-system + * repos that specify a remotes config dir (flatpak). + */ + { gboolean is_system = ostree_repo_is_system (self); + + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "add-remotes-config-dir", + is_system, &self->add_remotes_config_dir, error)) + return FALSE; + } + return TRUE; } diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 805a7130..f5d33a6f 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..$((21 + ${extra_admin_tests:-0}))" +echo "1..$((22 + ${extra_admin_tests:-0}))" function validate_bootloader() { cd ${test_tmpdir}; @@ -292,6 +292,15 @@ assert_not_file_has_content sysroot/ostree/repo/config remote-test-nonphysical assert_file_has_content ${deployment}/etc/ostree/remotes.d/remote-test-nonphysical.conf testos-repo echo "ok remote add nonphysical sysroot" +# Test that setting add-remotes-config-dir to false adds a remote in the +# config file rather than the remotes config dir even though this is a +# "system" repo. +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set core.add-remotes-config-dir false +${CMD_PREFIX} ostree --sysroot=${deployment} remote add --set=gpg-verify=false remote-test-config-dir file://$(pwd)/testos-repo +assert_not_has_file ${deployment}/etc/ostree/remotes.d/remote-test-config-dir.conf testos-repo +assert_file_has_content sysroot/ostree/repo/config remote-test-config-dir +echo "ok remote add nonphysical sysroot add-remotes-config-dir false" + if env OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},test-fifreeze" \ ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then fatal "fifreeze-test exited successfully?" diff --git a/tests/test-remotes-config-dir.js b/tests/test-remotes-config-dir.js index 9de8f01a..11d77348 100755 --- a/tests/test-remotes-config-dir.js +++ b/tests/test-remotes-config-dir.js @@ -32,7 +32,7 @@ function assertNotEquals(a, b) { throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b)); } -print('1..3') +print('1..4') let remotesDir = Gio.File.new_for_path('remotes.d'); remotesDir.make_directory(null); @@ -56,7 +56,8 @@ assertNotEquals(remotes.indexOf('foo'), -1); print("ok read-remotes-config-dir"); -// Adding a remote should not go in the remotes.d dir +// Adding a remote should not go in the remotes.d dir unless this is a +// system repo or add-remotes-config-dir is set to true repo.remote_add('bar', 'http://bar', null, null); remotes = repo.remote_list() assertNotEquals(remotes.indexOf('bar'), -1); @@ -71,3 +72,16 @@ assertEquals(remotes.indexOf('foo'), -1); assertEquals(remotesDir.get_child('foo.conf').query_exists(null), false); print("ok delete-in-remotes-config-dir"); + +// Set add-remotes-config-dir to true and check that a remote gets added +// in the config dir +let repoConfig = repo.copy_config(); +repoConfig.set_boolean('core', 'add-remotes-config-dir', true); +repo.write_config(repoConfig); +repo.reload_config(null); +repo.remote_add('baz', 'http://baz', null, null); +remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('baz'), -1); +assertEquals(remotesDir.get_child('baz.conf').query_exists(null), true); + +print("ok add-in-remotes-config-dir"); From 9689fb720a20d7139ae30d56fda1c9e0de49ffa2 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 12 Sep 2017 09:46:05 -0400 Subject: [PATCH 69/83] ci: Fixate CentOS container image until rpm-md repos sync Copy of https://github.com/projectatomic/rpm-ostree/pull/985 Closes: #1160 Approved by: jlebon --- .papr.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.papr.yml b/.papr.yml index 75ace5da..56ff4dae 100644 --- a/.papr.yml +++ b/.papr.yml @@ -41,8 +41,10 @@ env: CFLAGS: '' tests: + # FIXME revert setting to 7/3/1611 when repos sync + # https://github.com/projectatomic/rpm-ostree/pull/985 - docker run --privileged -v $PWD:$PWD --workdir $PWD - registry.centos.org/centos/centos:7 sh -c + registry.centos.org/centos/centos:7.3.1611 sh -c 'yum install -y git && ci/build-check.sh' --- From 662ad5b1719de2337561cbec5ad9bfeed2211513 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 12 Sep 2017 10:21:17 -0400 Subject: [PATCH 70/83] lib/sysroot: Use direct g_mkdtemp() for overlay tmpdir The new libglnx `glnx_mkdtempat()` uses autocleanups, which is inconvenient for this use case where we *don't* want autocleanups. Since we don't need it to be fd-relative, just directly invoke `g_mkdtemp_full()` which is fine for this use case. Prep for updating libglnx. Closes: #1161 Approved by: jlebon --- src/libostree/ostree-sysroot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index b8c4b4c5..18475d35 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -1738,8 +1738,8 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, "/usr", 0755, error)) return FALSE; - if (!glnx_mkdtempat (AT_FDCWD, development_ovldir, 0755, error)) - return FALSE; + if (g_mkdtemp_full (development_ovldir, 0755) == NULL) + return glnx_throw_errno_prefix (error, "mkdtemp"); } development_ovl_upper = glnx_strjoina (development_ovldir, "/upper"); From 48364459b8570c11116a8783c3914c0150e8b385 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Fri, 1 Sep 2017 15:44:49 -0400 Subject: [PATCH 71/83] bin/main: Print usage when no command given Minor regression from https://github.com/ostreedev/ostree/pull/1106. We want to print the usage text both when unknown commands are passed, as well as when no commands are passed at all. Closes: #1126 Approved by: cgwalters --- src/ostree/ot-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 011ae16c..eda787b4 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -181,10 +181,10 @@ ostree_run (int argc, { g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unknown command '%s'", command_name); - ostree_usage (commands, TRUE); } } + ostree_usage (commands, TRUE); goto out; } From ec9a58f2476bbce1e0ae6f267995b64f7c85162c Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Fri, 1 Sep 2017 15:52:13 -0400 Subject: [PATCH 72/83] bin/config: Tweak parameter string Make the parameter string more detailed. Closes: #1126 Approved by: cgwalters --- src/ostree/ot-builtin-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c index 6163b3b1..782fee85 100644 --- a/src/ostree/ot-builtin-config.c +++ b/src/ostree/ot-builtin-config.c @@ -69,7 +69,7 @@ ostree_builtin_config (int argc, char **argv, GCancellable *cancellable, GError g_autofree char *key = NULL; GKeyFile *config = NULL; - context = g_option_context_new ("- Change configuration settings"); + context = g_option_context_new ("(get KEY|set KEY VALUE) - Change repo configuration settings"); if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; From 077de8ea460562c9372f45b13a9b42867f9ad832 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 5 Sep 2017 14:27:20 -0400 Subject: [PATCH 73/83] tests/test-help.sh: Rework and strengthen checks The `sed` expression wasn't actually matching the main output, so we weren't recursing into the subcommands. Update the syntax to match the current output and add a check so we don't miss that happening again. Add a check that the help output is only printed once in all circumstances. Also add a check for proper handling of non-existent commands. Closes: #1126 Approved by: cgwalters --- tests/test-help.sh | 61 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/tests/test-help.sh b/tests/test-help.sh index ca555b1b..75fe0c11 100755 --- a/tests/test-help.sh +++ b/tests/test-help.sh @@ -23,41 +23,66 @@ set -euo pipefail echo "1..1" -echo "Testing:" 1>&2 +test_usage_output() { + file=$1; shift + cmd=$1; shift + assert_file_has_content $file '^Usage' + # check that it didn't print twice somehow + if [ "$(grep --count '^Usage' $file)" != 1 ]; then + _fatal_print_file "$file" "File '$file' has '^Usage' more than once." + fi + assert_file_has_content $file "$cmd" +} + +# check that we found at least one command with subcommands +found_subcommands=0 + test_recursive() { local cmd=$1 - local root=$2 echo "$cmd" 1>&2 $cmd --help 1>out 2>err # --help message goes to standard output - if [ "$root" = "1" ] ; then - assert_file_has_content out "[Uu]sage" - assert_file_has_content out "$cmd" - fi + test_usage_output out "$cmd" assert_file_empty err - builtins=`sed -n '/^Builtin commands/,/^[^ ]/p' out 2>err - if [ $? = 0 ] ; then - echo 1>&2 "missing subcommand but 0 exit status"; exit 1 + rc=0 + $cmd 1>out 2>err || rc=$? + if [ $rc = 0 ] ; then + assert_not_reached "missing subcommand but 0 exit status" fi - set -euo pipefail + # error message and usage goes to standard error - assert_file_has_content err "[Uu]sage" - assert_file_has_content err "$cmd" - assert_file_has_content err "Builtin commands" + test_usage_output err "$cmd" + assert_file_has_content err 'No \("[^"]*" sub\)\?command specified' assert_file_empty out - for subcmd in $builtins ; do - test_recursive "$cmd $subcmd" 0 + rc=0 + $cmd non-existent-subcommand 1>out 2>err || rc=$? + if [ $rc = 0 ] ; then + assert_not_reached "non-existent subcommand but 0 exit status" + fi + + test_usage_output err "$cmd" + assert_file_has_content err 'Unknown \("[^"]*" sub\)\?command' + assert_file_empty out + + for subcmd in $builtins; do + test_recursive "$cmd $subcmd" done fi } -test_recursive ostree 1 +test_recursive ostree +if [ $found_subcommands != 1 ]; then + assert_not_reached "no ostree commands with subcommands found!" +fi echo "ok help option is properly supported" From 4efab3feb07487cec80823ddfe48f32f2853e746 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 5 Sep 2017 14:27:20 -0400 Subject: [PATCH 74/83] bin/admin: Don't require root for instutil Otherwise, we can't even do `--help` on it. The subcommands all already have the root flag set. Closes: #1126 Approved by: cgwalters --- src/ostree/ot-admin-builtin-instutil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c index 2baa27f7..7b446e93 100644 --- a/src/ostree/ot-admin-builtin-instutil.c +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -106,7 +106,7 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr /* This will not return for some options (e.g. --version). */ if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, NULL, cancellable, error)) { if (subcommand_name == NULL) From 225bbdf0024a4325dcda273cce135912f6217824 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 5 Sep 2017 14:27:20 -0400 Subject: [PATCH 75/83] bin/static-delta: Convert to new style and tweak output Convert the whole file to new style. Also tweak the help outputs to make it similar enough to the other commands for tests to pass. Of course, we should just centralize all subcommand handling the same way it was done in rpm-ostree, though let's punt on that for now. Closes: #1126 Approved by: cgwalters --- src/ostree/ot-builtin-static-delta.c | 75 +++++++++++----------------- 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index 7fbb1c7f..c64dbbf5 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -100,48 +100,41 @@ static_delta_usage (char **argv, else print_func = g_print; - print_func ("usage: ostree static-delta\n"); - print_func ("Builtin commands:\n"); + print_func ("Usage:\n"); + print_func (" ostree static-delta [OPTION...] COMMAND\n\n"); + print_func ("Builtin \"static-delta\" Commands:\n"); while (command->name) { print_func (" %s\n", command->name); command++; } + + print_func ("\n"); } static gboolean ot_static_delta_builtin_list (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GPtrArray) delta_names = NULL; - guint i; - g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("- list static delta files"); + if (!ostree_option_context_parse (context, list_options, &argc, &argv, + OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) + return FALSE; - context = g_option_context_new ("LIST - list static delta files"); - - if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) - goto out; - + g_autoptr(GPtrArray) delta_names = NULL; if (!ostree_repo_list_static_delta_names (repo, &delta_names, cancellable, error)) - goto out; - + return FALSE; + if (delta_names->len == 0) - { - g_print ("(No static deltas)\n"); - } + g_print ("(No static deltas)\n"); else { - for (i = 0; i < delta_names->len; i++) - { - g_print ("%s\n", (char*)delta_names->pdata[i]); - } + for (guint i = 0; i < delta_names->len; i++) + g_print ("%s\n", (char*)delta_names->pdata[i]); } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -152,7 +145,7 @@ ot_static_delta_builtin_show (int argc, char **argv, GCancellable *cancellable, g_autoptr(OstreeRepo) repo = NULL; const char *delta_id = NULL; - context = g_option_context_new ("SHOW - Dump information on a delta"); + context = g_option_context_new ("- Dump information on a delta"); if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -182,7 +175,7 @@ ot_static_delta_builtin_delete (int argc, char **argv, GCancellable *cancellable g_autoptr(OstreeRepo) repo = NULL; const char *delta_id = NULL; - context = g_option_context_new ("DELETE - Remove a delta"); + context = g_option_context_new ("- Remove a delta"); if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -212,7 +205,7 @@ ot_static_delta_builtin_generate (int argc, char **argv, GCancellable *cancellab g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; - context = g_option_context_new ("GENERATE [TO] - Generate static delta files"); + context = g_option_context_new ("[TO] - Generate static delta files"); if (!ostree_option_context_parse (context, generate_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -363,7 +356,7 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, GCancellable *canc g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; - context = g_option_context_new ("APPLY-OFFLINE - Apply static delta file"); + context = g_option_context_new ("- Apply static delta file"); if (!ostree_option_context_parse (context, apply_offline_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -397,13 +390,9 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, GCancellable *canc gboolean ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - OstreeCommand *command = NULL; - const char *cmdname = NULL; - int i; gboolean want_help = FALSE; - - for (i = 1; i < argc; i++) + const char *cmdname = NULL; + for (int i = 1; i < argc; i++) { if (argv[i][0] != '-') { @@ -420,11 +409,10 @@ ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, G if (!cmdname && !want_help) { static_delta_usage (argv, TRUE); - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No command specified"); - goto out; + return glnx_throw (error, "No command specified"); } + OstreeCommand *command = NULL; if (cmdname) { command = static_delta_subcommands; @@ -439,22 +427,17 @@ ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, G if (want_help && command == NULL) { static_delta_usage (argv, FALSE); - ret = TRUE; - goto out; + return TRUE; /* Note early return */ } if (!command->fn) { - g_autofree char *msg = g_strdup_printf ("Unknown command '%s'", cmdname); static_delta_usage (argv, TRUE); - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg); - goto out; + return glnx_throw (error, "Unknown \"static-delta\" subcommand '%s'", cmdname); } - if (!command->fn (argc, argv, cancellable, error)) - goto out; + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), cmdname); + g_set_prgname (prgname); - ret = TRUE; - out: - return ret; + return command->fn (argc, argv, cancellable, error); } From 4c02fc2daa7c433c095b1757d630836d75b974db Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Fri, 8 Sep 2017 15:40:59 -0400 Subject: [PATCH 76/83] bin/admin: Don't load sysroot for root commands There's no need to load the sysroot for root commands which have subcommands, like `ostree admin` and `ostree admin instutil`. Otherwise, even just calling them without arguments will cause a failure. The subcommands will have the appropriate flags set as needed. Closes: #1126 Approved by: cgwalters --- src/ostree/ot-admin-builtin-instutil.c | 2 +- src/ostree/ot-builtin-admin.c | 2 +- src/ostree/ot-main.c | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c index 7b446e93..0770b1b2 100644 --- a/src/ostree/ot-admin-builtin-instutil.c +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -106,7 +106,7 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr /* This will not return for some options (e.g. --version). */ if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, NULL, cancellable, error)) { if (subcommand_name == NULL) diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c index 16aaec03..ce0b2ffa 100644 --- a/src/ostree/ot-builtin-admin.c +++ b/src/ostree/ot-builtin-admin.c @@ -126,7 +126,7 @@ ostree_builtin_admin (int argc, char **argv, GCancellable *cancellable, GError * /* This will not return for some options (e.g. --version). */ if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_NONE | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, NULL, cancellable, error)) { if (subcommand_name == NULL) diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index eda787b4..a6ddfe74 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -374,10 +374,11 @@ ostree_admin_option_context_parse (GOptionContext *context, g_option_context_add_main_entries (context, global_admin_entries, NULL); - if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) + if (!ostree_option_context_parse (context, main_entries, argc, argv, + OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) return FALSE; - if (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT) + if (!opt_print_current_dir && (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT)) { g_assert_null (out_sysroot); /* Early return if no sysroot is requested */ From 4cc813133c5aa074d2d2664fb57b9edb74c610c8 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 11 Sep 2017 21:06:30 +0000 Subject: [PATCH 77/83] bin/remote: don't load repo on root command Subcommands will demand a repo argument themselves. This allows one to call `ostree remote` and get the "No subcommand" error rather than the "Missing --repo" error. Closes: #1126 Approved by: cgwalters --- src/ostree/ot-builtin-remote.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c index dd999c01..9d290d09 100644 --- a/src/ostree/ot-builtin-remote.c +++ b/src/ostree/ot-builtin-remote.c @@ -115,7 +115,8 @@ ostree_builtin_remote (int argc, char **argv, GCancellable *cancellable, GError /* This will not return for some options (e.g. --version). */ if (ostree_option_context_parse (context, NULL, &argc, &argv, - OSTREE_BUILTIN_FLAG_NONE, NULL, cancellable, error)) + OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, + error)) { if (subcommand_name == NULL) { From 3b315e16d89fe55423d693c4c4acf3986489de24 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Mon, 11 Sep 2017 12:57:42 -0500 Subject: [PATCH 78/83] repo: Ensure new config doesn't set remotes in separate file If the new configuration passed to ostree_write_config () tries to update options for a remote defined in a separate config file, return an error. Without this, the full configuration would contain duplicate remote specifications, which would raise an error the next time the repo is opened. Closes: #1159 Approved by: cgwalters --- src/libostree/ostree-repo.c | 34 ++++++++++++++++++++++++++++++++ tests/test-remotes-config-dir.js | 29 ++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index b529854e..3d56bb55 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -933,6 +933,40 @@ ostree_repo_write_config (OstreeRepo *self, { g_return_val_if_fail (self->inited, FALSE); + /* Ensure that any remotes in the new config aren't defined in a + * separate config file. + */ + gsize num_groups; + g_auto(GStrv) groups = g_key_file_get_groups (new_config, &num_groups); + for (gsize i = 0; i < num_groups; i++) + { + g_autoptr(OstreeRemote) new_remote = ostree_remote_new_from_keyfile (new_config, groups[i]); + if (new_remote != NULL) + { + g_autoptr(GError) local_error = NULL; + + g_autoptr(OstreeRemote) cur_remote = + _ostree_repo_get_remote (self, new_remote->name, &local_error); + if (cur_remote == NULL) + { + if (!g_error_matches (local_error, G_IO_ERROR, + G_IO_ERROR_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + else if (cur_remote->file != NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Remote \"%s\" already defined in %s", + new_remote->name, + gs_file_get_path_cached (cur_remote->file)); + return FALSE; + } + } + } + gsize len; g_autofree char *data = g_key_file_to_data (new_config, &len, error); if (!glnx_file_replace_contents_at (self->repo_dir_fd, "config", diff --git a/tests/test-remotes-config-dir.js b/tests/test-remotes-config-dir.js index 11d77348..7b6585c9 100755 --- a/tests/test-remotes-config-dir.js +++ b/tests/test-remotes-config-dir.js @@ -32,7 +32,7 @@ function assertNotEquals(a, b) { throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b)); } -print('1..4') +print('1..6') let remotesDir = Gio.File.new_for_path('remotes.d'); remotesDir.make_directory(null); @@ -85,3 +85,30 @@ assertNotEquals(remotes.indexOf('baz'), -1); assertEquals(remotesDir.get_child('baz.conf').query_exists(null), true); print("ok add-in-remotes-config-dir"); + +// Trying to set a remote config option via write_config() for a remote +// defined in the config file should succeed +let [, gpg_verify] = repo.remote_get_gpg_verify('bar'); +assertEquals(gpg_verify, true); +repoConfig = repo.copy_config(); +repoConfig.set_boolean('remote "bar"', 'gpg-verify', false); +repo.write_config(repoConfig); +repo.reload_config(null); +[, gpg_verify] = repo.remote_get_gpg_verify('bar'); +assertEquals(gpg_verify, false); + +print("ok config-remote-in-config-file-succeeds"); + +// Trying to set a remote config option via write_config() for a remote +// defined in the config dir should fail with G_IO_ERROR_EXISTS +repoConfig = repo.copy_config(); +repoConfig.set_boolean('remote "baz"', 'gpg-verify', false); +try { + if (repo.write_config(repoConfig)) + throw new Error("config of remote in config dir should fail"); +} catch (e) { + if (!(e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))) + throw e; +} + +print("ok config-remote-in-config-dir-fails"); From 93038bcf712d36e178b6d1915984dc142712580a Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 13 Sep 2017 11:18:04 -0400 Subject: [PATCH 79/83] build-sys: Add -Werror=switch We use the "exhaustive enum" pattern (i.e. no `default:`) in some places so we're forced to touch all users when adding cases. Closes: #1167 Approved by: peterbaouoft --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 88dbc709..114264b5 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,7 @@ CC_CHECK_FLAGS_APPEND([WARN_CFLAGS], [CFLAGS], [\ -Werror=pointer-arith -Werror=init-self \ -Werror=missing-declarations \ -Werror=return-type \ + -Werror=switch \ -Werror=overflow \ -Werror=int-conversion \ -Werror=parenthesis \ From 8d3752a0d6034b378724134277e0fa1004591bb6 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 12 Sep 2017 10:31:39 -0400 Subject: [PATCH 80/83] lib/repo: Port tmpdir locking func to new style Prep for future work. Closes: #1168 Approved by: jlebon --- src/libostree/ostree-repo.c | 41 +++++++++++++++---------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 3d56bb55..0a7cf3e3 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -5148,19 +5148,17 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - gboolean reusing_dir = FALSE; - gboolean did_lock; - g_autofree char *tmpdir_name = NULL; - glnx_fd_close int tmpdir_fd = -1; - g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - g_return_val_if_fail (_ostree_repo_is_locked_tmpdir (tmpdir_prefix), FALSE); /* Look for existing tmpdir (with same prefix) to reuse */ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (tmpdir_dfd, ".", FALSE, &dfd_iter, error)) - goto out; + return FALSE; + gboolean reusing_dir = FALSE; + gboolean did_lock = FALSE; + g_autofree char *tmpdir_name = NULL; + glnx_fd_close int tmpdir_fd = -1; while (tmpdir_name == NULL) { struct dirent *dent; @@ -5168,7 +5166,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, g_autoptr(GError) local_error = NULL; if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) - goto out; + return FALSE; if (dent == NULL) break; @@ -5189,7 +5187,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, else { g_propagate_error (error, g_steal_pointer (&local_error)); - goto out; + return FALSE; } } @@ -5198,12 +5196,12 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, if (!_ostree_repo_try_lock_tmpdir (tmpdir_dfd, dent->d_name, file_lock_out, &did_lock, error)) - goto out; + return FALSE; if (!did_lock) continue; /* Touch the reused directory so that we don't accidentally - * remove it due to being old when cleaning up the tmpdir + * remove it due to being old when cleaning up the tmpdir. */ (void)futimens (existing_tmpdir_fd, NULL); @@ -5215,24 +5213,22 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, while (tmpdir_name == NULL) { - g_autofree char *tmpdir_name_template = g_strconcat (tmpdir_prefix, "XXXXXX", NULL); - glnx_fd_close int new_tmpdir_fd = -1; - /* No existing tmpdir found, create a new */ - + g_autofree char *tmpdir_name_template = g_strconcat (tmpdir_prefix, "XXXXXX", NULL); if (!glnx_mkdtempat (tmpdir_dfd, tmpdir_name_template, 0777, error)) - goto out; + return FALSE; + glnx_fd_close int new_tmpdir_fd = -1; if (!glnx_opendirat (tmpdir_dfd, tmpdir_name_template, FALSE, &new_tmpdir_fd, error)) - goto out; + return FALSE; /* Note, at this point we can race with another process that picks up this * new directory. If that happens we need to retry, making a new directory. */ if (!_ostree_repo_try_lock_tmpdir (tmpdir_dfd, tmpdir_name_template, file_lock_out, &did_lock, error)) - goto out; + return FALSE; if (!did_lock) continue; @@ -5242,16 +5238,11 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, if (tmpdir_name_out) *tmpdir_name_out = g_steal_pointer (&tmpdir_name); - if (tmpdir_fd_out) *tmpdir_fd_out = glnx_steal_fd (&tmpdir_fd); - if (reusing_dir_out) *reusing_dir_out = reusing_dir; - - ret = TRUE; - out: - return ret; + return TRUE; } /* See ostree-repo-private.h for more information about this */ From 051cdf396c4e2aed6fc1aad74dbf4d1a064b72d7 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 8 Sep 2017 17:07:45 -0400 Subject: [PATCH 81/83] lib/checkout: Rename disjoint union, change to merge identical files It turns out that librpm automatically merges identical files between distinct packages, and this occurs in practice with Fedora today between `chkconfig` and `initscripts` for exmaple. Since we added this for rpm-ostree, we basically want to do what librpm does, let's change the semantics to do a merge. While we're here rename to `UNION_IDENTICAL`. Closes: #1156 Approved by: jlebon --- bash/ostree | 2 +- man/ostree-checkout.xml | 9 +- src/libostree/ostree-repo-checkout.c | 176 ++++++++++++++++++++------- src/libostree/ostree-repo.h | 4 +- src/ostree/ot-builtin-checkout.c | 26 ++-- tests/basic-test.sh | 77 ++++++++---- 6 files changed, 208 insertions(+), 86 deletions(-) diff --git a/bash/ostree b/bash/ostree index 4ebe22c3..40326102 100644 --- a/bash/ostree +++ b/bash/ostree @@ -696,7 +696,7 @@ _ostree_checkout() { --require-hardlinks -H --union --union-add - --disjoint-union + --union-identical --user-mode -U --whiteouts " diff --git a/man/ostree-checkout.xml b/man/ostree-checkout.xml index 07d44b34..aba70741 100644 --- a/man/ostree-checkout.xml +++ b/man/ostree-checkout.xml @@ -98,11 +98,12 @@ Boston, MA 02111-1307, USA. - + - - When layering checkouts, error out if a file would be replaced, but add new files and directories - + Like --union, but error out + if a file would be replaced with a different file. Add new files + and directories, ignore identical files, and keep existing + directories. Requires -H. diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index dbdbf058..868cd186 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -188,8 +188,6 @@ create_file_copy_from_input_at (OstreeRepo *repo, GCancellable *cancellable, GError **error) { - const gboolean union_mode = options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; - const gboolean add_mode = options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES; const gboolean sepolicy_enabled = options->sepolicy && !repo->disable_xattrs; g_autoptr(GVariant) modified_xattrs = NULL; @@ -218,23 +216,51 @@ create_file_copy_from_input_at (OstreeRepo *repo, return FALSE; } - if (symlinkat (g_file_info_get_symlink_target (file_info), - destination_dfd, destination_name) < 0) + const char *target = g_file_info_get_symlink_target (file_info); + if (symlinkat (target, destination_dfd, destination_name) < 0) { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat"); + /* Handle union/add behaviors if we get EEXIST */ - if (errno == EEXIST && union_mode) + switch (options->overwrite_mode) { - /* Unioning? Let's unlink and try again */ - (void) unlinkat (destination_dfd, destination_name, 0); - if (symlinkat (g_file_info_get_symlink_target (file_info), - destination_dfd, destination_name) < 0) - return glnx_throw_errno (error); + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + return glnx_throw_errno_prefix (error, "symlinkat"); + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + { + /* Unioning? Let's unlink and try again */ + (void) unlinkat (destination_dfd, destination_name, 0); + if (symlinkat (target, destination_dfd, destination_name) < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + } + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + /* Note early return - we don't want to set the xattrs below */ + return TRUE; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + /* See the comments for the hardlink version of this + * for why we do this. + */ + struct stat dest_stbuf; + if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (S_ISLNK (dest_stbuf.st_mode)) + { + g_autofree char *dest_target = + glnx_readlinkat_malloc (destination_dfd, destination_name, + cancellable, error); + if (!dest_target) + return FALSE; + /* In theory we could also compare xattrs...but eh */ + if (g_str_equal (dest_target, target)) + return TRUE; + } + errno = EEXIST; + return glnx_throw_errno_prefix (error, "symlinkat"); + } } - else if (errno == EEXIST && add_mode) - /* Note early return - we don't want to set the xattrs below */ - return TRUE; - else - return glnx_throw_errno (error); } /* Process ownership and xattrs now that we made the link */ @@ -255,7 +281,6 @@ create_file_copy_from_input_at (OstreeRepo *repo, else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { g_auto(GLnxTmpfile) tmpf = { 0, }; - GLnxLinkTmpfileReplaceMode replace_mode; if (!glnx_open_tmpfile_linkable_at (destination_dfd, ".", O_WRONLY | O_CLOEXEC, &tmpf, error)) @@ -278,12 +303,23 @@ create_file_copy_from_input_at (OstreeRepo *repo, return FALSE; /* The add/union/none behaviors map directly to GLnxLinkTmpfileReplaceMode */ - if (add_mode) - replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST; - else if (union_mode) - replace_mode = GLNX_LINK_TMPFILE_REPLACE; - else - replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + GLnxLinkTmpfileReplaceMode replace_mode; + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + replace_mode = GLNX_LINK_TMPFILE_REPLACE; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + /* We don't support copying in union identical */ + g_assert_not_reached (); + break; + } if (!glnx_link_tmpfile_at (&tmpf, replace_mode, destination_dfd, destination_name, @@ -329,25 +365,61 @@ checkout_file_hardlink (OstreeRepo *self, else if (allow_noent && errno == ENOENT) { } - else if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES) + else if (errno == EEXIST) { - /* In this mode, we keep existing content. Distinguish this case though to - * avoid inserting into the devino cache. - */ - ret_result = HARDLINK_RESULT_SKIP_EXISTED; - } - else if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) - { - /* Idiocy, from man rename(2) - * - * "If oldpath and newpath are existing hard links referring to - * the same file, then rename() does nothing, and returns a - * success status." - * - * So we can't make this atomic. - */ - (void) unlinkat (destination_dfd, destination_name, 0); - goto again; + /* When we get EEXIST, we need to handle the different overwrite modes. */ + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + /* Just throw */ + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + /* In this mode, we keep existing content. Distinguish this case though to + * avoid inserting into the devino cache. + */ + ret_result = HARDLINK_RESULT_SKIP_EXISTED; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + { + /* Idiocy, from man rename(2) + * + * "If oldpath and newpath are existing hard links referring to + * the same file, then rename() does nothing, and returns a + * success status." + * + * So we can't make this atomic. + */ + (void) unlinkat (destination_dfd, destination_name, 0); + goto again; + } + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + /* In this mode, we error out on EEXIST *unless* the files are already + * hardlinked, which is what rpm-ostree wants for package layering. + * https://github.com/projectatomic/rpm-ostree/issues/982 + * + * This should be similar to the librpm version: + * https://github.com/rpm-software-management/rpm/blob/e3cd2bc85e0578f158d14e6f9624eb955c32543b/lib/rpmfi.c#L921 + * in rpmfilesCompare(). + */ + struct stat src_stbuf; + if (!glnx_fstatat (srcfd, loose_path, &src_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + struct stat dest_stbuf; + if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + const gboolean is_identical = + (src_stbuf.st_dev == dest_stbuf.st_dev && + src_stbuf.st_ino == dest_stbuf.st_ino); + if (is_identical) + ret_result = HARDLINK_RESULT_SKIP_EXISTED; + else + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + break; + } + } } else { @@ -652,13 +724,20 @@ checkout_tree_at_recurse (OstreeRepo *self, */ if (TEMP_FAILURE_RETRY (mkdirat (destination_parent_fd, destination_name, 0700)) < 0) { - if (errno == EEXIST && - (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES - || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES - || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES)) - did_exist = TRUE; - else - return glnx_throw_errno (error); + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "mkdirat"); + + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + return glnx_throw_errno_prefix (error, "mkdirat"); + /* All of these cases are the same for directories */ + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + did_exist = TRUE; + break; + } } } @@ -1002,6 +1081,9 @@ ostree_repo_checkout_at (OstreeRepo *self, g_return_val_if_fail (!(options->force_copy && options->no_copy_fallback), FALSE); g_return_val_if_fail (!options->sepolicy || options->force_copy, FALSE); + /* union identical requires hardlink mode */ + g_return_val_if_fail (!(options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL && + !options->no_copy_fallback), FALSE); g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error); if (!commit_root) diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 58b1a1dc..227fe597 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -832,13 +832,13 @@ typedef enum { * @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories * @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories - * @OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES: When layering checkouts, error out if a file would be replaced, but add new files and directories + * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: Like UNION_FILES, but error if files are not identical (requires hardlink checkouts) */ typedef enum { OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1, OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES = 2, /* Since: 2017.3 */ - OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES = 3 /* Since: 2017.11 */ + OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL = 3, /* Since: 2017.11 */ } OstreeRepoCheckoutOverwriteMode; _OSTREE_PUBLIC diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index a3494ae3..170d24e9 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -37,7 +37,7 @@ static gboolean opt_disable_cache; static char *opt_subpath; static gboolean opt_union; static gboolean opt_union_add; -static gboolean opt_disjoint_union; +static gboolean opt_union_identical; static gboolean opt_whiteouts; static gboolean opt_from_stdin; static char *opt_from_file; @@ -73,7 +73,7 @@ static GOptionEntry options[] = { { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, { "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL }, - { "disjoint-union", 0, 0, G_OPTION_ARG_NONE, &opt_disjoint_union, "When layering checkouts, error out if a file would be replaced, but add new files and directories", NULL }, + { "union-identical", 0, 0, G_OPTION_ARG_NONE, &opt_union_identical, "When layering checkouts, error out if a file would be replaced with a different version, but add new files and directories", NULL }, { "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL }, { "allow-noent", 0, 0, G_OPTION_ARG_NONE, &opt_allow_noent, "Do nothing if specified path does not exist", NULL }, { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL }, @@ -101,7 +101,7 @@ process_one_checkout (OstreeRepo *repo, * convenient infrastructure for testing C APIs with data. */ if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || - opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_disjoint_union) + opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_union_identical) { OstreeRepoCheckoutAtOptions options = { 0, }; @@ -114,16 +114,16 @@ process_one_checkout (OstreeRepo *repo, "Cannot specify both --union and --union-add"); goto out; } - if (opt_union && opt_disjoint_union) + if (opt_union && opt_union_identical) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Cannot specify both --union and --disjoint-union"); + "Cannot specify both --union and --union-identical"); goto out; } - if (opt_union_add && opt_disjoint_union) + if (opt_union_add && opt_union_identical) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Cannot specify both --union-add and --disjoint-union "); + "Cannot specify both --union-add and --union-identical "); goto out; } if (opt_require_hardlinks && opt_force_copy) @@ -135,8 +135,16 @@ process_one_checkout (OstreeRepo *repo, options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; else if (opt_union_add) options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES; - else if (opt_disjoint_union) - options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES; + else if (opt_union_identical) + { + if (!opt_require_hardlinks) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "--union-identical requires --require-hardlinks"); + goto out; + } + options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL; + } if (opt_whiteouts) options.process_whiteouts = TRUE; if (subpath) diff --git a/tests/basic-test.sh b/tests/basic-test.sh index 6b43ca90..5058af1d 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -26,6 +26,7 @@ python -c 'import yaml; yaml.safe_load(open("version.yaml"))' echo "ok yaml version" CHECKOUT_U_ARG="" +CHECKOUT_H_ARGS="-H" COMMIT_ARGS="" DIFF_ARGS="" if is_bare_user_only_repo repo; then @@ -36,6 +37,11 @@ if is_bare_user_only_repo repo; then DIFF_ARGS="--owner-uid=0 --owner-gid=0 --no-xattrs" # Also, since we can't check out uid=0 files we need to check out in user mode CHECKOUT_U_ARG="-U" + CHECKOUT_H_ARGS="-U -H" +else + if grep -E -q '^mode=bare-user' repo/config; then + CHECKOUT_H_ARGS="-U -H" + fi fi validate_checkout_basic() { @@ -469,31 +475,56 @@ assert_file_has_content checkout-test-union-add/union-add-test 'existing file fo assert_file_has_content checkout-test-union-add/union-add-test2 'another file for union add testing' echo "ok checkout union add" -# Create some new files for testing +# Test --union-identical +# Prepare data: cd ${test_tmpdir} -mkdir disjoint-union-test -mkdir disjoint-union-test/test_one -chmod a+w disjoint-union-test/test_one -echo 'file for add dirs testing' > disjoint-union-test/test_one/test_file -$OSTREE commit ${COMMIT_ARGS} -b test-disjoint-union --tree=dir=disjoint-union-test -$OSTREE checkout --disjoint-union test-disjoint-union checkout-test-disjoint-union -echo "ok adding new directories and new file" -# Make a new file, and try the checkout again -echo 'second test file' > disjoint-union-test/test_one/test_second_file -$OSTREE commit ${COMMIT_ARGS} -b test-disjoint-union --tree=dir=disjoint-union-test -# Check out the latest commit, should fail due to presence of existing files -if $OSTREE checkout --disjoint-union test-disjoint-union checkout-test-disjoint-union 2> err.txt; then - assert_not_reached "checking out files unexpectedly succeeded!" +for x in $(seq 3); do + mkdir -p pkg${x}/usr/{bin,share/licenses} + # Separate binaries and symlinks + echo 'binary for pkg'${x} > pkg${x}/usr/bin/pkg${x} + ln -s pkg${x} pkg${x}/usr/bin/link${x} + # But they share the GPL + echo 'this is the GPL' > pkg${x}/usr/share/licenses/COPYING + ln -s COPYING pkg${x}/usr/share/licenses/LICENSE + $OSTREE commit -b union-identical-pkg${x} --tree=dir=pkg${x} +done +rm union-identical-test -rf +for x in $(seq 3); do + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg${x} union-identical-test +done +if $OSTREE checkout ${CHECKOUT_H_ARGS/-H/} --union-identical union-identical-pkg${x} union-identical-test-tmp 2>err.txt; then + fatal "--union-identical without -H" fi -assert_file_has_content err.txt 'File exists' -# Verify that Union mode still functions properly -rm checkout-test-disjoint-union/test_one/test_file -echo 'file for testing union mode alongwith disjoint-union mode' > checkout-test-disjoint-union/test_one/test_file -$OSTREE checkout --union test-disjoint-union checkout-test-disjoint-union -assert_has_file checkout-test-disjoint-union/test_one/test_second_file -# This shows the file with same name has been successfully overwriten -assert_file_has_content checkout-test-disjoint-union/test_one/test_file 'file for add dirs testing' -echo "ok checkout disjoint union" +assert_file_has_content err.txt "error:.*--union-identical requires --require-hardlinks" +for x in $(seq 3); do + for v in pkg link; do + assert_file_has_content union-identical-test/usr/bin/${v}${x} "binary for pkg"${x} + done + for v in COPYING LICENSE; do + assert_file_has_content union-identical-test/usr/share/licenses/${v} GPL + done +done +echo "ok checkout union identical merges" + +# Make conflicting packages, one with regfile, one with symlink +mkdir -p pkg-conflict1bin/usr/{bin,share/licenses} +echo 'binary for pkg-conflict1bin' > pkg-conflict1bin/usr/bin/pkg1 +echo 'this is the GPL' > pkg-conflict1bin/usr/share/licenses/COPYING +$OSTREE commit -b union-identical-conflictpkg1bin --tree=dir=pkg-conflict1bin +mkdir -p pkg-conflict1link/usr/{bin,share/licenses} +ln -s somewhere-else > pkg-conflict1link/usr/bin/pkg1 +echo 'this is the GPL' > pkg-conflict1link/usr/share/licenses/COPYING +$OSTREE commit -b union-identical-conflictpkg1link --tree=dir=pkg-conflict1link + +for v in bin link; do + rm union-identical-test -rf + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg1 union-identical-test + if $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-conflictpkg1${v} union-identical-test 2>err.txt; then + fatal "union identical $v succeeded?" + fi + assert_file_has_content err.txt 'error:.*File exists' +done +echo "ok checkout union identical conflicts" cd ${test_tmpdir} rm files -rf && mkdir files From 1c2d34407415c499ac3e0f3c89e1eca4981d8ef9 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 13 Sep 2017 12:09:51 -0400 Subject: [PATCH 82/83] tests: Port some bits of C to new style Where we can; perhaps after updating libglnx we should use the new test error macro? Closes: #1169 Approved by: jlebon --- tests/libostreetest.c | 47 ++++++++++------------------------ tests/test-libarchive-import.c | 29 ++++++++------------- 2 files changed, 24 insertions(+), 52 deletions(-) diff --git a/tests/libostreetest.c b/tests/libostreetest.c index bc4c49f6..f1a01e68 100644 --- a/tests/libostreetest.c +++ b/tests/libostreetest.c @@ -33,9 +33,7 @@ gboolean ot_test_run_libtest (const char *cmd, GError **error) { - gboolean ret = FALSE; const char *srcdir = g_getenv ("G_TEST_SRCDIR"); - int estatus; g_autoptr(GPtrArray) argv = g_ptr_array_new (); g_autoptr(GString) cmdstr = g_string_new (""); @@ -50,53 +48,39 @@ ot_test_run_libtest (const char *cmd, GError **error) g_ptr_array_add (argv, cmdstr->str); g_ptr_array_add (argv, NULL); + int estatus; if (!g_spawn_sync (NULL, (char**)argv->pdata, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &estatus, error)) - goto out; - + return FALSE; if (!g_spawn_check_exit_status (estatus, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } OstreeRepo * ot_test_setup_repo (GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); - glnx_unref_object OstreeRepo* ret_repo = NULL; - if (!ot_test_run_libtest ("setup_test_repository archive", error)) - goto out; - - ret_repo = ostree_repo_new (repo_path); + return NULL; + g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); + g_autoptr(OstreeRepo) ret_repo = ostree_repo_new (repo_path); if (!ostree_repo_open (ret_repo, cancellable, error)) - goto out; + return NULL; - ret = TRUE; - out: - if (ret) - return g_steal_pointer (&ret_repo); - return NULL; + return g_steal_pointer (&ret_repo); } OstreeSysroot * ot_test_setup_sysroot (GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); - glnx_unref_object OstreeSysroot *ret_sysroot = NULL; - struct statfs stbuf; - if (!ot_test_run_libtest ("setup_os_repository \"archive\" \"syslinux\"", error)) - goto out; + return FALSE; + struct statfs stbuf; { g_autoptr(GString) buf = g_string_new ("mutable-deployments"); if (statfs ("/", &stbuf) < 0) return glnx_null_throw_errno (error); @@ -113,11 +97,6 @@ ot_test_setup_sysroot (GCancellable *cancellable, g_setenv ("OSTREE_SYSROOT_DEBUG", buf->str, TRUE); } - ret_sysroot = ostree_sysroot_new (sysroot_path); - - ret = TRUE; - out: - if (ret) - return g_steal_pointer (&ret_sysroot); - return NULL; + g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); + return ostree_sysroot_new (sysroot_path); } diff --git a/tests/test-libarchive-import.c b/tests/test-libarchive-import.c index 6047d359..77c2dd30 100644 --- a/tests/test-libarchive-import.c +++ b/tests/test-libarchive-import.c @@ -260,34 +260,31 @@ import_write_and_ref (OstreeRepo *repo, OstreeRepoCommitModifier *modifier, GError **error) { - gboolean ret = FALSE; - glnx_unref_object GFile *root = NULL; - g_autofree char *commit_checksum = NULL; - glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + g_autoptr(OstreeMutableTree) mtree = ostree_mutable_tree_new (); if (!ostree_repo_prepare_transaction (repo, NULL, NULL, error)) - goto out; + return FALSE; if (!ostree_repo_import_archive_to_mtree (repo, opts, a, mtree, modifier, NULL, error)) - goto out; + return FALSE; + g_autoptr(GFile) root = NULL; if (!ostree_repo_write_mtree (repo, mtree, &root, NULL, error)) - goto out; + return FALSE; + g_autofree char *commit_checksum = NULL; if (!ostree_repo_write_commit (repo, NULL, "", "", NULL, OSTREE_REPO_FILE (root), &commit_checksum, NULL, error)) - goto out; + return FALSE; ostree_repo_transaction_set_ref (repo, NULL, ref, commit_checksum); if (!ostree_repo_commit_transaction (repo, NULL, NULL, error)) - goto out; + return FALSE; - ret = TRUE; -out: - return ret; + return TRUE; } static void @@ -413,7 +410,7 @@ test_libarchive_xattr_callback (gconstpointer data) GError *error = NULL; g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0 }; - OstreeRepoCommitModifier *modifier = NULL; + g_autoptr(OstreeRepoCommitModifier) modifier = NULL; char buf[7] = { 0 }; if (skip_if_no_xattr (td)) @@ -452,8 +449,6 @@ test_libarchive_xattr_callback (gconstpointer data) g_assert_cmpstr (buf, ==, "mydata"); out: - if (modifier) - ostree_repo_commit_modifier_unref (modifier); g_assert_no_error (error); } @@ -543,7 +538,7 @@ test_libarchive_selinux (gconstpointer data) g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0 }; glnx_unref_object OstreeSePolicy *sepol = NULL; - OstreeRepoCommitModifier *modifier = NULL; + g_autoptr(OstreeRepoCommitModifier) modifier = NULL; char buf[64] = { 0 }; if (skip_if_no_xattr (td)) @@ -591,8 +586,6 @@ test_libarchive_selinux (gconstpointer data) g_assert_cmpstr (buf, ==, "system_u:object_r:etc_t:s0"); out: - if (modifier) - ostree_repo_commit_modifier_unref (modifier); g_assert_no_error (error); } From 6c0738a000800856d09774d50d16d84c1b537a7b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 14 Sep 2017 10:44:04 -0400 Subject: [PATCH 83/83] Release 2017.11 Closes: #1173 Approved by: jlebon --- configure.ac | 2 +- src/libostree/libostree-devel.sym | 5 +++-- src/libostree/libostree-released.sym | 3 +++ tests/test-symbols.sh | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 114264b5..2461f4d0 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ m4_define([year_version], [2017]) m4_define([release_version], [11]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) -is_release_build=no +is_release_build=yes AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIR([buildutil]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index 76aa280f..07f918a1 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -18,8 +18,9 @@ ***/ /* Add new symbols here. Release commits should copy this section into -released.sym. */ -LIBOSTREE_2017.11 { -} LIBOSTREE_2017.10; +LIBOSTREE_2017.12 { +} LIBOSTREE_2017.11; + /* 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 diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym index fe98858d..03cb952d 100644 --- a/src/libostree/libostree-released.sym +++ b/src/libostree/libostree-released.sym @@ -427,6 +427,9 @@ LIBOSTREE_2017.10 { */ } LIBOSTREE_2017.8; +LIBOSTREE_2017.11 { +} LIBOSTREE_2017.10; + /* NOTE: Only add more content here in release commits! See the * comments at the top of this file. */ diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh index b324d1bf..f54b64ee 100755 --- a/tests/test-symbols.sh +++ b/tests/test-symbols.sh @@ -52,7 +52,7 @@ echo 'ok documented symbols' # ONLY update this checksum in release commits! cat > released-sha256.txt <