static gboolean
deployment_get_gpg_verify (OstreeDeployment *deployment,
                           OstreeRepo *repo)
{
  /* XXX Something like this could be added to the OstreeDeployment
   *     API in libostree if the OstreeRepo parameter is acceptable. */
  GKeyFile *origin = ostree_deployment_get_origin (deployment);

  if (origin == NULL)
    return FALSE;

  g_autofree char *refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);

  if (refspec == NULL)
    return FALSE;

  g_autofree char *remote = NULL;
  if (!ostree_parse_refspec (refspec, &remote, NULL, NULL))
    return FALSE;

  gboolean gpg_verify = FALSE;
  if (remote)
    (void) ostree_repo_remote_get_gpg_verify (repo, remote, &gpg_verify, NULL);

  return gpg_verify;
}
gboolean
get_booted_refspec (gchar **booted_refspec,
                    gchar **booted_remote,
                    gchar **booted_ref,
                    GError **error)
{
  g_autoptr(OstreeDeployment) booted_deployment = NULL;
  g_autofree gchar *refspec = NULL;
  g_autofree gchar *remote = NULL;
  g_autofree gchar *ref = NULL;

  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  booted_deployment = eos_updater_get_booted_deployment (error);

  if (!get_origin_refspec (booted_deployment, &refspec, error))
    return FALSE;

  if (!ostree_parse_refspec (refspec, &remote, &ref, error))
    return FALSE;

  g_message ("Using product branch %s", ref);

  if (booted_refspec != NULL)
    *booted_refspec = g_steal_pointer (&refspec);
  if (booted_remote != NULL)
    *booted_remote = g_steal_pointer (&remote);
  if (booted_ref != NULL)
    *booted_ref = g_steal_pointer (&ref);

  return TRUE;
}
Example #3
0
gboolean
_ostree_repo_update_refs (OstreeRepo        *self,
                          GHashTable        *refs,
                          GCancellable      *cancellable,
                          GError           **error)
{
    gboolean ret = FALSE;
    GHashTableIter hash_iter;
    gpointer key, value;

    g_hash_table_iter_init (&hash_iter, refs);
    while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
        const char *refspec = key;
        const char *rev = value;
        g_autofree char *remote = NULL;
        g_autofree char *ref = NULL;

        if (!ostree_parse_refspec (refspec, &remote, &ref, error))
            goto out;

        if (!_ostree_repo_write_ref (self, remote, ref, rev,
                                     cancellable, error))
            goto out;
    }

    ret = TRUE;
out:
    return ret;
}
Example #4
0
gboolean
ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  GOptionContext *context;
  gs_unref_object OstreeRepo *repo = NULL;
  const char *refspec_prefix = NULL;
  gs_unref_hashtable GHashTable *refs = NULL;
  GHashTableIter hashiter;
  gpointer hashkey, hashvalue;

  context = g_option_context_new ("[PREFIX] - List refs");

  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
    goto out;

  if (argc >= 2)
    refspec_prefix = argv[1];

  if (!ostree_repo_list_refs (repo, refspec_prefix, &refs,
                              cancellable, error))
    goto out;

  if (!opt_delete)
    {
      g_hash_table_iter_init (&hashiter, refs);
      while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
        {
          const char *ref = hashkey;
          g_print ("%s\n", ref);
        }
    }
  else
    {
      g_hash_table_iter_init (&hashiter, refs);
      while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
        {
          const char *refspec = hashkey;
          gs_free char *remote = NULL;
          gs_free char *ref = NULL;

          if (!ostree_parse_refspec (refspec, &remote, &ref, error))
            goto out;
          
          if (!ostree_repo_set_ref_immediate (repo, remote, ref, NULL,
                                              cancellable, error))
            goto out;
        }
    }

  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  if (repo)
    ostree_repo_abort_transaction (repo, cancellable, NULL);
  return ret;
}
static GVariant *
rpmostreed_deployment_gpg_results (OstreeRepo *repo,
                                   const gchar *origin_refspec,
                                   const gchar *csum)
{
  GError *error = NULL;
  GVariant *ret = NULL;

  g_autofree gchar *remote = NULL;
  glnx_unref_object OstreeGpgVerifyResult *result = NULL;

  guint n_sigs, i;
  gboolean gpg_verify;
  GVariantBuilder builder;

  g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));

  if (!ostree_parse_refspec (origin_refspec, &remote, NULL, &error))
    goto out;

  if (!ostree_repo_remote_get_gpg_verify (repo, remote, &gpg_verify, &error))
    goto out;

  if (!gpg_verify)
    goto out;


  result = ostree_repo_verify_commit_ext (repo, csum, NULL, NULL,
                                          NULL, &error);
  if (!result)
      goto out;

  n_sigs = ostree_gpg_verify_result_count_all (result);
  if (n_sigs < 1)
    goto out;

  for (i = 0; i < n_sigs; i++)
    {
      g_variant_builder_add (&builder, "v",
                             ostree_gpg_verify_result_get_all (result, i));
    }

  ret = g_variant_builder_end (&builder);

out:

  /* NOT_FOUND just means the commit is not signed. */
  if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
    g_warning ("error loading gpg verify result %s", error->message);

  g_clear_error (&error);
  return ret;
}
Example #6
0
/**
 * ostree_repo_list_refs:
 * @self: Repo
 * @refspec_prefix: (allow-none): Only list refs which match this prefix
 * @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum
 * @cancellable: Cancellable
 * @error: Error
 *
 * If @refspec_prefix is %NULL, list all local and remote refspecs,
 * with their current values in @out_all_refs.  Otherwise, only list
 * refspecs which have @refspec_prefix as a prefix.
 */
gboolean
ostree_repo_list_refs (OstreeRepo       *self,
                       const char       *refspec_prefix,
                       GHashTable      **out_all_refs,
                       GCancellable     *cancellable,
                       GError          **error)
{
    gboolean ret = FALSE;
    g_autoptr(GHashTable) ret_all_refs = NULL;
    g_autofree char *remote = NULL;
    g_autofree char *ref_prefix = NULL;

    ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

    if (refspec_prefix)
    {
        g_autoptr(GFile) dir = NULL;
        g_autoptr(GFile) child = NULL;
        g_autoptr(GFileInfo) info = NULL;

        if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
            goto out;

        if (remote)
            dir = g_file_get_child (self->remote_heads_dir, remote);
        else
            dir = g_object_ref (self->local_heads_dir);

        child = g_file_resolve_relative_path (dir, ref_prefix);
        if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0,
                                              &info, cancellable, error))
            goto out;

        if (info)
        {
            if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
            {
                if (!enumerate_refs_recurse (self, remote, child, child,
                                             ret_all_refs,
                                             cancellable, error))
                    goto out;
            }
            else
            {
                if (!add_ref_to_set (remote, dir, child, ret_all_refs,
                                     cancellable, error))
                    goto out;
            }
        }
    }
    else
    {
        g_autoptr(GFileEnumerator) remote_enumerator = NULL;

        if (!enumerate_refs_recurse (self, NULL, self->local_heads_dir, self->local_heads_dir,
                                     ret_all_refs,
                                     cancellable, error))
            goto out;

        remote_enumerator = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
                            0,
                            cancellable, error);

        while (TRUE)
        {
            GFileInfo *info;
            GFile *child;
            const char *name;

            if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child,
                                             cancellable, error))
                goto out;
            if (!info)
                break;

            name = g_file_info_get_name (info);
            if (!enumerate_refs_recurse (self, name, child, child,
                                         ret_all_refs,
                                         cancellable, error))
                goto out;
        }
    }

    ret = TRUE;
    ot_transfer_out_value (out_all_refs, &ret_all_refs);
