Пример #1
0
/**
 * ostree_sysroot_get_deployment_origin_path:
 * @deployment_path: A deployment path
 *
 * Returns: (transfer full): Path to deployment origin file
 */
GFile *
ostree_sysroot_get_deployment_origin_path (GFile   *deployment_path)
{
  g_autoptr(GFile) deployment_parent = g_file_get_parent (deployment_path);
  return ot_gfile_resolve_path_printf (deployment_parent,
                                       "%s.origin",
                                       gs_file_get_path_cached (deployment_path));
}
Пример #2
0
static gboolean
cleanup_other_bootversions (OstreeSysroot       *self,
                            GCancellable        *cancellable,
                            GError             **error)
{
    gboolean ret = FALSE;
    int cleanup_bootversion;
    int cleanup_subbootversion;
    gs_unref_object GFile *cleanup_boot_dir = NULL;

    cleanup_bootversion = self->bootversion == 0 ? 1 : 0;
    cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0;

    cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion);
    if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
        goto out;
    g_clear_object (&cleanup_boot_dir);

    cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d", cleanup_bootversion);
    if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
        goto out;
    g_clear_object (&cleanup_boot_dir);

    cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.0", cleanup_bootversion);
    if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
        goto out;
    g_clear_object (&cleanup_boot_dir);

    cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.1", cleanup_bootversion);
    if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
        goto out;
    g_clear_object (&cleanup_boot_dir);

    cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion,
                       cleanup_subbootversion);
    if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
        goto out;
    g_clear_object (&cleanup_boot_dir);

    ret = TRUE;
out:
    return ret;
}
Пример #3
0
static gboolean
_ostree_bootloader_uboot_write_config (OstreeBootloader          *bootloader,
                                  int                    bootversion,
                                  GCancellable          *cancellable,
                                  GError               **error)
{
  OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader);
  g_autoptr(GFile) new_config_path = NULL;
  g_autofree char *config_contents = NULL;
  g_autofree char *new_config_contents = NULL;
  g_autoptr(GPtrArray) new_lines = NULL;

  /* This should follow the symbolic link to the current bootversion. */
  config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL,
                                                    cancellable, error);
  if (!config_contents)
    return FALSE;

  new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/uEnv.txt",
                                                      bootversion);

  new_lines = g_ptr_array_new_with_free_func (g_free);

  if (!create_config_from_boot_loader_entries (self, bootversion, new_lines,
                                               cancellable, error))
    return FALSE;

  new_config_contents = _ostree_sysroot_join_lines (new_lines);
  {
    g_autoptr(GBytes) new_config_contents_bytes =
      g_bytes_new_static (new_config_contents,
                          strlen (new_config_contents));

    if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
                                          cancellable, error))
      return FALSE;
  }

  return TRUE;
}
Пример #4
0
static gboolean
resolve_refspec (OstreeRepo     *self,
                 const char     *remote,
                 const char     *ref,
                 gboolean        allow_noent,
                 char          **out_rev,
                 GError        **error)
{
    gboolean ret = FALSE;
    __attribute__((unused)) GCancellable *cancellable = NULL;
    GError *temp_error = NULL;
    g_autofree char *ret_rev = NULL;
    g_autoptr(GFile) child = NULL;

    g_return_val_if_fail (ref != NULL, FALSE);

    /* We intentionally don't allow a ref that looks like a checksum */
    if (ostree_validate_checksum_string (ref, NULL))
    {
        ret_rev = g_strdup (ref);
    }
    else if (remote != NULL)
    {
        child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s",
                                              remote, ref);
        if (!g_file_query_exists (child, NULL))
            g_clear_object (&child);
    }
    else
    {
        child = g_file_resolve_relative_path (self->local_heads_dir, ref);

        if (!g_file_query_exists (child, NULL))
        {
            g_clear_object (&child);

            child = g_file_resolve_relative_path (self->remote_heads_dir, ref);

            if (!g_file_query_exists (child, NULL))
            {
                g_clear_object (&child);

                if (!find_ref_in_remotes (self, ref, &child, error))
                    goto out;
            }
        }
    }

    if (child)
    {
        if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL)
        {
            g_propagate_error (error, temp_error);
            g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child));
            goto out;
        }

        g_strchomp (ret_rev);
        if (!ostree_validate_checksum_string (ret_rev, error))
            goto out;
    }
    else
    {
        if (!resolve_refspec_fallback (self, remote, ref, allow_noent,
                                       &ret_rev, cancellable, error))
            goto out;
    }

    ot_transfer_out_value (out_rev, &ret_rev);
    ret = TRUE;
