Add a notion of "physical" sysroot, use for remote writing
authorColin Walters <walters@verbum.org>
Tue, 30 May 2017 18:07:13 +0000 (14:07 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 18 Jul 2017 18:58:06 +0000 (18:58 +0000)
(Note this PR was reverted in <https://github.com/ostreedev/ostree/pull/902>;
 this version should be better)

Using `${sysroot}` to mean the physical storage root: We don't want to write to
`${sysroot}/etc/ostree/remotes.d`, since nothing will read it, and really
`${sysroot}` should just have `/ostree` (ideally). Today the Anaconda rpmostree
code ends up writing there. Fix this by adding a notion of "physical" sysroot.
We determine whether the path is physical by checking for `/sysroot`, which
exists in deployment roots (and there shouldn't be a `${sysroot}/sysroot`).

In order to unit test this, I added a `--sysroot` argument to `remote add`.
However, doing this better would require reworking the command line parsing for
the `remote` argument to support specifying `--repo` or `--sysroot`, and I
didn't quite want to do that yet in this patch.

This second iteration of this patch fixes the bug we hit the first time;
embarassingly enough I broke `ostree remote list` finding system remotes.
The fix is to have `ostree_repo_open()` figure out whether it's the same
as `/ostree/repo` for now.

Down the line...we might consider having the `ostree remote` command line itself
instatiate an `OstreeSysroot` by default, but this maximizes compatibility; we
just have to pay a small cost that `ostree` usage outside of that case like
`ostree static-delta` in a releng Jenkins job or whatever will do this `stat()`
too.

Closes: https://github.com/ostreedev/ostree/issues/892
Closes: #1008
Approved by: mbarnes

13 files changed:
src/libostree/ostree-repo-private.h
src/libostree/ostree-repo.c
src/libostree/ostree-sysroot-private.h
src/libostree/ostree-sysroot.c
src/ostree/ot-main.c
src/ostree/ot-main.h
src/ostree/ot-remote-builtin-add.c
src/ostree/ot-remote-builtin-delete.c
tests/admin-test.sh
tests/installed/itest-remotes.sh [new file with mode: 0755]
tests/test-admin-deploy-grub2.sh
tests/test-admin-deploy-syslinux.sh
tests/test-admin-deploy-uboot.sh

index dc49ed3be3c579b6f01fcb16532beeab800cd9b3..da448bbee038c111ce84d04cfe2c5fae754c40d6 100644 (file)
@@ -80,6 +80,13 @@ struct OstreeRepoCommitModifier {
   GHashTable *devino_cache;
 };
 
+typedef enum {
+  OSTREE_REPO_SYSROOT_KIND_UNKNOWN,
+  OSTREE_REPO_SYSROOT_KIND_NO,  /* Not a system repo */
+  OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT, /* Constructed via ostree_sysroot_get_repo() */
+  OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE, /* We match /ostree/repo */
+} OstreeRepoSysrootKind;
+
 /**
  * OstreeRepo:
  *
@@ -101,6 +108,7 @@ struct OstreeRepo {
   int objects_dir_fd;
   int uncompressed_objects_dir_fd;
   GFile *sysroot_dir;
+  GWeakRef sysroot; /* Weak to avoid a circular ref; see also `is_system` */
   char *remotes_config_dir;
 
   GHashTable *txn_refs;  /* (element-type utf8 utf8) */
@@ -118,7 +126,7 @@ struct OstreeRepo {
 
   gboolean inited;
   gboolean writable;
-  gboolean is_system; /* Was this repo created via ostree_sysroot_get_repo() ? */
+  OstreeRepoSysrootKind sysroot_kind;
   GError *writable_error;
   gboolean in_transaction;
   gboolean disable_fsync;
index 815d2d654fa894e0d6e916599e13221b4303de57..48c9a134e136c6171bdf70e458f6bf9251b706a0 100644 (file)
@@ -32,6 +32,7 @@
 #include <glnx-console.h>
 
 #include "ostree-core-private.h"
+#include "ostree-sysroot-private.h"
 #include "ostree-remote-private.h"
 #include "ostree-repo-private.h"
 #include "ostree-repo-file.h"
@@ -125,6 +126,10 @@ G_DEFINE_TYPE (OstreeRepo, ostree_repo, G_TYPE_OBJECT)
 
 #define SYSCONF_REMOTES SHORTENED_SYSCONFDIR "/ostree/remotes.d"
 
+static GFile *
+get_remotes_d_dir (OstreeRepo          *self,
+                   GFile               *sysroot);
+
 OstreeRemote *
 _ostree_repo_get_remote (OstreeRepo  *self,
                          const char  *name,
@@ -467,6 +472,7 @@ ostree_repo_finalize (GObject *object)
   if (self->uncompressed_objects_dir_fd != -1)
     (void) close (self->uncompressed_objects_dir_fd);
   g_clear_object (&self->sysroot_dir);
+  g_weak_ref_clear (&self->sysroot);
   g_free (self->remotes_config_dir);
 
   if (self->loose_object_devino_hash)
@@ -547,10 +553,6 @@ ostree_repo_constructed (GObject *object)
 
   g_assert (self->repodir != NULL);
 
-  /* Ensure the "sysroot-path" property is set. */
-  if (self->sysroot_dir == NULL)
-    self->sysroot_dir = g_object_ref (_ostree_get_default_sysroot_path ());
-
   G_OBJECT_CLASS (ostree_repo_parent_class)->constructed (object);
 }
 
@@ -645,6 +647,7 @@ ostree_repo_init (OstreeRepo *self)
   self->objects_dir_fd = -1;
   self->uncompressed_objects_dir_fd = -1;
   self->commit_stagedir_lock = empty_lockfile;
+  self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_UNKNOWN;
 }
 
 /**
@@ -728,18 +731,20 @@ ostree_repo_new_default (void)
 gboolean
 ostree_repo_is_system (OstreeRepo   *repo)
 {
-  g_autoptr(GFile) default_repo_path = NULL;
-
   g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
 
   /* If we were created via ostree_sysroot_get_repo(), we know the answer is yes
    * without having to compare file paths.
    */
-  if (repo->is_system)
+  if (repo->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT ||
+      repo->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE)
     return TRUE;
 
-  default_repo_path = get_default_repo_path (repo->sysroot_dir);
+  /* No sysroot_dir set?  Not a system repo then. */
+  if (!repo->sysroot_dir)
+    return FALSE;
 
+  g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir);
   return g_file_equal (repo->repodir, default_repo_path);
 }
 