out:
    return ret;
}
Example #7
0
/**
 * ostree_repo_resolve_rev:
 * @self: Repo
 * @refspec: A refspec
 * @allow_noent: Do not throw an error if refspec does not exist
 * @out_rev: (out) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist
 * @error: Error
 *
 * Look up the given refspec, returning the checksum it references in
 * the parameter @out_rev.
 */
gboolean
ostree_repo_resolve_rev (OstreeRepo     *self,
                         const char     *refspec,
                         gboolean        allow_noent,
                         char          **out_rev,
                         GError        **error)
{
    gboolean ret = FALSE;
    g_autofree char *ret_rev = NULL;

    g_return_val_if_fail (refspec != NULL, FALSE);

    if (ostree_validate_checksum_string (refspec, NULL))
    {
        ret_rev = g_strdup (refspec);
    }

    else if (!ostree_repo_resolve_partial_checksum (self, refspec, &ret_rev, error))
        goto out;

    if (!ret_rev)
    {
        if (error != NULL && *error != NULL)
            goto out;

        if (g_str_has_suffix (refspec, "^"))
        {
            g_autofree char *parent_refspec = NULL;
            g_autofree char *parent_rev = NULL;
            g_autoptr(GVariant) commit = NULL;

            parent_refspec = g_strdup (refspec);
            parent_refspec[strlen(parent_refspec) - 1] = '\0';

            if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error))
                goto out;

            if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev,
                                           &commit, error))
                goto out;

            if (!(ret_rev = ostree_commit_get_parent (commit)))
            {
                g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                             "Commit %s has no parent", parent_rev);
                goto out;
            }
        }
        else
        {
            g_autofree char *remote = NULL;
            g_autofree char *ref = NULL;

            if (!ostree_parse_refspec (refspec, &remote, &ref, error))
                goto out;

            if (!resolve_refspec (self, remote, ref, allow_noent,
                                  &ret_rev, error))
                goto out;
        }
    }

    ret = TRUE;
    ot_transfer_out_value (out_rev, &ret_rev);