out:
    return ret;
}
Пример #5
0
static gboolean
_ostree_bootloader_grub2_write_config (OstreeBootloader      *bootloader,
                                       int                    bootversion,
                                       GCancellable          *cancellable,
                                       GError               **error)
{
  OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
  gboolean ret = FALSE;
  gs_unref_object GFile *efi_new_config_temp = NULL;
  gs_unref_object GFile *efi_orig_config = NULL;
  gs_unref_object GFile *new_config_path = NULL;
  gs_unref_object GSSubprocessContext *procctx = NULL;
  gs_unref_object GSSubprocess *proc = NULL;
  gs_strfreev char **child_env = g_get_environ ();
  gs_free char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
  gs_unref_object GFile *config_path_efi_dir = NULL;

  if (self->is_efi)
    {
      config_path_efi_dir = g_file_get_parent (self->config_path_efi);
      new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new");
      /* We use grub2-mkconfig to write to a temporary file first */
      if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error))
        goto out;
    }
  else
    {
      new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/grub.cfg",
                                                      bootversion);
    }

  procctx = gs_subprocess_context_newv ("grub2-mkconfig", "-o",
                                        gs_file_get_path_cached (new_config_path),
                                        NULL);
  child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_BOOTVERSION", bootversion_str, TRUE);
  /* We have to pass our state to the child */
  if (self->is_efi)
    child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_IS_EFI", "1", TRUE);
  gs_subprocess_context_set_environment (procctx, child_env);
  gs_subprocess_context_set_stdout_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
  if (g_getenv ("OSTREE_DEBUG_GRUB2"))
    gs_subprocess_context_set_stderr_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT);
  else
    gs_subprocess_context_set_stderr_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL);

  /* In the current Fedora grub2 package, this script doesn't even try
     to be atomic; it just does:

cat ${grub_cfg}.new > ${grub_cfg}
rm -f ${grub_cfg}.new

     Upstream is fixed though.
  */
  proc = gs_subprocess_new (procctx, cancellable, error);
  if (!proc)
    goto out;

  if (!gs_subprocess_wait_sync_check (proc, cancellable, error))
    goto out;

  /* Now let's fdatasync() for the new file */
  if (!gs_file_sync_data (new_config_path, cancellable, error))
    goto out;

  if (self->is_efi)
    {
      gs_unref_object GFile *config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old");
      
      /* copy current to old */
      if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error))
        goto out;
      if (!g_file_copy (self->config_path_efi, config_path_efi_old,
                        G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error))
        goto out;
      if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error))
        goto out;

      /* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT;
       * see https://bugzilla.gnome.org/show_bug.cgi?id=724246
       */
      if (!ot_gfile_ensure_unlinked (self->config_path_efi, cancellable, error))
        goto out;
      if (!gs_file_rename (new_config_path, self->config_path_efi,
                           cancellable, error))
        goto out;
    }
  
  ret = TRUE;
 out:
  return ret;
}
Пример #6
0
static gboolean
_ostree_bootloader_syslinux_write_config (OstreeBootloader          *bootloader,
                                     int                    bootversion,
                                     GCancellable          *cancellable,
                                     GError               **error)
{
  gboolean ret = FALSE;
  OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader);
  gs_unref_object GFile *new_config_path = NULL;
  gs_free char *config_contents = NULL;
  gs_free char *new_config_contents = NULL;
  gs_unref_ptrarray GPtrArray *new_lines = NULL;
  gs_unref_ptrarray GPtrArray *tmp_lines = NULL;
  gs_free char *kernel_arg = NULL;
  gboolean saw_default = FALSE;
  gboolean regenerate_default = FALSE;
  gboolean parsing_label = FALSE;
  char **lines = NULL;
  char **iter;
  guint i;

  new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg",
                                                  bootversion);

  /* This should follow the symbolic link to the current bootversion. */
  config_contents = gs_file_load_contents_utf8 (self->config_path, cancellable, error);
  if (!config_contents)
    goto out;

  lines = g_strsplit (config_contents, "\n", -1);
  new_lines = g_ptr_array_new_with_free_func (g_free);
  tmp_lines = g_ptr_array_new_with_free_func (g_free);
  
  /* Note special iteration condition here; we want to also loop one
   * more time at the end where line = NULL to ensure we finish off
   * processing the last LABEL.
   */
  iter = lines;
  while (TRUE)
    {
      char *line = *iter;
      gboolean skip = FALSE;

      if (parsing_label && 
          (line == NULL || !g_str_has_prefix (line, "\t")))
        {
          parsing_label = FALSE;
          if (kernel_arg == NULL)
            {
              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                   "No KERNEL argument found after LABEL");
              goto out;
            }

          /* If this is a non-ostree kernel, just emit the lines
           * we saw.
           */
          if (!g_str_has_prefix (kernel_arg, "/ostree/"))
            {
              for (i = 0; i < tmp_lines->len; i++)
                {
                  g_ptr_array_add (new_lines, tmp_lines->pdata[i]);
                  tmp_lines->pdata[i] = NULL; /* Transfer ownership */
                }
            }
          else
            {
              /* Otherwise, we drop the config on the floor - it
               * will be regenerated.
               */
              g_ptr_array_set_size (tmp_lines, 0);
            }
        }

      if (line == NULL)
        break;

      if (!parsing_label &&
          (g_str_has_prefix (line, "LABEL ")))
        {
          parsing_label = TRUE;
          g_ptr_array_set_size (tmp_lines, 0);
        }
      else if (parsing_label && g_str_has_prefix (line, "\tKERNEL "))
        {
          g_free (kernel_arg);
          kernel_arg = g_strdup (line + strlen ("\tKERNEL "));
        }
      else if (!parsing_label &&
               (g_str_has_prefix (line, "DEFAULT ")))
        {
          saw_default = TRUE;
          /* XXX Searching for patterns in the title is rather brittle,
           *     but this hack is at least noted in the code that builds
           *     the title to hopefully avoid regressions. */
          if (g_str_has_prefix (line, "DEFAULT ostree:") ||  /* old format */
              strstr (line, "(ostree") != NULL)              /* new format */
            {
              regenerate_default = TRUE;
            }
          skip = TRUE;
        }
      
      if (skip)
        {
          g_free (line);
        }
      else
        {
          if (parsing_label)
            {
              g_ptr_array_add (tmp_lines, line);
            }
          else
            {
              g_ptr_array_add (new_lines, line);
            }
        }
      /* Transfer ownership */
      *iter = NULL;
      iter++;
    }

  if (!saw_default)
    regenerate_default = TRUE;

  if (!append_config_from_boostree_loader_entries (self, regenerate_default,
                                               bootversion, new_lines,
                                               cancellable, error))
    goto out;

  new_config_contents = _ostree_sysroot_join_lines (new_lines);
  {
    gs_unref_bytes GBytes *new_config_contents_bytes =
      g_bytes_new_static (new_config_contents,
                          strlen (new_config_contents));

    if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
                                          cancellable, error))
      goto out;
  }
  
  ret = TRUE;
 out:
  g_free (lines); /* Note we freed elements individually */
  return ret;
}
/**
 * ostree_repo_static_delta_execute_offline:
 * @self: Repo
 * @dir: Path to a directory containing static delta data
 * @skip_validation: If %TRUE, assume data integrity
 * @cancellable: Cancellable
 * @error: Error
 *
 * Given a directory representing an already-downloaded static delta
 * on disk, apply it, generating a new commit.  The directory must be
 * named with the form "FROM-TO", where both are checksums, and it
 * must contain a file named "superblock", along with at least one part.
 */
