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:
*
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) */
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;
#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"
#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,
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)
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);
}
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;
}
/**
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);
}
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))
{
}
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
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;
GCancellable *cancellable,
GError **error)
{
+ struct stat self_stbuf;
struct stat stbuf;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
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))
{
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;
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);
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;
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);
}
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;
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,
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. */
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)
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,
#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" },
{ "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 }
};
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;
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)
#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;
}
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"
--- /dev/null
+#!/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
set -euo pipefail
-echo "1..16"
+echo "1..18"
. $(dirname $0)/libtest.sh
set -euo pipefail
-echo "1..16"
+echo "1..18"
. $(dirname $0)/libtest.sh
set -euo pipefail
-echo "1..17"
+echo "1..19"
. $(dirname $0)/libtest.sh