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;
}
void
rpmostreed_deployment_get_refspec_packages (OstreeDeployment *deployment,
        char            **out_refspec,
        char           ***out_packages)
{
    GKeyFile *origin = NULL; /* owned by deployment */
    gsize len;

    g_return_if_fail (out_refspec != NULL);

    origin = ostree_deployment_get_origin (deployment);

    if (!origin)
    {
        *out_refspec = NULL;
        *out_packages = NULL;
        return;
    }

    *out_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
    if (!*out_refspec)
        *out_refspec = g_key_file_get_string (origin, "origin", "baserefspec", NULL);

    if (out_packages)
        *out_packages = g_key_file_get_string_list (origin, "packages", "requested", &len, NULL);
}
gboolean
get_origin_refspec (OstreeDeployment *booted_deployment,
                    gchar **out_refspec,
                    GError **error)
{
  GKeyFile *origin;
  g_autofree gchar *refspec = NULL;

  g_return_val_if_fail (OSTREE_IS_DEPLOYMENT (booted_deployment), FALSE);
  g_return_val_if_fail (out_refspec != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  origin = ostree_deployment_get_origin (booted_deployment);
  if (origin == NULL)
    {
      const gchar *osname = ostree_deployment_get_osname (booted_deployment);
      const gchar *booted = ostree_deployment_get_csum (booted_deployment);

      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                   "No origin found for %s (%s), cannot upgrade",
                   osname, booted);
      return FALSE;
    }

  refspec = g_key_file_get_string (origin, "origin", "refspec", error);
  if (refspec == NULL)
    return FALSE;

  *out_refspec = g_steal_pointer (&refspec);
  return TRUE;
}
char *
rpmostreed_deployment_get_refspec (OstreeDeployment *deployment)
{
  GKeyFile *origin = NULL; /* owned by deployment */
  char *origin_refspec = NULL;
  origin = ostree_deployment_get_origin (deployment);

  if (!origin)
    goto out;

  origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);