out:
    return ret;
}
gboolean
rpmostree_builtin_rebase (int             argc,
                          char          **argv,
                          GCancellable   *cancellable,
                          GError        **error)
{
  gboolean ret = FALSE;
  GOptionContext *context = g_option_context_new ("REFSPEC - Switch to a different tree");
  const char *new_provided_refspec;
  gs_unref_object OstreeSysroot *sysroot = NULL;
  gs_unref_object OstreeRepo *repo = NULL;
  gs_free char *origin_refspec = NULL;
  gs_free char *origin_remote = NULL;
  gs_free char *origin_ref = NULL;
  gs_free char *new_remote = NULL;
  gs_free char *new_ref = NULL;
  gs_free char *new_refspec = NULL;
  gs_unref_object GFile *sysroot_path = NULL;
  gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
  gs_unref_object OstreeAsyncProgress *progress = NULL;
  gboolean changed;
  GSConsole *console = NULL;
  gs_unref_keyfile GKeyFile *old_origin = NULL;
  gs_unref_keyfile GKeyFile *new_origin = NULL;
  
  if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, error))
    goto out;

  if (argc < 2)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "REFSPEC must be specified");
      goto out;
    }

  new_provided_refspec = argv[1];

  sysroot_path = g_file_new_for_path (opt_sysroot);
  sysroot = ostree_sysroot_new (sysroot_path);
  if (!ostree_sysroot_load (sysroot, cancellable, error))
    goto out;

  upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname,
                                                            OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED,
                                                            cancellable, error);
  if (!upgrader)
    goto out;

  old_origin = ostree_sysroot_upgrader_get_origin (upgrader);
  origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL);
  
  if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
    goto out;

  /* Allow just switching remotes */
  if (g_str_has_suffix (new_provided_refspec, ":"))
    {
      new_remote = g_strdup (new_provided_refspec);
      new_remote[strlen(new_remote)-1] = '\0';
      new_ref = g_strdup (origin_ref);
    }
  else
    {
      if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error))
        goto out;
    }
  
  if (!new_remote)
    new_refspec = g_strconcat (origin_remote, ":", new_ref, NULL);
  else
    new_refspec = g_strconcat (new_remote, ":", new_ref, NULL);
  
  if (strcmp (origin_refspec, new_refspec) == 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Old and new refs are equal: %s", new_refspec);
      goto out;
    }

  new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec);
  if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error))
    goto out;

  console = gs_console_get ();
  if (console)
    {
      gs_console_begin_status_line (console, "", NULL, NULL);
      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.
   */
  if (!ostree_sysroot_upgrader_pull (upgrader, 0,
                                     OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
                                     progress, &changed,
                                     cancellable, error))
    goto out;

  if (console)
    {
      if (!gs_console_end_status_line (console, cancellable, error))
        {
          console = NULL;
          goto out;
        }
      console = NULL;
    }

  if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
    goto out;

  if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
    goto out;

  if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
    goto out;

  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;
  
  if (!rpmostree_print_treepkg_diff (sysroot, cancellable, error))
    goto out;
  
  ret = TRUE;
 out:
  if (console)
    (void) gs_console_end_status_line (console, NULL, NULL);
  return ret;
}
gboolean
ot_admin_builtin_set_origin (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  GOptionContext *context;
  const char *remotename = NULL;
  const char *url = NULL;
  const char *branch = NULL;
  gs_unref_object OstreeRepo *repo = NULL;
  gs_unref_object OstreeSysroot *sysroot = NULL;
  OstreeDeployment *target_deployment = NULL;

  context = g_option_context_new ("REMOTENAME URL [BRANCH]");

  if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
                                          OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
                                          &sysroot, cancellable, error))
    goto out;

  if (argc < 3)
    {
      ot_util_usage_error (context, "REMOTENAME and URL must be specified", error);
      goto out;
    }

  remotename = argv[1];
  url = argv[2];
  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;

  if (opt_index == -1)
    {
      target_deployment = ostree_sysroot_get_booted_deployment (sysroot);
      if (target_deployment == NULL)
        {
          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                               "Not currently booted into an OSTree system");
          goto out;
        }
    }
  else
    {
      target_deployment = ot_admin_get_indexed_deployment (sysroot, opt_index, error);
      if (!target_deployment)
        goto out;
    }

  { char **iter;
    gs_unref_variant_builder GVariantBuilder *optbuilder =
      g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));

    for (iter = opt_set; iter && *iter; iter++)
      {
        const char *keyvalue = *iter;
        gs_free char *subkey = NULL;
        gs_free char *subvalue = NULL;

        if (!ot_parse_keyvalue (keyvalue, &subkey, &subvalue, error))
          goto out;

        g_variant_builder_add (optbuilder, "{s@v}",
                               subkey, g_variant_new_variant (g_variant_new_string (subvalue)));
      }
    
    if (!ostree_repo_remote_change (repo, NULL,
                                    OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS, 
                                    remotename, url,
                                    g_variant_builder_end (optbuilder),
                                    cancellable, error))
      goto out;
  }
  
  { GKeyFile *old_origin = ostree_deployment_get_origin (target_deployment);
    gs_free char *origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL);
    gs_free char *new_refspec = NULL;
    gs_free char *origin_remote = NULL;
    gs_free char *origin_ref = NULL;
  
    if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
      goto out;

    { gs_free char *new_refspec = g_strconcat (remotename, ":", branch ? branch : origin_ref, NULL);
      gs_unref_keyfile GKeyFile *new_origin = NULL;
      gs_unref_object GFile *origin_path = NULL;
      
      new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec);

      if (!ostree_sysroot_write_origin_file (sysroot, target_deployment, new_origin,
                                             cancellable, error))
        goto out;
    }
  }

  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  return ret;
}
Example #10
0
static gboolean
_ostree_repo_list_refs_internal (OstreeRepo       *self,
                                 gboolean         cut_prefix,
                                 const char       *refspec_prefix,
                                 GHashTable      **out_all_refs,
                                 GCancellable     *cancellable,
                                 GError          **error)
{
  g_autoptr(GHashTable) ret_all_refs = NULL;
  g_autofree char *remote = NULL;
  g_autofree char *ref_prefix = NULL;

  ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

  if (refspec_prefix)
    {
      struct stat stbuf;
      const char *prefix_path;
      const char *path;

      if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
        return FALSE;

      if (remote)
        {
          prefix_path = glnx_strjoina ("refs/remotes/", remote, "/");
          path = glnx_strjoina (prefix_path, ref_prefix);
        }
      else
        {
          prefix_path = "refs/heads/";
          path = glnx_strjoina (prefix_path, ref_prefix);
        }

      if (fstatat (self->repo_dir_fd, path, &stbuf, 0) < 0)
        {
          if (errno != ENOENT)
            return glnx_throw_errno (error);
        }
      else
        {
          if (S_ISDIR (stbuf.st_mode))
            {
              glnx_fd_close int base_fd = -1;
              g_autoptr(GString) base_path = g_string_new ("");
              if (!cut_prefix)
                g_string_printf (base_path, "%s/", ref_prefix);

              if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error))
                return FALSE;

              if (!enumerate_refs_recurse (self, remote, base_fd, base_path,
                                           base_fd, cut_prefix ? "." : ref_prefix,
                                           ret_all_refs, cancellable, error))
                return FALSE;
            }
          else
            {
              glnx_fd_close int prefix_dfd = -1;

              if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error))
                return FALSE;

              if (!add_ref_to_set (remote, prefix_dfd, ref_prefix, ret_all_refs,
                                   cancellable, error))
                return FALSE;
            }
        }
    }
  else
    {
      g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
      g_autoptr(GString) base_path = g_string_new ("");
      glnx_fd_close int refs_heads_dfd = -1;

      if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
        return FALSE;

      if (!enumerate_refs_recurse (self, NULL, refs_heads_dfd, base_path,
                                   refs_heads_dfd, ".",
                                   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)
        {
          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, remote_dfd, base_path,
                                       remote_dfd, ".",
                                       ret_all_refs,
                                       cancellable, error))
            return FALSE;
        }
    }

  ot_transfer_out_value (out_all_refs, &ret_all_refs);
  return TRUE;
}
Example #11
0
gboolean
ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  GOptionContext *context;
  gs_unref_object OstreeRepo *repo = NULL;
  gboolean ret = FALSE;
  gs_free char *remote = NULL;
  OstreeRepoPullFlags pullflags = 0;
  GSConsole *console = NULL;
  gs_unref_ptrarray GPtrArray *refs_to_fetch = NULL;
  gs_unref_object OstreeAsyncProgress *progress = NULL;

  context = g_option_context_new ("REMOTE [BRANCH...] - Download data from remote repository");

  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
    goto out;

  if (argc < 2)
    {
      ot_util_usage_error (context, "REMOTE must be specified", error);
      goto out;
    }

  if (opt_disable_fsync)
    ostree_repo_set_disable_fsync (repo, TRUE);

  if (opt_mirror)
    pullflags |= OSTREE_REPO_PULL_FLAGS_MIRROR;

  if (strchr (argv[1], ':') == NULL)
    {
      remote = g_strdup (argv[1]);
      if (argc > 2)
        {
          int i;
          refs_to_fetch = g_ptr_array_new ();
          for (i = 2; i < argc; i++)
            g_ptr_array_add (refs_to_fetch, argv[i]);
          g_ptr_array_add (refs_to_fetch, NULL);
        }
    }
  else
    {
      char *ref_to_fetch;
      refs_to_fetch = g_ptr_array_new ();
      if (!ostree_parse_refspec (argv[1], &remote, &ref_to_fetch, error))
        goto out;
      /* Transfer ownership */
      g_ptr_array_add (refs_to_fetch, ref_to_fetch);
      g_ptr_array_add (refs_to_fetch, NULL);
    }

  console = gs_console_get ();
  if (console)
    {
      gs_console_begin_status_line (console, "", NULL, NULL);
      progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
    }

  {
    GVariantBuilder builder;
    g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));

    if (opt_subpath)
      g_variant_builder_add (&builder, "{s@v}", "subdir",
                             g_variant_new_variant (g_variant_new_string (opt_subpath)));
    g_variant_builder_add (&builder, "{s@v}", "flags",
                           g_variant_new_variant (g_variant_new_int32 (pullflags)));
    if (refs_to_fetch)
      g_variant_builder_add (&builder, "{s@v}", "refs",
                             g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch->pdata, -1)));
    g_variant_builder_add (&builder, "{s@v}", "depth",
                           g_variant_new_variant (g_variant_new_int32 (opt_depth)));
    
    if (!ostree_repo_pull_with_options (repo, remote, g_variant_builder_end (&builder),
                                        progress, cancellable, error))
      goto out;
  }

  if (progress)
    ostree_async_progress_finish (progress);

  ret = TRUE;
 out:
  if (console)
    gs_console_end_status_line (console, NULL, NULL);
 
  if (context)
    g_option_context_free (context);
  return ret;
}
Example #12
0
/**
 * rpmostreed_refspec_parse_partial:
 * @new_provided_refspec: The provided refspec
 * @base_refspec: The refspec string to base on.
 * @out_refspec: Pointer to the new refspec
 * @error: Pointer to an error pointer.
 *
 * Takes a refspec string and adds any missing bits based on the
 * base_refspec argument. Errors if a full valid refspec can't
 * be derived.
 *
 * Returns: True on success.
 */