@@ -916,24 +921,11 @@ impl_repo_remote_add (OstreeRepo     *self,
 
   remote = ostree_remote_new (name);
 
-  /* The OstreeRepo maintains its own internal system root path,
-   * so we need to not only check if a "sysroot" argument was given
-   * but also whether it's actually different from OstreeRepo's.
-   *
-   * XXX Having API regret about the "sysroot" argument now.
-   */
-  gboolean different_sysroot = FALSE;
-  if (sysroot != NULL)
-    different_sysroot = !g_file_equal (sysroot, self->sysroot_dir);
-
-  if (different_sysroot || ostree_repo_is_system (self))
+  g_autoptr(GFile) etc_ostree_remotes_d = get_remotes_d_dir (self, sysroot);
+  if (etc_ostree_remotes_d)
     {
       g_autoptr(GError) local_error = NULL;
 
-      if (sysroot == NULL)
-        sysroot = self->sysroot_dir;
-
-      g_autoptr(GFile) etc_ostree_remotes_d = g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES);
       if (!g_file_make_directory_with_parents (etc_ostree_remotes_d,
                                                cancellable, &local_error))
         {
@@ -1874,14 +1866,55 @@ append_one_remote_config (OstreeRepo      *self,
 }
 
 static GFile *
-get_remotes_d_dir (OstreeRepo          *self)
+get_remotes_d_dir (OstreeRepo          *self,
+                   GFile               *sysroot)
 {
-  if (self->remotes_config_dir != NULL)
+  /* 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);
-  else if (ostree_repo_is_system (self))
-    return g_file_resolve_relative_path (self->sysroot_dir, SYSCONF_REMOTES);
 
-  return NULL;
+  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
+   * provided, use it. Otherwise, check to see whether we reference
+   * /ostree/repo, or if not that, see if we have a ref to a sysroot (and it's
+   * physical).
+   */
+  g_autoptr(OstreeSysroot) sysroot_ref = NULL;
+  if (sysroot == NULL)
+    {
+      /* No explicit sysroot?  Let's see if we have a kind */
+      switch (self->sysroot_kind)
+        {
+        case OSTREE_REPO_SYSROOT_KIND_UNKNOWN:
+          g_assert_not_reached ();
+          break;
+        case OSTREE_REPO_SYSROOT_KIND_NO:
+          break;
+        case OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE:
+          sysroot = sysroot_owned = g_file_new_for_path ("/");
+          break;
+        case OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT:
+          sysroot_ref = (OstreeSysroot*)g_weak_ref_get (&self->sysroot);
+          /* Only write to /etc/ostree/remotes.d if we are pointed at a deployment */
+          if (sysroot_ref != NULL && !sysroot_ref->is_physical)
+            sysroot = ostree_sysroot_get_path (sysroot_ref);
+          break;
+        }
+    }
+  /* For backwards compat, also fall back to the sysroot-path variable, which we
+   * don't set anymore internally, and I hope no one else uses.
+   */
+  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.
+   */
+  if (sysroot == NULL)
+    return NULL;
+  else
+    return g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES);
 }
 
 static gboolean
@@ -2036,7 +2069,7 @@ reload_remote_config (OstreeRepo          *self,
   if (!add_remotes_from_keyfile (self, self->config, NULL, error))
     return FALSE;
 
-  g_autoptr(GFile) remotes_d = get_remotes_d_dir (self);
+  g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL);
   if (remotes_d == NULL)
     return TRUE;
 
@@ -2101,6 +2134,7 @@ ostree_repo_open (OstreeRepo    *self,
                   GCancellable  *cancellable,
                   GError       **error)
 {
+  struct stat self_stbuf;
   struct stat stbuf;
 
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -2137,6 +2171,9 @@ ostree_repo_open (OstreeRepo    *self,
       return FALSE;
     }
 
+  if (!glnx_fstat (self->repo_dir_fd, &self_stbuf, error))
+    return FALSE;
+
   if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE,
                        &self->objects_dir_fd, error))
     {
@@ -2178,6 +2215,27 @@ ostree_repo_open (OstreeRepo    *self,
         return FALSE;
     }
 
+  /* If we weren't created via ostree_sysroot_get_repo(), for backwards
+   * compatibility we need to figure out now whether or not we refer to the
+   * system repo.  See also ostree-sysroot.c.
+   */
+  if (self->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_UNKNOWN)
+    {
+      struct stat system_stbuf;
+      /* Ignore any errors if we can't access /ostree/repo */
+      if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0)
+        {
+          /* Are we the same as /ostree/repo? */
+          if (self_stbuf.st_dev == system_stbuf.st_dev &&
+              self_stbuf.st_ino == system_stbuf.st_ino)
+            self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE;
+          else
+            self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
+        }
+      else
+        self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
+    }
+
   if (!ostree_repo_reload_config (self, cancellable, error))
     return FALSE;
 
