gboolean
ot_admin_instutil_builtin_set_kargs (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  guint i;
  g_autoptr(GPtrArray) deployments = NULL;
  OstreeDeployment *first_deployment = NULL;
  GOptionContext *context = NULL;
  glnx_unref_object OstreeSysroot *sysroot = NULL;
  __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;

  context = g_option_context_new ("ARGS - set new kernel command line arguments");

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

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

  deployments = ostree_sysroot_get_deployments (sysroot);
  if (deployments->len == 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Unable to find a deployment in sysroot");
      goto out;
    }
  first_deployment = deployments->pdata[0];

  kargs = _ostree_kernel_args_new ();

  /* If they want the current kernel's args, they very likely don't
   * want the ones from the merge.
   */
  if (opt_proc_cmdline)
    {
      if (!_ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error))
        goto out;
    }
  else if (opt_merge)
    {
      OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (first_deployment);
      g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);

      _ostree_kernel_args_append_argv (kargs, previous_args);
    }

  if (opt_replace)
    {
      _ostree_kernel_args_replace_argv (kargs, opt_replace);
    }

  if (opt_append)
    {
      _ostree_kernel_args_append_argv (kargs, opt_append);
    }

  for (i = 1; i < argc; i++)
    _ostree_kernel_args_append (kargs, argv[i]);

  {
    g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);

    if (!ostree_sysroot_deployment_set_kargs (sysroot, first_deployment,
                                              kargs_strv,
                                              cancellable, error))
      goto out;
  }

  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  return ret;
}
gboolean
ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  const char *refspec;
  GOptionContext *context;
  GKeyFile *origin = NULL;
  gs_unref_object OstreeRepo *repo = NULL;
  gs_unref_ptrarray GPtrArray *new_deployments = NULL;
  gs_unref_object OstreeDeployment *new_deployment = NULL;
  gs_unref_object OstreeDeployment *merge_deployment = NULL;
  gs_free char *revision = NULL;
  __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;

  context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment");

  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/REV must be specified", error);
      goto out;
    }

  refspec = argv[1];

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

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

  /* Find the currently booted deployment, if any; we will ensure it
   * is present in the new deployment list.
   */
  if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,
                                                     cancellable, error))
    {
      g_prefix_error (error, "Looking for booted deployment: ");
      goto out;
    }

  if (opt_origin_path)
    {
      origin = g_key_file_new ();
      
      if (!g_key_file_load_from_file (origin, opt_origin_path, 0, error))
        goto out;
    }
  else
    {
      origin = ostree_sysroot_origin_new_from_refspec (sysroot, refspec);
    }

  if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error))
    goto out;

  merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname);

  /* Here we perform cleanup of any leftover data from previous
   * partial failures.  This avoids having to call gs_shutil_rm_rf()
   * at random points throughout the process.
   *
   * TODO: Add /ostree/transaction file, and only do this cleanup if
   * we find it.
   */
  if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
    {
      g_prefix_error (error, "Performing initial cleanup: ");
      goto out;
    }

  kargs = _ostree_kernel_args_new ();

  /* If they want the current kernel's args, they very likely don't
   * want the ones from the merge.
   */
  if (opt_kernel_proc_cmdline)
    {
      gs_unref_object GFile *proc_cmdline_path = g_file_new_for_path ("/proc/cmdline");
      gs_free char *proc_cmdline = NULL;
      gsize proc_cmdline_len = 0;
      gs_strfreev char **proc_cmdline_args = NULL;

      if (!g_file_load_contents (proc_cmdline_path, cancellable,
                                 &proc_cmdline, &proc_cmdline_len,
                                 NULL, error))
        goto out;

      g_strchomp (proc_cmdline);

      proc_cmdline_args = g_strsplit (proc_cmdline, " ", -1);
      _ostree_kernel_args_replace_argv (kargs, proc_cmdline_args);
    }
  else if (merge_deployment)
    {
      OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
      gs_strfreev char **previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);

      _ostree_kernel_args_replace_argv (kargs, previous_args);
    }

  if (opt_kernel_argv)
    {
      _ostree_kernel_args_replace_argv (kargs, opt_kernel_argv);
    }

  if (opt_kernel_argv_append)
    {
      _ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append);
    }

  {
    gs_strfreev char **kargs_strv = _ostree_kernel_args_to_strv (kargs);

    if (!ostree_sysroot_deploy_tree (sysroot,
                                     opt_osname, revision, origin,
                                     merge_deployment, kargs_strv,
                                     &new_deployment,
                                     cancellable, error))
      goto out;
  }

  if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname,
                                               new_deployment, merge_deployment,
                                               opt_retain ? OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN : 0,
                                               cancellable, error))
    goto out;

  ret = TRUE;
 out:
  if (origin)
    g_key_file_unref (origin);
  if (context)
    g_option_context_free (context);
  return ret;
}