gboolean
rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec,
                                  const gchar *base_refspec,
                                  gchar **out_refspec,
                                  GError **error)
{

  g_autofree gchar *ref = NULL;
  g_autofree gchar *remote = NULL;
  gboolean infer_remote = TRUE;;

  /* Allow just switching remotes */
  if (g_str_has_suffix (new_provided_refspec, ":"))
    {
      remote = g_strndup (new_provided_refspec, strlen(new_provided_refspec)-1);
    }
  /* Allow switching to a local branch */
  else if (g_str_has_prefix (new_provided_refspec, ":"))
    {
      infer_remote = FALSE;
      ref = g_strdup (new_provided_refspec + 1);
    }
  else
    {
      g_autoptr(GError) parse_error = NULL;
      if (!ostree_parse_refspec (new_provided_refspec, &remote,
                                 &ref, &parse_error))
        {
          g_set_error_literal (error, RPM_OSTREED_ERROR,
                               RPM_OSTREED_ERROR_INVALID_REFSPEC,
                               parse_error->message);
          return FALSE;
        }
    }

  g_autofree gchar *origin_ref = NULL;
  g_autofree gchar *origin_remote = NULL;
  if (base_refspec != NULL)
    {
      g_autoptr(GError) parse_error = NULL;
      if (!ostree_parse_refspec (base_refspec, &origin_remote,
                                 &origin_ref, &parse_error))
        {
          g_set_error_literal (error, RPM_OSTREED_ERROR,
                               RPM_OSTREED_ERROR_INVALID_REFSPEC,
                               parse_error->message);
          return FALSE;
        }
    }

  if (ref == NULL)
    {
      if (origin_ref)
        {
          ref = g_strdup (origin_ref);
        }
      else
        {
          g_set_error (error, RPM_OSTREED_ERROR,
                       RPM_OSTREED_ERROR_INVALID_REFSPEC,
                      "Could not determine default ref to pull.");
          return FALSE;
        }

    }
  else if (infer_remote && remote == NULL)
    {
      if (origin_remote)
        {
          remote = g_strdup (origin_remote);
        }
    }

  if (g_strcmp0 (origin_remote, remote) == 0 &&
      g_strcmp0 (origin_ref, ref) == 0)
    {
      g_set_error (error, RPM_OSTREED_ERROR,
                   RPM_OSTREED_ERROR_INVALID_REFSPEC,
                   "Old and new refs are equal: %s:%s",
                   remote, ref);
      return FALSE;
    }

  if (remote == NULL)
      *out_refspec = g_steal_pointer (&ref);
  else
      *out_refspec = g_strconcat (remote, ":", ref, NULL);

  return TRUE;
}
Example #13
0
gboolean
ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  GOptionContext *context;
  const char *new_provided_refspec = NULL;
  gs_unref_object OstreeRepo *repo = NULL;
  gs_free char *origin_refspec = NULL;
  gs_free char *origin_remote = NULL;
  gs_free char *origin_ref = NULL;
  gs_free char *new_remote = NULL;
  gs_free char *new_ref = NULL;
  gs_free char *new_refspec = NULL;
  gs_free char *new_revision = NULL;
  gs_unref_object GFile *deployment_path = NULL;
  gs_unref_object GFile *deployment_origin_path = NULL;
  gs_unref_object OstreeDeployment *merge_deployment = NULL;
  gs_unref_object OstreeDeployment *new_deployment = NULL;
  gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
  gs_unref_object OstreeAsyncProgress *progress = NULL;
  gboolean changed;
  GSConsole *console = NULL;
  gboolean in_status_line = FALSE;
  GKeyFile *old_origin;
  GKeyFile *new_origin = NULL;

  context = g_option_context_new ("REF - Construct new tree from current origin and deploy it, if it changed");
  g_option_context_add_main_entries (context, options, NULL);

  if (!g_option_context_parse (context, &argc, &argv, error))
    goto out;

  if (argc < 2)
    {
      ot_util_usage_error (context, "REF must be specified", error);
      goto out;
    }

  new_provided_refspec = argv[1];

  if (!ostree_sysroot_load (sysroot, cancellable, error))
    goto out;

  upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname,
                                                 cancellable, error);
  if (!upgrader)
    goto out;

  old_origin = ostree_sysroot_upgrader_get_origin (upgrader);
  origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL);
  
  if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
    goto out;

  /* Allow just switching remotes */
  if (g_str_has_suffix (new_provided_refspec, ":"))
    {
      new_remote = g_strdup (new_provided_refspec);
      new_remote[strlen(new_remote)-1] = '\0';
      new_ref = g_strdup (origin_ref);
    }
  else
    {
      if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error))
        goto out;
    }
  
  if (!new_remote)
    new_refspec = g_strconcat (origin_remote, ":", new_ref, NULL);
  else
    new_refspec = g_strconcat (new_remote, ":", new_ref, NULL);
  
  if (strcmp (origin_refspec, new_refspec) == 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Old and new refs are equal: %s", new_refspec);
      goto out;
    }

  new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec);
  if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error))
    goto out;

  console = gs_console_get ();
  if (console)
    {
      gs_console_begin_status_line (console, "", NULL, NULL);
      in_status_line = TRUE;
      progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
    }

  /* Always allow older...there's not going to be a chronological
   * relationship necessarily.
   */
  if (!ostree_sysroot_upgrader_pull (upgrader, 0,
                                     OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
                                     progress, &changed,
                                     cancellable, error))
    goto out;

  if (in_status_line)
    {
      gs_console_end_status_line (console, NULL, NULL);
      in_status_line = FALSE;
    }

  if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
    goto out;

  if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
    goto out;

  if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
    goto out;

  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;
  
  {
    gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
      
    if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
      {
        gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
                                       cancellable, error,
                                       "systemctl", "reboot", NULL);
      }
  }

  ret = TRUE;
 out:
  if (in_status_line)
    gs_console_end_status_line (console, NULL, NULL);
  if (new_origin)
    g_key_file_unref (new_origin);
  if (context)
    g_option_context_free (context);
  return ret;
}
gboolean
xdg_app_builtin_repo_contents (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  GOptionContext *context;
  g_autoptr(XdgAppDir) dir = NULL;
  OstreeRepo *repo = NULL;
  g_autoptr(GHashTable) refs = NULL;
  g_autofree char *title = NULL;
  GHashTableIter iter;
  gpointer key;
  gpointer value;
  g_autoptr(GPtrArray) names = NULL;
  int i;
  const char *repository;
  g_autofree char *url = NULL;
  g_autoptr(GBytes) bytes = NULL;

  context = g_option_context_new (" REPOSITORY - Show available runtimes and applications");

  if (!xdg_app_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
    goto out;

  if (argc < 2)
    {
      usage_error (context, "REPOSITORY must be specified", error);
      goto out;
    }

  repository = argv[1];

  repo = xdg_app_dir_get_repo (dir);
  if (!ostree_repo_remote_get_url (repo, repository, &url, error))
    goto out;

  if (!ostree_repo_load_summary (url, &refs, &title, cancellable, error))
    goto out;

  names = g_ptr_array_new_with_free_func (g_free);

  g_hash_table_iter_init (&iter, refs);
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      const char *refspec = key;
      const char *checksum = value;
      g_autofree char *remote = NULL;
      g_autofree char *ref = NULL;
      char *name = NULL;
      char *p;

      if (!ostree_parse_refspec (refspec, &remote, &ref, error))
        goto out;

      if (remote != NULL && !g_str_equal (remote, repository))
        continue;

      if (opt_only_updates)
        {
          g_autofree char *deployed = NULL;

          deployed = xdg_app_dir_read_active (dir, ref, cancellable);
          if (deployed == NULL)
            continue;

          if (g_strcmp0 (deployed, checksum) == 0)
            continue;
        }

      if (g_str_has_prefix (ref, "runtime/") && !opt_only_apps)
        {
          if (!opt_show_details)
            {
              name = g_strdup (ref + strlen ("runtime/"));
              p = strchr (name, '/');
              if (p)
                *p = 0;
            }
          else
            {
              name = g_strdup (ref);
            }
        }

      if (g_str_has_prefix (ref, "app/") && !opt_only_runtimes)
        {
          if (!opt_show_details)
            {
              name = g_strdup (ref + strlen ("app/"));
              p = strchr (name, '/');
              if (p)
                *p = 0;
            }
          else
            {
              name = g_strdup (ref);
            }
        }

      if (name)
        {
	  gboolean found = FALSE;

          for (i = 0; i < names->len; i++)
            {
              if (strcmp (name, g_ptr_array_index (names, i)) == 0)
		found = TRUE;
              break;
            }

	  if (!found)
            g_ptr_array_add (names, name);
	  else
	    g_free (name);
        }
    }

  g_ptr_array_sort (names, (GCompareFunc)strcmp);

  for (i = 0; i < names->len; i++)
    g_print ("%s\n", (char *)g_ptr_array_index (names, i));

  ret = TRUE;

 out:
  if (context)
    g_option_context_free (context);

  return ret;
}
Example #15
0
/**
 * rpmostreed_refspec_parse_partial:
 * @new_provided_refspec: The provided refspec
 * @base_refspec: The refspec string to base on.
 * @out_refspec: Pointer to the new refspec
 * @error: Pointer to an error pointer.
 *
 * Takes a refspec string and adds any missing bits based on the
 * base_refspec argument. Errors if a full valid refspec can't
 * be derived.
 *
 * Returns: True on success.
 */