@@ -4144,7 +4202,7 @@ find_keyring (OstreeRepo          *self,
       return g_steal_pointer (&file);
     }
 
-  g_autoptr(GFile) remotes_d = get_remotes_d_dir (self);
+  g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL);
   if (remotes_d)
     {
       g_autoptr(GFile) file2 = g_file_get_child (remotes_d, remote->keyring);
index 14ee5cad965c4c8730272858083d0fe66b9d85c2..82abc8e77fee240090ddaf8d2e9cd54fd02fd65f 100644 (file)
@@ -48,7 +48,8 @@ struct OstreeSysroot {
   GLnxLockFile lock;
 
   gboolean loaded;
-  
+
+  gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */
   GPtrArray *deployments;
   int bootversion;
   int subbootversion;
index 90868aae93fdb0cee985a682b32eea166514704a..d262a903166a0bc68aa0194d668dcf415b792bdd 100644 (file)
@@ -134,7 +134,9 @@ ostree_sysroot_constructed (GObject *object)
 
   repo_path = g_file_resolve_relative_path (self->path, "ostree/repo");
   self->repo = ostree_repo_new_for_sysroot_path (repo_path, self->path);
-  self->repo->is_system = TRUE;
+  self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT;
+  /* Hold a weak ref for the remote-add handling */
+  g_weak_ref_init (&self->repo->sysroot, object);
 
   G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object);
 }
@@ -813,6 +815,26 @@ ostree_sysroot_load_if_changed (OstreeSysroot  *self,
                                cancellable, error))
     return FALSE;
 