out:
  return origin_refspec;
}
gboolean
ot_admin_builtin_status (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
  const int is_tty = isatty (1);
  const char *red_bold_prefix = is_tty ? "\x1b[31m\x1b[1m" : "";
  const char *red_bold_suffix = is_tty ? "\x1b[22m\x1b[0m" : "";

  g_autoptr(GOptionContext) context = g_option_context_new ("");

  g_autoptr(OstreeSysroot) sysroot = NULL;
  if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
                                          OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED,
                                          invocation, &sysroot, cancellable, error))
    return FALSE;

  g_autoptr(OstreeRepo) repo = NULL;
  if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
    return FALSE;

  g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot);
  OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);

  g_autoptr(OstreeDeployment) pending_deployment = NULL;
  g_autoptr(OstreeDeployment) rollback_deployment = NULL;
  if (booted_deployment)
    ostree_sysroot_query_deployments_for (sysroot, NULL, &pending_deployment,
                                          &rollback_deployment);

  if (deployments->len == 0)
    {
      g_print ("No deployments.\n");
    }
  else
    {
      for (guint i = 0; i < deployments->len; i++)
        {
          OstreeDeployment *deployment = deployments->pdata[i];
          const char *ref = ostree_deployment_get_csum (deployment);

          /* Load the backing commit; shouldn't normally fail, but if it does,
           * we stumble on.
           */
          g_autoptr(GVariant) commit = NULL;
          (void)ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, ref,
                                          &commit, NULL);
          g_autoptr(GVariant) commit_metadata = NULL;
          if (commit)
            commit_metadata = g_variant_get_child_value (commit, 0);

          const char *version = NULL;
          const char *source_title = NULL;
          if (commit_metadata)
            {
              (void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_VERSION, "&s", &version);
              (void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_SOURCE_TITLE, "&s", &source_title);
            }

          GKeyFile *origin = ostree_deployment_get_origin (deployment);

          const char *deployment_status = "";
          if (deployment == pending_deployment)
            deployment_status = " (pending)";
          else if (deployment == rollback_deployment)
            deployment_status = " (rollback)";
          g_print ("%c %s %s.%d%s\n",
                   deployment == booted_deployment ? '*' : ' ',
                   ostree_deployment_get_osname (deployment),
                   ostree_deployment_get_csum (deployment),
                   ostree_deployment_get_deployserial (deployment),
                   deployment_status);
          if (version)
            g_print ("    Version: %s\n", version);

          OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment);
          switch (unlocked)
            {
            case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
              break;
            default:
              g_print ("    %sUnlocked: %s%s\n", red_bold_prefix,
                       ostree_deployment_unlocked_state_to_string (unlocked),
                       red_bold_suffix);
            }
          if (!origin)
            g_print ("    origin: none\n");
          else
            {
              g_autofree char *origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
              if (!origin_refspec)
                g_print ("    origin: <unknown origin type>\n");
              else
                g_print ("    origin refspec: %s\n", origin_refspec);
              if (source_title)
                g_print ("    `- %s\n", source_title);
            }

          if (deployment_get_gpg_verify (deployment, repo))
            {
              g_autoptr(GString) output_buffer = g_string_sized_new (256);
              /* Print any digital signatures on this commit. */

              g_autoptr(GError) local_error = NULL;
              g_autoptr(OstreeGpgVerifyResult) result =
                ostree_repo_verify_commit_ext (repo, ref, NULL, NULL,
                                               cancellable, &local_error);

              /* G_IO_ERROR_NOT_FOUND just means the commit is not signed. */
              if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
                {
                  g_clear_error (&local_error);
                  continue;
                }
              else if (local_error != NULL)
                {
                  g_propagate_error (error, g_steal_pointer (&local_error));
                  return FALSE;
                }

              const guint n_signatures = ostree_gpg_verify_result_count_all (result);
              for (guint jj = 0; jj < n_signatures; jj++)
                {
                  ostree_gpg_verify_result_describe (result, jj, output_buffer, "    GPG: ",
                                                     OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
                }

              g_print ("%s", output_buffer->str);
            }
        }
    }

  return TRUE;
}
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 #7
0
gboolean
ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  g_autoptr(GOptionContext) context = NULL;
  glnx_unref_object OstreeSysroot *sysroot = NULL;
  gboolean ret = FALSE;
  glnx_unref_object OstreeRepo *repo = NULL;
  OstreeDeployment *booted_deployment = NULL;
  g_autoptr(GPtrArray) deployments = NULL;
  const int is_tty = isatty (1);
  const char *red_bold_prefix = is_tty ? "\x1b[31m\x1b[1m" : "";
  const char *red_bold_suffix = is_tty ? "\x1b[22m\x1b[0m" : "";
  guint i;

  context = g_option_context_new ("List deployments");

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

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

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

  deployments = ostree_sysroot_get_deployments (sysroot);
  booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);

  if (deployments->len == 0)
    {
      g_print ("No deployments.\n");
    }
  else
    {
      for (i = 0; i < deployments->len; i++)
        {
          OstreeDeployment *deployment = deployments->pdata[i];
          GKeyFile *origin;
          const char *ref = ostree_deployment_get_csum (deployment);
          OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment);
          g_autofree char *version = version_of_commit (repo, ref);
          glnx_unref_object OstreeGpgVerifyResult *result = NULL;
          GString *output_buffer;
          guint jj, n_signatures;
          GError *local_error = NULL;

          origin = ostree_deployment_get_origin (deployment);

          g_print ("%c %s %s.%d\n",
                   deployment == booted_deployment ? '*' : ' ',
                   ostree_deployment_get_osname (deployment),
                   ostree_deployment_get_csum (deployment),
                   ostree_deployment_get_deployserial (deployment));
          if (version)
            g_print ("    Version: %s\n", version);
          switch (unlocked)
            {
            case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
              break;
            default:
              g_print ("    %sUnlocked: %s%s\n", red_bold_prefix,
                       ostree_deployment_unlocked_state_to_string (unlocked),
                       red_bold_suffix);
            }
          if (!origin)
            g_print ("    origin: none\n");
          else
            {
              g_autofree char *origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
              if (!origin_refspec)
                g_print ("    origin: <unknown origin type>\n");
              else
                g_print ("    origin refspec: %s\n", origin_refspec);
            }

          if (deployment_get_gpg_verify (deployment, repo))
            {
              /* Print any digital signatures on this commit. */

              result = ostree_repo_verify_commit_ext (repo, ref, NULL, NULL,
                                                      cancellable, &local_error);

              /* G_IO_ERROR_NOT_FOUND just means the commit is not signed. */
              if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
                {
                  g_clear_error (&local_error);
                  continue;
                }
              else if (local_error != NULL)
                {
                  g_propagate_error (error, local_error);
                  goto out;
                }

              output_buffer = g_string_sized_new (256);
              n_signatures = ostree_gpg_verify_result_count_all (result);

              for (jj = 0; jj < n_signatures; jj++)
                {
                  ostree_gpg_verify_result_describe (result, jj, output_buffer, "    GPG: ",
                                                     OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
                }

              g_print ("%s", output_buffer->str);
              g_string_free (output_buffer, TRUE);
            }
        }
    }

  ret = TRUE;
 out:
  return ret;
}