gboolean
rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec,
                                  gchar *base_refspec,
                                  gchar **out_refspec,
                                  GError **error)
{

  g_autofree gchar *ref = NULL;
  g_autofree gchar *remote = NULL;
  g_autofree gchar *origin_ref = NULL;
  g_autofree gchar *origin_remote = NULL;
  GError *parse_error = NULL;

  gboolean ret = FALSE;

  /* Allow just switching remotes */
  if (g_str_has_suffix (new_provided_refspec, ":"))
    {
      remote = g_strdup (new_provided_refspec);
      remote[strlen (remote) - 1] = '\0';
    }
  else
    {
      if (!ostree_parse_refspec (new_provided_refspec, &remote,
                                 &ref, &parse_error))
        {
          g_set_error_literal (error, RPM_OSTREED_ERROR,
                       RPM_OSTREED_ERROR_INVALID_REFSPEC,
                       parse_error->message);
          g_clear_error (&parse_error);
          goto out;
        }
    }

  if (base_refspec != NULL)
    {
      if (!ostree_parse_refspec (base_refspec, &origin_remote,
                               &origin_ref, &parse_error))
        goto out;
    }

  if (ref == NULL)
    {
      if (origin_ref)
        {
          ref = g_strdup (origin_ref);
        }

      else
        {
          g_set_error (error, RPM_OSTREED_ERROR,
                       RPM_OSTREED_ERROR_INVALID_REFSPEC,
                      "Could not determine default ref to pull.");
          goto out;
        }

    }
  else if (remote == NULL)
    {
      if (origin_remote)
        {
          remote = g_strdup (origin_remote);
        }
      else
        {
          g_set_error (error, RPM_OSTREED_ERROR,
                       RPM_OSTREED_ERROR_INVALID_REFSPEC,
                       "Could not determine default remote to pull.");
          goto out;
        }
    }

  if (g_strcmp0 (origin_remote, remote) == 0 &&
      g_strcmp0 (origin_ref, ref) == 0)
    {
      g_set_error (error, RPM_OSTREED_ERROR,
                   RPM_OSTREED_ERROR_INVALID_REFSPEC,
                   "Old and new refs are equal: %s:%s",
                   remote, ref);
      goto out;
    }

  *out_refspec = g_strconcat (remote, ":", ref, NULL);
  ret = TRUE;

out:
  return ret;
}
gboolean
rpmostree_builtin_upgrade (int             argc,
                           char          **argv,
                           GCancellable   *cancellable,
                           GError        **error)
{
  gboolean ret = FALSE;
  GOptionContext *context = g_option_context_new ("- Perform a system upgrade");
  gs_unref_object GFile *sysroot_path = NULL;
  gs_unref_object OstreeSysroot *sysroot = NULL;
  gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
  gs_unref_object OstreeAsyncProgress *progress = NULL;
  GSConsole *console = NULL;
  gboolean changed;
  OstreeSysrootUpgraderPullFlags upgraderpullflags = 0;

  gs_free char *origin_description = NULL;
  gs_unref_object OstreeRepo *repo = NULL; 

  g_option_context_add_main_entries (context, option_entries, NULL);

   if (!g_option_context_parse (context, &argc, &argv, error))
    goto out;

  sysroot_path = g_file_new_for_path (opt_sysroot);
  sysroot = ostree_sysroot_new (sysroot_path);
  if (!ostree_sysroot_load (sysroot, cancellable, error))
    goto out;

  upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname,
                                                 cancellable, error);
  if (!upgrader)
    goto out;

  origin_description = ostree_sysroot_upgrader_get_origin_description (upgrader);
  if (origin_description)
    g_print ("Updating from: %s\n", origin_description);

  if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
    goto out;

  console = gs_console_get ();
  if (console)
    {
      gs_console_begin_status_line (console, "", NULL, NULL);
      progress = ostree_async_progress_new_and_connect (_rpmostree_pull_progress, console);
    }

  if (opt_allow_downgrade)  
    upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER;

  if (opt_check_diff)
    {
      if (!ostree_sysroot_upgrader_pull_one_dir (upgrader, "/usr/share/rpm", 0, 0, progress, &changed,
                                     cancellable, error))
        goto out;
    }

  else
    {
      if (!ostree_sysroot_upgrader_pull (upgrader, 0, 0, progress, &changed,
                                       cancellable, error))
        goto out;
    }

  if (console)
    {
      if (!gs_console_end_status_line (console, cancellable, error))
        {
          console = NULL;
          goto out;
        }
      console = NULL;
    }

  if (!changed)
    {
      g_print ("No updates available.\n");
    }
  else
    {
      if (!opt_check_diff)
        {
          if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
                goto out;
        
          if (opt_reboot)
            gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
                                           cancellable, error,
                                           "systemctl", "reboot", NULL);
          else
            {
#ifdef HAVE_PATCHED_HAWKEY_AND_LIBSOLV
              if (!rpmostree_print_treepkg_diff (sysroot, cancellable, error))
                goto out;
#endif

              g_print ("Updates prepared for next boot; run \"systemctl reboot\" to start a reboot\n");
            }
        }


      else
        {
          gs_unref_object GFile *rpmdbdir = NULL;
          _cleanup_rpmrev_ struct RpmRevisionData *rpmrev1 = NULL;
          _cleanup_rpmrev_ struct RpmRevisionData *rpmrev2 = NULL;

          gs_free char *tmpd = g_mkdtemp (g_strdup ("/tmp/rpm-ostree.XXXXXX"));

          gs_free char *ref = NULL; // location of this rev
          gs_free char *remote = NULL;

          if (!ostree_parse_refspec (origin_description, &remote, &ref, error))
             goto out;

          if (rpmReadConfigFiles (NULL, NULL))
            {
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "rpm failed to init: %s", rpmlogMessage());
              goto out;
            }

          rpmdbdir = g_file_new_for_path (tmpd);

          if (!(rpmrev1 = rpmrev_new (repo, rpmdbdir, 
                                      ostree_deployment_get_csum (ostree_sysroot_get_booted_deployment (sysroot)),
                                      NULL, cancellable, error)))
            goto out;

          if (!(rpmrev2 = rpmrev_new (repo, rpmdbdir, ref,
                                      NULL, cancellable, error)))
            goto out;

          rpmhdrs_diff_prnt_diff (rpmrev1->root, rpmrev2->root,
                            rpmhdrs_diff (rpmrev1->rpmdb, rpmrev2->rpmdb),
                            cancellable, error);
        }
    }
  
  ret = TRUE;
 out:
  if (console)
    (void) gs_console_end_status_line (console, NULL, NULL);

  return ret;
}
Example #17
0
/**
 * rpmostreed_repo_pull_ancestry:
 * @repo: Repo
 * @refspec: Repository branch
 * @visitor: (allow-none): Visitor function to call on each commit
 * @visitor_data: (allow-none): User data for @visitor
 * @progress: (allow-none): Progress
 * @cancellable: Cancellable
 * @error: Error
 *
 * Downloads an ancestry of commit objects starting from @refspec.
 *
 * If a @visitor function pointer is given, commit objects are downloaded
 * in batches and the @visitor function is called for each commit object.
 * The @visitor function can stop the recursion, such as when looking for
 * a particular commit.
 *
 * Returns: %TRUE on success, %FALSE on failure
 */