+  /* Determine whether we're "physical" or not, the first time we initialize */
+  if (!self->loaded)
+    {
+      /* If we have a booted deployment, the sysroot is / and we're definitely
+       * not physical.
+       */
+      if (self->booted_deployment)
+        self->is_physical = FALSE;  /* (the default, but explicit for clarity) */
+      /* Otherwise - check for /sysroot which should only exist in a deployment,
+       * not in ${sysroot} (a metavariable for the real physical root).
+       */
+      else if (fstatat (self->sysroot_fd, "sysroot", &stbuf, 0) < 0)
+        {
+          if (errno != ENOENT)
+            return glnx_throw_errno_prefix (error, "fstatat");
+          self->is_physical = TRUE;
+        }
+      /* Otherwise, the default is FALSE */
+    }
+
   self->bootversion = bootversion;
   self->subbootversion = subbootversion;
   self->deployments = deployments;
index 40d77f5f7189d3d3f65e1c714f5b3bf6238fb84c..ca4f15927290c3a72760550fe0637e655038eaf1 100644 (file)
@@ -207,6 +207,88 @@ ostree_run (int    argc,
   return 0;
 }
 
+/* Process a --repo arg; used below, and for the remote builtins */
+static OstreeRepo *
+parse_repo_option (GOptionContext *context,
+                   const char     *repo_path,
+                   gboolean        skip_repo_open,
+                   GCancellable   *cancellable,
+                   GError        **error)
+{
+  g_autoptr(OstreeRepo) repo = NULL;
+
+  if (repo_path == NULL)
+    {
+      g_autoptr(GError) local_error = NULL;
+
+      repo = ostree_repo_new_default ();
+      if (!ostree_repo_open (repo, cancellable, &local_error))
+        {
+          if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+            {
+              g_autofree char *help = NULL;
+
+              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                   "Command requires a --repo argument");
+
+              help = g_option_context_get_help (context, FALSE, NULL);
+              g_printerr ("%s", help);
+            }
+          else
+            {
+              g_propagate_error (error, g_steal_pointer (&local_error));
+            }
+          return NULL;
+        }
+    }
+  else
+    {
+      g_autoptr(GFile) repo_file = g_file_new_for_path (repo_path);
+
+      repo = ostree_repo_new (repo_file);
+      if (!skip_repo_open)
+        {
+          if (!ostree_repo_open (repo, cancellable, error))
+            return NULL;
+        }
+    }
+
+  return g_steal_pointer (&repo);
+}
+
+/* Used by the remote builtins which are special in taking --sysroot or --repo */
+gboolean
+ostree_parse_sysroot_or_repo_option (GOptionContext *context,
+                                     const char *sysroot_path,
+                                     const char *repo_path,
+                                     OstreeSysroot **out_sysroot,
+                                     OstreeRepo **out_repo,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+  g_autoptr(OstreeSysroot) sysroot = NULL;
+  g_autoptr(OstreeRepo) repo = NULL;
+  if (sysroot_path)
+    {
+      g_autoptr(GFile) sysroot_file = g_file_new_for_path (sysroot_path);
+      sysroot = ostree_sysroot_new (sysroot_file);
+      if (!ostree_sysroot_load (sysroot, cancellable, error))
+        return FALSE;
+      if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
+        return FALSE;
+    }
+  else
+    {
+      repo = parse_repo_option (context, repo_path, FALSE, cancellable, error);
+      if (!repo)
+        return FALSE;
+    }
+
+  ot_transfer_out_value (out_sysroot, &sysroot);
+  ot_transfer_out_value (out_repo, &repo);
+  return TRUE;
+}
+
 gboolean
 ostree_option_context_parse (GOptionContext *context,
                              const GOptionEntry *main_entries,
@@ -217,7 +299,7 @@ ostree_option_context_parse (GOptionContext *context,
                              GCancellable *cancellable,
                              GError **error)
 {
-  glnx_unref_object OstreeRepo *repo = NULL;
+  g_autoptr(OstreeRepo) repo = NULL;
 
   /* Entries are listed in --help output in the order added.  We add the
    * main entries ourselves so that we can add the --repo entry first. */
@@ -254,40 +336,12 @@ ostree_option_context_parse (GOptionContext *context,
   if (opt_verbose)
     g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, message_handler, NULL);
 
-  if (opt_repo == NULL && !(flags & OSTREE_BUILTIN_FLAG_NO_REPO))
-    {
-      g_autoptr(GError) local_error = NULL;
-
-      repo = ostree_repo_new_default ();
-      if (!ostree_repo_open (repo, cancellable, &local_error))
-        {
-          if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-            {
-              g_autofree char *help = NULL;
-
-              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                                   "Command requires a --repo argument");
-
-              help = g_option_context_get_help (context, FALSE, NULL);
-              g_printerr ("%s", help);
-            }
-          else
-            {
-              g_propagate_error (error, g_steal_pointer (&local_error));
-            }
-          return FALSE;
-        }
-    }
-  else if (opt_repo != NULL)
+  if (!(flags & OSTREE_BUILTIN_FLAG_NO_REPO))
     {
-      g_autoptr(GFile) repo_file = g_file_new_for_path (opt_repo);
-
-      repo = ostree_repo_new (repo_file);
-      if (!(flags & OSTREE_BUILTIN_FLAG_NO_CHECK))
-        {
-          if (!ostree_repo_open (repo, cancellable, error))
-            return FALSE;
-        }
+      repo = parse_repo_option (context, opt_repo, (flags & OSTREE_BUILTIN_FLAG_NO_CHECK) > 0,
+                                cancellable, error);
+      if (!repo)
+        return FALSE;
     }
 
   if (out_repo)
index 3bb752438b9e76bdefed60274e1da2675b967b7e..c7db4a07d2f0b1b1c52aab7fe12f4b6fa5328d57 100644 (file)
@@ -46,6 +46,14 @@ int ostree_run (int argc, char **argv, OstreeCommand *commands, GError **error);
 
 int ostree_usage (OstreeCommand *commands, gboolean is_error);
 
+gboolean ostree_parse_sysroot_or_repo_option (GOptionContext *context,
+                                              const char *sysroot_path,
+                                              const char *repo_path,
+                                              OstreeSysroot **out_sysroot,
+                                              OstreeRepo **out_repo,
+                                              GCancellable *cancellable,
+                                              GError **error);
+
 gboolean ostree_option_context_parse (GOptionContext *context,
                                       const GOptionEntry *main_entries,
                                       int *argc, char ***argv,
index db115efd4c29ec8ac30156c8c8900681f1fa24f8..c1f489690e6fcc5ead0267d048c272d1ba29ae9f 100644 (file)
@@ -34,6 +34,8 @@ static char *opt_contenturl;
 #ifdef OSTREE_ENABLE_EXPERIMENTAL_API
 static char *opt_collection_id;
 #endif  /* OSTREE_ENABLE_EXPERIMENTAL_API */
+static char *opt_sysroot;
+static char *opt_repo;
 
 static GOptionEntry option_entries[] = {
   { "set", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" },
@@ -45,6 +47,8 @@ static GOptionEntry option_entries[] = {
   { "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" },
 #endif  /* OSTREE_ENABLE_EXPERIMENTAL_API */
+  { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
+  { "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" },
   { NULL }
 };
 
@@ -52,6 +56,7 @@ gboolean
 ot_remote_builtin_add (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   g_autoptr(GOptionContext) context = NULL;
+  g_autoptr(OstreeSysroot) sysroot = NULL;
   g_autoptr(OstreeRepo) repo = NULL;
   const char *remote_name;
   const char *remote_url;
@@ -63,7 +68,12 @@ ot_remote_builtin_add (int argc, char **argv, GCancellable *cancellable, GError
   context = g_option_context_new ("NAME [metalink=|mirrorlist=]URL [BRANCH...] - Add a remote repository");
 
   if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
-                                    OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
+                                    OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error))
+    goto out;
+
+  if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo,
+                                            &sysroot, &repo,
+                                            cancellable, error))
     goto out;
 
   if (argc < 3)
index cac1b7ead9cf371bff1ee1c912e1f34d06deaae9..65a7ada3c6a7d7176bcfb78d73833598375ca1ab 100644 (file)
 #include "ot-main.h"
 #include "ot-remote-builtins.h"
 
-gboolean opt_if_exists = FALSE;
+static gboolean opt_if_exists = FALSE;
+static char *opt_sysroot;
+static char *opt_repo;
 
 static GOptionEntry option_entries[] = {
   { "if-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_exists, "Do nothing if the provided remote does not exist", NULL },
+  { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
+  { "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" },
   { NULL }
 };
 
 gboolean
 ot_remote_builtin_delete (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
-  g_autoptr(GOptionContext) context = NULL;
-  g_autoptr(OstreeRepo) repo = NULL;
-  const char *remote_name;
-  gboolean ret = FALSE;
 
-  context = g_option_context_new ("NAME - Delete a remote repository");
+  g_autoptr(GOptionContext) context = g_option_context_new ("NAME - Delete a remote repository");
 
   if (!ostree_option_context_parse (context, option_entries, &argc, &argv,
-                                    OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
-    goto out;
+                                    OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error))
+    return FALSE;
+
+  g_autoptr(OstreeSysroot) sysroot = NULL;
+  g_autoptr(OstreeRepo) repo = NULL;
+  if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo,
+                                            &sysroot, &repo,
+                                            cancellable, error))
+    return FALSE;
 
   if (argc < 2)
     {
       ot_util_usage_error (context, "NAME must be specified", error);
-      goto out;
+      return FALSE;
     }
 
-  remote_name = argv[1];
+  const char *remote_name = argv[1];
 
   if (!ostree_repo_remote_change (repo, NULL,
-                                  opt_if_exists ? OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS : 
+                                  opt_if_exists ? OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS :
                                   OSTREE_REPO_REMOTE_CHANGE_DELETE,
                                   remote_name, NULL, NULL,
                                   cancellable, error))
-    goto out;
+    return FALSE;
 
-  ret = TRUE;
- out:
-  return ret;
+  return TRUE;
 }
index 671fd905aebcc71bfd2de3e332ea94dbfa41cfe4..6001ceea41c15ae5d6b367c8c5d1c1ddd510dded 100644 (file)
@@ -234,3 +234,18 @@ curr_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buil
 assert_streq ${curr_rev} ${head_rev}
 
 echo "ok upgrade with and without override-commit"
+
+deployment=$(${CMD_PREFIX} ostree admin --sysroot=sysroot --print-current-dir)
+${CMD_PREFIX} ostree --sysroot=sysroot remote add --set=gpg-verify=false remote-test-physical file://$(pwd)/testos-repo
+assert_not_has_file ${deployment}/etc/ostree/remotes.d/remote-test-physical.conf testos-repo
+assert_file_has_content sysroot/ostree/repo/config remote-test-physical
+echo "ok remote add physical sysroot"
+
+# Now a hack...symlink ${deployment}/sysroot to the sysroot in lieu of a bind
+# mount which we can't do in unit tests.
+ln -sr sysroot ${deployment}/sysroot
+ln -s sysroot/ostree ${deployment}/ostree
+${CMD_PREFIX} ostree --sysroot=${deployment} remote add --set=gpg-verify=false remote-test-nonphysical file://$(pwd)/testos-repo
+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"
diff --git a/tests/installed/itest-remotes.sh b/tests/installed/itest-remotes.sh
new file mode 100755 (executable)
index 0000000..9b48b68
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# Test that we didn't regress /etc/ostree/remotes.d handling
+
+set -xeuo pipefail
+
+dn=$(dirname $0)
+. ${dn}/libinsttest.sh
+
+test_tmpdir=$(prepare_tmpdir)
+trap _tmpdir_cleanup EXIT
+
+ostree remote list > remotes.txt
+if ! test -s remotes.txt; then
+    assert_not_reached "no ostree remotes"
+fi
index 2b90c2866529e596524aa8352e9dd4955655646c..d7c1c6db595af7bb7dd4809445e8d337abc5ea5e 100755 (executable)
@@ -19,7 +19,7 @@
 
 set -euo pipefail
 
-echo "1..16"
+echo "1..18"
 
 . $(dirname $0)/libtest.sh
 
index 70b3b4d3e67f20738185a3877cb32043241f6b76..797836f082027976e9a1b40de5cb8bde94eb619f 100755 (executable)
@@ -19,7 +19,7 @@
 
 set -euo pipefail
 
-echo "1..16"
+echo "1..18"
 
 . $(dirname $0)/libtest.sh
 
index d4c3a0dbf9349889e6638fa627e398a4034f6ca5..d9104f8cb238faa9da5ad2f66ffbb01e4b00272c 100755 (executable)
@@ -20,7 +20,7 @@
 
 set -euo pipefail
 
-echo "1..17"
+echo "1..19"
 
 . $(dirname $0)/libtest.sh