gboolean
ostree_repo_static_delta_execute_offline (OstreeRepo                    *self,
                                          GFile                         *dir,
                                          gboolean                       skip_validation,
                                          GCancellable                  *cancellable,
                                          GError                      **error)
{
  gboolean ret = FALSE;
  guint i, n;
  gs_unref_object GFile *meta_file = g_file_get_child (dir, "superblock");
  gs_unref_variant GVariant *meta = NULL;
  gs_unref_variant GVariant *headers = NULL;
  gs_unref_variant GVariant *fallback = NULL;

  if (!ot_util_variant_map (meta_file, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT),
                            FALSE, &meta, error))
    goto out;

  /* Parsing OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */

  /* Write the to-commit object */
  {
    gs_unref_variant GVariant *to_csum_v = NULL;
    gs_free char *to_checksum = NULL;
    gs_unref_variant GVariant *to_commit = NULL;
    gboolean have_to_commit;

    to_csum_v = g_variant_get_child_value (meta, 3);
    if (!ostree_validate_structureof_csum_v (to_csum_v, error))
      goto out;
    to_checksum = ostree_checksum_from_bytes_v (to_csum_v);

    if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT, to_checksum,
                                 &have_to_commit, cancellable, error))
      goto out;
    
    if (!have_to_commit)
      {
        to_commit = g_variant_get_child_value (meta, 4);
        if (!ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_COMMIT,
                                         to_checksum, to_commit, NULL,
                                         cancellable, error))
          goto out;
      }
  }

  fallback = g_variant_get_child_value (meta, 7);
  if (g_variant_n_children (fallback) > 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Cannot execute delta offline: contains nonempty http fallback entries");
      goto out;
    }

  headers = g_variant_get_child_value (meta, 6);
  n = g_variant_n_children (headers);
  for (i = 0; i < n; i++)
    {
      guint64 size;
      guint64 usize;
      const guchar *csum;
      gboolean have_all;
      gs_unref_variant GVariant *header = NULL;
      gs_unref_variant GVariant *csum_v = NULL;
      gs_unref_variant GVariant *objects = NULL;
      gs_unref_object GFile *part_path = NULL;
      gs_unref_object GInputStream *raw_in = NULL;
      gs_unref_object GInputStream *in = NULL;

      header = g_variant_get_child_value (headers, i);
      g_variant_get (header, "(@aytt@ay)", &csum_v, &size, &usize, &objects);

      if (!_ostree_repo_static_delta_part_have_all_objects (self, objects, &have_all,
                                                            cancellable, error))
        goto out;

      /* If we already have these objects, don't bother executing the
       * static delta.
       */
      if (have_all)
        continue;

      csum = ostree_checksum_bytes_peek_validate (csum_v, error);
      if (!csum)
        goto out;

      part_path = ot_gfile_resolve_path_printf (dir, "%u", i);

      in = (GInputStream*)g_file_read (part_path, cancellable, error);
      if (!in)
        goto out;

      if (!skip_validation)
        {
          gs_free char *expected_checksum = ostree_checksum_from_bytes (csum);
          if (!_ostree_static_delta_part_validate (self, part_path, i,
                                                   expected_checksum,
                                                   cancellable, error))
            goto out;
        }

      {
        GMappedFile *mfile = gs_file_map_noatime (part_path, cancellable, error);
        gs_unref_bytes GBytes *bytes = NULL;

        if (!mfile)
          goto out;

        bytes = g_mapped_file_get_bytes (mfile);
        g_mapped_file_unref (mfile);
        
        if (!_ostree_static_delta_part_execute (self, objects, bytes,
                                                cancellable, error))
          {
            g_prefix_error (error, "executing delta part %i: ", i);
            goto out;
          }
      }
    }

  ret = TRUE;
 out:
  return ret;
}