gboolean
rpmostreed_repo_pull_ancestry (OstreeRepo               *repo,
                               const char               *refspec,
                               RpmostreedCommitVisitor   visitor,
                               gpointer                  visitor_data,
                               OstreeAsyncProgress      *progress,
                               GCancellable             *cancellable,
                               GError                  **error)
{
  OstreeRepoPullFlags flags;
  GVariantDict options;
  GVariant *refs_value;
  const char *refs_array[] = { NULL, NULL };
  g_autofree char *remote = NULL;
  g_autofree char *ref = NULL;
  g_autofree char *checksum = NULL;
  int depth, ii;
  gboolean ret = FALSE;

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (refspec != NULL, FALSE);

  if (!ostree_parse_refspec (refspec, &remote, &ref, error))
    goto out;

  /* If no visitor function was provided then we won't be short-circuiting
   * the recursion, so pull everything in one shot. Otherwise pull commits
   * in increasingly large batches. */
  depth = (visitor != NULL) ? 10 : -1;

  flags = OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY;

  /* It's important to use the ref name instead of a checksum on the first
   * pass because we want to search from the latest available commit on the
   * remote server, which is not necessarily what the ref name is currently
   * pointing at in our local repo. */
  refs_array[0] = ref;

  while (TRUE)
    {
      /* Floating reference, transferred to dictionary. */
      refs_value = g_variant_new_strv ((const char * const *) refs_array, -1);

      g_variant_dict_init (&options, NULL);
      g_variant_dict_insert (&options, "depth", "i", depth);
      g_variant_dict_insert (&options, "flags", "i", flags);
      g_variant_dict_insert_value (&options, "refs", refs_value);

      if (!ostree_repo_pull_with_options (repo, remote,
                                          g_variant_dict_end (&options),
                                          progress, cancellable, error))
        goto out;

      /* First pass only.  Now we can resolve the ref to a checksum. */
      if (checksum == NULL)
        {
          if (!ostree_repo_resolve_rev (repo, ref, FALSE, &checksum, error))
            goto out;
        }

      /* If depth is negative (no visitor), this loop is skipped. */
      for (ii = 0; ii < depth && checksum != NULL; ii++)
        {
          g_autoptr(GVariant) commit = NULL;
          gboolean stop = FALSE;

          if (!ostree_repo_load_commit (repo, checksum, &commit, NULL, error))
            goto out;

          if (!visitor (repo, checksum, commit, visitor_data, &stop, error))
            goto out;

          g_clear_pointer (&checksum, g_free);

          if (!stop)
            checksum = ostree_commit_get_parent (commit);
        }

      /* Break if no visitor, or visitor told us to stop. */
      if (depth < 0 || checksum == NULL)
        break;

      /* Pull the next batch of commits, twice as many. */
      refs_array[0] = checksum;
      depth = depth * 2;
    }

  ret = TRUE;

out:
  return ret;
}
gboolean
rpmostree_builtin_upgrade (int             argc,
                           char          **argv,
                           GCancellable   *cancellable,
                           GError        **error)
{
  gboolean ret = FALSE;

  GOptionContext *context = g_option_context_new ("- Perform a system upgrade");
  glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
  glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
  g_autoptr(GVariant) default_deployment = NULL;
  g_autofree char *transaction_address = NULL;

  if (!rpmostree_option_context_parse (context,
                                       option_entries,
                                       &argc, &argv,
                                       RPM_OSTREE_BUILTIN_FLAG_NONE,
                                       cancellable,
                                       &sysroot_proxy,
                                       error))
    goto out;

  if (opt_check_diff && opt_reboot)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "cannot specify both --reboot and --check-diff");
      goto out;
    }

  if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname,
                                cancellable, &os_proxy, error))
    goto out;

  if (opt_check_diff)
    {
      if (!rpmostree_os_call_download_update_rpm_diff_sync (os_proxy,
                                                            &transaction_address,
                                                            cancellable,
                                                            error))
        goto out;
    }
  else
    {
      g_signal_connect (os_proxy, "notify::default-deployment",
                        G_CALLBACK (default_changed_callback),
                        &default_deployment);

      if (!rpmostree_os_call_upgrade_sync (os_proxy,
                                           get_args_variant (),
                                           &transaction_address,
                                           cancellable,
                                           error))
        goto out;
    }

  if (!rpmostree_transaction_get_response_sync (sysroot_proxy,
                                                transaction_address,
                                                cancellable,
                                                error))
    goto out;

  if (opt_check_diff)
    {
      /* yes, doing this without using dbus */
      gs_unref_object OstreeSysroot *sysroot = NULL;
      gs_unref_object OstreeRepo *repo = NULL;
      gs_unref_object GFile *rpmdbdir = NULL;
      gs_unref_object GFile *sysroot_file = NULL;
      g_autofree char *origin_description = NULL;
      g_autoptr(GVariant) cached_update = NULL;
      const char *sysroot_path;
      GVariantDict upgrade_dict;

      _cleanup_rpmrev_ struct RpmRevisionData *rpmrev1 = NULL;
      _cleanup_rpmrev_ struct RpmRevisionData *rpmrev2 = NULL;

      gs_free char *ref = NULL; /* location of this rev */
      gs_free char *remote = NULL;

      if (!rpmostree_os_get_has_cached_update_rpm_diff (os_proxy))
        goto out;

      sysroot_path = rpmostree_sysroot_get_path (sysroot_proxy);
      sysroot_file = g_file_new_for_path (sysroot_path);
      sysroot = ostree_sysroot_new (sysroot_file);

      if (!ostree_sysroot_load (sysroot, cancellable, error))
        goto out;

      if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
        goto out;

      cached_update = rpmostree_os_dup_cached_update(os_proxy);
      g_variant_dict_init (&upgrade_dict, cached_update);
      if (!g_variant_dict_lookup (&upgrade_dict, "origin", "s", &origin_description))
        goto out;

      if (!ostree_parse_refspec (origin_description, &remote, &ref, error))
         goto out;

      if (rpmReadConfigFiles (NULL, NULL))
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                       "rpm failed to init: %s", rpmlogMessage ());
          goto out;
        }

      if (!(rpmrev1 = rpmrev_new (repo,
                                  ostree_deployment_get_csum (ostree_sysroot_get_booted_deployment (sysroot)),
                                  NULL, cancellable, error)))
        goto out;

      if (!(rpmrev2 = rpmrev_new (repo, ref,
                                  NULL, cancellable, error)))
        goto out;

      rpmhdrs_diff_prnt_diff (rpmhdrs_diff (rpmrev_get_headers (rpmrev1),
                                            rpmrev_get_headers (rpmrev2)));
    }
  else
    {
      /* nothing changed */
      if (default_deployment == NULL)
        {
          goto out;
        }
      if (!opt_reboot)
        {
          const char *sysroot_path;

          sysroot_path = rpmostree_sysroot_get_path (sysroot_proxy);

          if (!rpmostree_print_treepkg_diff_from_sysroot_path (sysroot_path,
                                                               cancellable,
                                                               error))
            goto out;

          g_print ("Run \"systemctl reboot\" to start a reboot\n");
        }
    }

  ret = TRUE;

