gboolean
rpmostree_print_treepkg_diff (OstreeSysroot    *sysroot,
                              GCancellable     *cancellable,
                              GError          **error)
{
  gboolean ret = FALSE;
  OstreeDeployment *booted_deployment;
  OstreeDeployment *new_deployment;
  gs_unref_ptrarray GPtrArray *deployments = 
    ostree_sysroot_get_deployments (sysroot);
  gs_unref_object GFile *booted_root = NULL;
  gs_unref_object GFile *new_root = NULL;

  booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
  
  g_assert (deployments->len > 1);
  new_deployment = deployments->pdata[0];
  
  if (booted_deployment && new_deployment != booted_deployment)
    {
      booted_root = ostree_sysroot_get_deployment_directory (sysroot, booted_deployment);
      new_root = ostree_sysroot_get_deployment_directory (sysroot, new_deployment);
      
      if (!print_rpmdb_diff (booted_root, new_root, cancellable, error))
        goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
示例#2
0
gboolean
ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error)
{
  GOptionContext *context;
  gboolean ret = FALSE;
  gs_unref_object OstreeDeployment *deployment = NULL;
  gs_unref_object GFile *deployment_dir = NULL;
  gs_unref_ptrarray GPtrArray *modified = NULL;
  gs_unref_ptrarray GPtrArray *removed = NULL;
  gs_unref_ptrarray GPtrArray *added = NULL;
  gs_unref_object GFile *orig_etc_path = NULL;
  gs_unref_object GFile *new_etc_path = NULL;

  context = g_option_context_new ("Diff current /etc configuration versus default");

  g_option_context_add_main_entries (context, options, NULL);

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

  if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,
                                                     cancellable, error))
    goto out;
  if (opt_osname != NULL)
    {
      deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname);
      if (deployment == NULL)
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                       "No deployment for OS '%s'", opt_osname);
          goto out;
        }
    }
  else
    deployment = g_object_ref (ostree_sysroot_get_booted_deployment (sysroot));

  deployment_dir = ostree_sysroot_get_deployment_directory (sysroot, deployment);

  orig_etc_path = g_file_resolve_relative_path (deployment_dir, "usr/etc");
  new_etc_path = g_file_resolve_relative_path (deployment_dir, "etc");
  
  modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
  removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
  added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
  if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_IGNORE_XATTRS,
                         orig_etc_path, new_etc_path, modified, removed, added,
                         cancellable, error))
    goto out;

  ostree_diff_print (orig_etc_path, new_etc_path, modified, removed, added);

  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  return ret;
}
gboolean
ot_admin_builtin_unlock (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(OstreeSysroot) sysroot = NULL;
  OstreeDeployment *booted_deployment = NULL;
  OstreeDeploymentUnlockedState target_state;

  context = g_option_context_new ("");

  if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
                                          OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
                                          invocation, &sysroot, cancellable, error))
    goto out;
  
  if (argc > 1)
    {
      ot_util_usage_error (context, "This command takes no extra arguments", error);
      goto out;
    }

  booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
  if (!booted_deployment)
    {
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Not currently booted into an OSTree system");
      goto out;
    }

  target_state = opt_hotfix ? OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX : OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;

  if (!ostree_sysroot_deployment_unlock (sysroot, booted_deployment,
                                         target_state, cancellable, error))
    goto out;
  
  switch (target_state)
    {
    case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
      g_assert_not_reached ();
      break;
    case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
      g_print ("Hotfix mode enabled.  A writable overlayfs is now mounted on /usr\n"
               "for this booted deployment.  A non-hotfixed clone has been created\n"
               "as the non-default rollback target.\n");
      break;
    case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
      g_print ("Development mode enabled.  A writable overlayfs is now mounted on /usr.\n"
               "All changes there will be discarded on reboot.\n");
      break;
    }

  ret = TRUE;
 out:
  return ret;
}
示例#4
0
/**
 * ostree_sysroot_simple_write_deployment:
 * @sysroot: Sysroot
 * @osname: (allow-none): OS name
 * @new_deployment: Prepend this deployment to the list
 * @merge_deployment: (allow-none): Use this deployment for configuration merge
 * @flags: Flags controlling behavior
 * @cancellable: Cancellable
 * @error: Error
 *
 * Prepend @new_deployment to the list of deployments, commit, and
 * cleanup.  By default, all other deployments for the given @osname
 * except the merge deployment and the booted deployment will be
 * garbage collected.
 *
 * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is
 * specified, then all current deployments will be kept.
 */