out:
  /* Does nothing if using the message bus. */
  rpmostree_cleanup_peer ();

  return ret;
}
gboolean
ot_admin_builtin_switch (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
  g_autoptr(GOptionContext) context =
    g_option_context_new ("REF");
  g_autoptr(OstreeSysroot) sysroot = NULL;
  if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
                                          OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
                                          invocation, &sysroot, cancellable, error))
    return FALSE;

  if (argc < 2)
    {
      ot_util_usage_error (context, "REF must be specified", error);
      return FALSE;
    }

  const char *new_provided_refspec = argv[1];

  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)
    return FALSE;

  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))
    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, ":"))
    {
      new_remote = g_strdup (new_provided_refspec);
      new_remote[strlen(new_remote)-1] = '\0';
      new_ref = g_strdup (origin_ref);
    }
  else
    {
      if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error))
        return FALSE;
    }

  const char* remote = new_remote ?: origin_remote;
  g_autofree char *new_refspec = NULL;
  if (remote)
    new_refspec = g_strconcat (remote, ":", new_ref, NULL);
  else
    new_refspec = g_strdup (new_ref);

  if (strcmp (origin_refspec, new_refspec) == 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Old and new refs are equal: %s", new_refspec);
      return FALSE;
    }

  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))
    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))
      return FALSE;

    if (progress)
      ostree_async_progress_finish (progress);
  }

  if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
    return FALSE;

  OstreeRepo *repo = ostree_sysroot_repo (sysroot);
  if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
    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))
    return FALSE;

  if (opt_reboot)
    {
      if (!ot_admin_execve_reboot (sysroot, error))
        return FALSE;
    }

  return TRUE;
}
Example #20
0
gboolean
ostree_builtin_fsck (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
  g_autoptr(OstreeRepo) repo = NULL;
  gboolean found_corruption = FALSE;

  g_autoptr(GOptionContext) context = g_option_context_new ("");
  if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error))
    return FALSE;

  if (!opt_quiet)
    g_print ("Validating refs...\n");

  /* Validate that the commit for each ref is available */
  g_autoptr(GHashTable) all_refs = NULL;
  if (!ostree_repo_list_refs (repo, NULL, &all_refs,
                              cancellable, error))
    return FALSE;

  GHashTableIter hash_iter;
  gpointer key, value;
  g_hash_table_iter_init (&hash_iter, all_refs);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      const char *refspec = key;
      const char *checksum = value;
      g_autofree char *ref_name = NULL;
      if (!ostree_parse_refspec (refspec, NULL, &ref_name, error))
        return FALSE;
      if (!fsck_commit_for_ref (repo, checksum, NULL, ref_name,
                                &found_corruption, cancellable, error))
        return FALSE;
    }

  if (!opt_quiet)
    g_print ("Validating refs in collections...\n");

  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;

  g_hash_table_iter_init (&hash_iter, all_collection_refs);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      const OstreeCollectionRef *ref = key;
      if (!fsck_commit_for_ref (repo, value, ref->collection_id, ref->ref_name,
                                &found_corruption, cancellable, error))
        return FALSE;
    }

  if (!opt_quiet)
    g_print ("Enumerating objects...\n");

  g_autoptr(GHashTable) objects = NULL;
  if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL,
                                 &objects, cancellable, error))
    return FALSE;

  g_autoptr(GHashTable) commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
                                                         (GDestroyNotify)g_variant_unref, NULL);


  g_autoptr(GPtrArray) tombstones = NULL;
  if (opt_add_tombstones)
    tombstones = g_ptr_array_new_with_free_func (g_free);

  if (opt_verify_back_refs)
    opt_verify_bindings = TRUE;

  guint n_partial = 0;
  g_hash_table_iter_init (&hash_iter, objects);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      GVariant *serialized_key = key;
      const char *checksum;
      OstreeObjectType objtype;
      OstreeRepoCommitState commitstate = 0;
      g_autoptr(GVariant) commit = NULL;

      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);

      if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
        {
          if (!ostree_repo_load_commit (repo, checksum, &commit, &commitstate, error))
            return FALSE;

          /* If requested, check that all the refs listed in the ref-bindings
           * for this commit resolve back to this commit. */
          if (opt_verify_back_refs)
            {
              g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0);

              const char *collection_id = NULL;
              if (!g_variant_lookup (metadata,
                                     OSTREE_COMMIT_META_KEY_COLLECTION_BINDING,
                                     "&s",
                                     &collection_id))
                collection_id = NULL;

              g_autofree const char **refs = NULL;
              if (g_variant_lookup (metadata,
                                    OSTREE_COMMIT_META_KEY_REF_BINDING,
                                    "^a&s",
                                    &refs))
                {
                  for (const char **iter = refs; *iter != NULL; ++iter)
                    {
                      g_autofree char *checksum_for_ref = NULL;

                      if (collection_id != NULL)
                        {
                          const OstreeCollectionRef collection_ref = { (char *) collection_id, (char *) *iter };
                          if (!ostree_repo_resolve_collection_ref (repo, &collection_ref,
                                                                   TRUE,
                                                                   OSTREE_REPO_RESOLVE_REV_EXT_NONE,
                                                                   &checksum_for_ref,
                                                                   cancellable,
                                                                   error))
                            return FALSE;
                        }
                      else
                        {
                          if (!ostree_repo_resolve_rev (repo, *iter, TRUE,
                                                        &checksum_for_ref, error))
                            return FALSE;
                        }

                      if (checksum_for_ref == NULL)
                        {
                          if (collection_id != NULL)
                            return glnx_throw (error,
                                               "Collection–ref (%s, %s) in bindings for commit %s does not exist",
                                               collection_id, *iter, checksum);
                          else
                            return glnx_throw (error,
                                               "Ref ‘%s’ in bindings for commit %s does not exist",
                                               *iter, checksum);
                        }
                      else if (g_strcmp0 (checksum_for_ref, checksum) != 0)
                        {
                          if (collection_id != NULL)
                            return glnx_throw (error,
                                               "Collection–ref (%s, %s) in bindings for commit %s does not resolve to that commit",
                                               collection_id, *iter, checksum);
                          else
                            return glnx_throw (error,
                                               "Ref ‘%s’ in bindings for commit %s does not resolve to that commit",
                                               *iter, checksum);
                        }
                    }
                }
            }

          if (opt_add_tombstones)
            {
              GError *local_error = NULL;
              g_autofree char *parent = ostree_commit_get_parent (commit);
              if (parent)
                {
                  g_autoptr(GVariant) parent_commit = NULL;
                  if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, parent,
                                                 &parent_commit, &local_error))
                    {
                      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
                        {
                          g_ptr_array_add (tombstones, g_strdup (checksum));
                          g_clear_error (&local_error);
                        }
                      else
                        {
                          g_propagate_error (error, local_error);
                          return FALSE;
                        }
                    }
                }
            }

          if (commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL)
            n_partial++;
          else
            g_hash_table_add (commits, g_variant_ref (serialized_key));
        }
    }

  g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref);

  if (!opt_quiet)
    g_print ("Verifying content integrity of %u commit objects...\n",
             (guint)g_hash_table_size (commits));

  if (!fsck_reachable_objects_from_commits (repo, commits, &found_corruption,
                                            cancellable, error))
    return FALSE;

  if (opt_add_tombstones)
    {
      guint i;
      if (tombstones->len)
        {
          if (!ot_enable_tombstone_commits (repo, error))
            return FALSE;
        }
      for (i = 0; i < tombstones->len; i++)
        {
          const char *checksum = tombstones->pdata[i];
          g_print ("Adding tombstone for commit %s\n", checksum);
          if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum, cancellable, error))
            return FALSE;
        }
    }
  else if (n_partial > 0)
    {
      g_print ("%u partial commits not verified\n", n_partial);
    }

  if (found_corruption)
    return glnx_throw (error, "Repository corruption encountered");

  return TRUE;
}
Example #21
0
static gboolean
_ostree_repo_resolve_rev_internal (OstreeRepo     *self,
                                   const char     *refspec,
                                   gboolean        allow_noent,
                                   gboolean        fallback_remote,
                                   char          **out_rev,
                                   GError        **error)
{
  g_autofree char *ret_rev = NULL;

  g_return_val_if_fail (refspec != NULL, FALSE);

  if (ostree_validate_checksum_string (refspec, NULL))
    {
      ret_rev = g_strdup (refspec);
    }

  else if (!ostree_repo_resolve_partial_checksum (self, refspec, &ret_rev, error))
    return FALSE;

  if (!ret_rev)
    {
      if (error != NULL && *error != NULL)
        return FALSE;

      if (g_str_has_suffix (refspec, "^"))
        {
          g_autofree char *parent_refspec = NULL;
          g_autofree char *parent_rev = NULL;
          g_autoptr(GVariant) commit = NULL;

          parent_refspec = g_strdup (refspec);
          parent_refspec[strlen(parent_refspec) - 1] = '\0';

          if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error))
            return FALSE;

          if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev,
                                         &commit, error))
            return FALSE;

          if (!(ret_rev = ostree_commit_get_parent (commit)))
            return glnx_throw (error, "Commit %s has no parent", parent_rev);
        }
      else
        {
          g_autofree char *remote = NULL;
          g_autofree char *ref = NULL;

          if (!ostree_parse_refspec (refspec, &remote, &ref, error))
            return FALSE;

          if (!resolve_refspec (self, remote, ref, allow_noent,
                                fallback_remote, &ret_rev, error))
            return FALSE;
        }
    }

  ot_transfer_out_value (out_rev, &ret_rev);
  return TRUE;
}