gboolean
ostree_sysroot_simple_write_deployment (OstreeSysroot      *sysroot,
                                        const char         *osname,
                                        OstreeDeployment   *new_deployment,
                                        OstreeDeployment   *merge_deployment,
                                        OstreeSysrootSimpleWriteDeploymentFlags flags,
                                        GCancellable       *cancellable,
                                        GError            **error)
{
  gboolean ret = FALSE;
  guint i;
  OstreeDeployment *booted_deployment = NULL;
  g_autoptr(GPtrArray) deployments = NULL;
  g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
  gboolean retain = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0;

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

  if (osname == NULL && booted_deployment)
    osname = ostree_deployment_get_osname (booted_deployment);

  g_ptr_array_add (new_deployments, g_object_ref (new_deployment));

  for (i = 0; i < deployments->len; i++)
    {
      OstreeDeployment *deployment = deployments->pdata[i];
      
      /* Keep deployments with different osnames, as well as the
       * booted and merge deployments
       */
      if (retain ||
          (osname != NULL &&
           strcmp (ostree_deployment_get_osname (deployment), osname) != 0) ||
          ostree_deployment_equal (deployment, booted_deployment) ||
          ostree_deployment_equal (deployment, merge_deployment))
        {
          g_ptr_array_add (new_deployments, g_object_ref (deployment));
        }
    }

  if (!ostree_sysroot_write_deployments (sysroot, new_deployments, cancellable, error))
    goto out;

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

  ret = TRUE;
 out:
  return ret;
}
示例#5
0
gboolean
ot_admin_require_booted_deployment_or_osname (OstreeSysroot       *sysroot,
                                              const char          *osname,
                                              GCancellable        *cancellable,
                                              GError             **error)
{
  gboolean ret = FALSE;
  OstreeDeployment *booted_deployment =
    ostree_sysroot_get_booted_deployment (sysroot);

  if (booted_deployment == NULL && osname == NULL)
    {
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Not currently booted into an OSTree system and no --os= argument given");
      goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
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;
}
示例#7
0
static gboolean
sysroot_populate_deployments_unlocked (RpmostreedSysroot *self,
				       gboolean *out_changed,
				       GError **error)
{
  gboolean ret = FALSE;
  OstreeDeployment *booted = NULL; /* owned by sysroot */
  g_autofree gchar *booted_id = NULL;
  g_autoptr(GPtrArray) deployments = NULL;
  g_autoptr(GHashTable) seen_osnames = NULL;
  GHashTableIter iter;
  gpointer hashkey;
  gpointer value;
  GVariantBuilder builder;
  guint i;
  gboolean sysroot_changed;
  gboolean repo_changed;
  struct stat repo_new_stat;

  if (!ostree_sysroot_load_if_changed (self->ot_sysroot, &sysroot_changed, self->cancellable, error))
    goto out;

  if (fstat (ostree_repo_get_dfd (self->repo), &repo_new_stat) < 0)
    {
      glnx_set_error_from_errno (error);
      goto out;
    }

  repo_changed = !(self->repo_last_stat.st_mtim.tv_sec == repo_new_stat.st_mtim.tv_sec
		   && self->repo_last_stat.st_mtim.tv_nsec == repo_new_stat.st_mtim.tv_nsec);
  if (repo_changed)
    self->repo_last_stat = repo_new_stat;

  if (!(sysroot_changed || repo_changed))
    {
      ret = TRUE;
      if (out_changed)
	*out_changed = FALSE;
      goto out;
    }

  g_debug ("loading deployments");
  g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));

  seen_osnames = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);

  /* Updated booted property */
  booted = ostree_sysroot_get_booted_deployment (self->ot_sysroot);
  if (booted)
    {
      const gchar *os = ostree_deployment_get_osname (booted);
      g_autofree gchar *path = rpmostreed_generate_object_path (BASE_DBUS_PATH,
                                                                os, NULL);
      rpmostree_sysroot_set_booted (RPMOSTREE_SYSROOT (self), path);
      booted_id = rpmostreed_deployment_generate_id (booted);
    }
  else
    {
      rpmostree_sysroot_set_booted (RPMOSTREE_SYSROOT (self), "/");
    }

  /* Add deployment interfaces */
  deployments = ostree_sysroot_get_deployments (self->ot_sysroot);

  for (i = 0; deployments != NULL && i < deployments->len; i++)
    {
      GVariant *variant;
      OstreeDeployment *deployment = deployments->pdata[i];
      const char *deployment_os;
      
      variant = rpmostreed_deployment_generate_variant (deployment, booted_id, self->repo, error);
      if (!variant)
	goto out;
      g_variant_builder_add_value (&builder, variant);

      deployment_os = ostree_deployment_get_osname (deployment);

      /* Have we not seen this osname instance before?  If so, add it
       * now.
       */
      if (!g_hash_table_contains (self->os_interfaces, deployment_os))
	{
	  RPMOSTreeOS *obj = rpmostreed_os_new (self->ot_sysroot, self->repo,
						deployment_os,
                                                self->transaction_monitor);
          g_hash_table_insert (self->os_interfaces, g_strdup (deployment_os), obj);
	}
      /* Owned by deployment, hash lifetime is smaller */
      g_hash_table_add (seen_osnames, (char*)deployment_os);
    }

  /* Remove dead os paths */
  g_hash_table_iter_init (&iter, self->os_interfaces);
  while (g_hash_table_iter_next (&iter, &hashkey, &value))
    {
      if (!g_hash_table_contains (seen_osnames, hashkey))
        {
          g_object_run_dispose (G_OBJECT (value));
          g_hash_table_iter_remove (&iter);
        }
    }

  rpmostree_sysroot_set_deployments (RPMOSTREE_SYSROOT (self),
                                     g_variant_builder_end (&builder));
  g_debug ("finished deployments");

  ret = TRUE;
  if (out_changed)
    *out_changed = 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
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;
}
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;
}
示例#11
0
gboolean
ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  GOptionContext *context;
  gs_unref_object OstreeSysroot *sysroot = NULL;
  const char *deploy_index_str;
  int deploy_index;
  gs_unref_ptrarray GPtrArray *current_deployments = NULL;
  gs_unref_object OstreeDeployment *booted_deployment = NULL;
  gs_unref_object OstreeDeployment *target_deployment = NULL;

  context = g_option_context_new ("INDEX - Delete deployment INDEX");

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

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

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

  deploy_index_str = argv[1];
  deploy_index = atoi (deploy_index_str);

  target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error);
  if (!target_deployment)
    goto out;

  if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                   "Cannot undeploy currently booted deployment %i", deploy_index);
      goto out;
    }
  
  g_ptr_array_remove_index (current_deployments, deploy_index);

  if (!ostree_sysroot_write_deployments (sysroot, current_deployments,
                                         cancellable, error))
    goto out;

  g_print ("Deleted deployment %s.%d\n", ostree_deployment_get_csum (target_deployment),
           ostree_deployment_get_deployserial (target_deployment));
  
  if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
    {
      g_prefix_error (error, "Performing final cleanup: ");
      goto out;
    }

  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  return ret;
}
gboolean
rpmostree_builtin_rollback (int             argc,
                            char          **argv,
                            GCancellable   *cancellable,
                            GError        **error)
{
  gboolean ret = FALSE;
  GOptionContext *context = g_option_context_new ("- Revert to the previously booted tree");
  gs_unref_object GFile *sysroot_path = NULL;
  gs_unref_object OstreeSysroot *sysroot = NULL;
  gs_free char *origin_description = NULL;
  gs_unref_ptrarray GPtrArray *deployments = NULL;
  gs_unref_ptrarray GPtrArray *new_deployments =
    g_ptr_array_new_with_free_func (g_object_unref);
  OstreeDeployment *booted_deployment = NULL;
  guint i;
  guint booted_index;
  guint index_to_prepend;
  
  if (!rpmostree_option_context_parse (context, option_entries, &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;

  booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
  if (booted_deployment == NULL)
    {
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Not currently booted into an OSTree system");
      goto out;
    }

  deployments = ostree_sysroot_get_deployments (sysroot);
  if (deployments->len < 2)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Found %u deployments, at least 2 required for rollback",
                   deployments->len);
      goto out;
    }

  g_assert (booted_deployment != NULL);
  for (booted_index = 0; booted_index < deployments->len; booted_index++)
    {
      if (deployments->pdata[booted_index] == booted_deployment)
        break;
    }
  g_assert (booted_index < deployments->len);
  g_assert (deployments->pdata[booted_index] == booted_deployment);
  
  if (booted_index != 0)
    {
      /* There is an earlier deployment, let's assume we want to just
       * insert the current one in front.
       */

       /*
       What this does is, if we're NOT in the default boot index, it plans to prepend
       our current index (1, since we can't have more than two trees) so that it becomes index 0 
       (default) and the current default becomes index 1
       */
      index_to_prepend = booted_index;
    }
  else
    {
      /* We're booted into the first, let's roll back to the previous */
      index_to_prepend = 1;
    }
  
  g_ptr_array_add (new_deployments, g_object_ref (deployments->pdata[index_to_prepend]));
  for (i = 0; i < deployments->len; i++)
    {
      if (i == index_to_prepend)
        continue;
      g_ptr_array_add (new_deployments, g_object_ref (deployments->pdata[i]));
    }

  g_print ("Moving '%s.%d' to be first deployment\n",
           ostree_deployment_get_csum (deployments->pdata[index_to_prepend]),
           ostree_deployment_get_deployserial (deployments->pdata[index_to_prepend]));

  if (!ostree_sysroot_write_deployments (sysroot, new_deployments, cancellable,
                                         error))
    goto out;

  if (opt_reboot)
    gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
                                   cancellable, error,
                                   "systemctl", "reboot", NULL);
  else
    {
      if (!rpmostree_print_treepkg_diff (sysroot, cancellable, error))
        goto out;

      g_print ("Successfully reset deployment order; run \"systemctl reboot\" to start a reboot\n");
    }

  if (opt_reboot)
  ret = TRUE;
 out:
  return ret;
}
示例#13
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;
}