Пример #1
0
/**
 * ot_gfile_replace_contents_fsync:
 * 
 * Like g_file_replace_contents(), except always uses fdatasync().
 */
gboolean
ot_gfile_replace_contents_fsync (GFile          *path,
                                 GBytes         *contents,
                                 GCancellable   *cancellable,
                                 GError        **error)
{
  gboolean ret = FALSE;
  int parent_dfd;
  const char *target_basename = gs_file_get_basename_cached (path);
  g_autoptr(GFile) parent = NULL;

  parent = g_file_get_parent (path);

  if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (parent), TRUE,
                       &parent_dfd, error))
    goto out;

  if (!ot_file_replace_contents_at (parent_dfd, target_basename,
                                    contents, TRUE,
                                    cancellable, error))
    goto out;

  ret = TRUE;
 out:
  if (parent_dfd != -1)
    (void) close (parent_dfd);
  return ret;
}
Пример #2
0
/**
 * ot_util_ensure_directory_and_fsync:
 * @dir: Path to a directory
 * @cancellable: Cancellable
 * @error: Error
 *
 * Create @dir (and all intermediate parent directories), ensuring
 * that all entries are on disk.
 */
gboolean
ot_util_ensure_directory_and_fsync (GFile         *dir,
                                    GCancellable  *cancellable,
                                    GError       **error)
{
  gboolean ret = FALSE;
  int parentfd = -1;
  const char *basename = gs_file_get_basename_cached (dir);
  g_autoptr(GFile) parent = g_file_get_parent (dir);
  
 again:
  parentfd = open (gs_file_get_path_cached (parent),
                   O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC);
  if (parentfd == -1)
    {
      if (errno == ENOENT)
        {
          if (!ot_util_ensure_directory_and_fsync (parent, cancellable, error))
            goto out;
          goto again;
        }
      else
        {
          int errsv = errno;
          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
                       "opendir: %s", g_strerror (errsv));
          goto out;
        }
    }
  
  if (mkdirat (parentfd, basename, 0777) == -1)
    {
      if (errno == EEXIST)
        {
          ;
        }
      else
        {
          int errsv = errno;
          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
                       "mkdirat: %s", g_strerror (errsv));
          goto out;
        }
    }

  if (fsync (parentfd) == -1)
    {
      int errsv = errno;
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
                   "fsync: %s", g_strerror (errsv));
      goto out;
    }

  ret = TRUE;
 out:
  if (parentfd != -1)
    (void) close (parentfd);
  return ret;
}
static gboolean
relabel_recursively (OstreeSePolicy *sepolicy,
                     GFile          *dir,
                     GFileInfo      *dir_info,
                     GPtrArray      *path_parts,
                     GCancellable   *cancellable,
                     GError        **error)
{
  gboolean ret = FALSE;
  g_autoptr(GFileEnumerator) direnum = NULL;

  if (!relabel_one_path (sepolicy, dir, dir_info, path_parts,
                         cancellable, error))
    goto out;

  direnum = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable, error);
  if (!direnum)
    goto out;
  
  while (TRUE)
    {
      GFileInfo *file_info;
      GFile *child;
      GFileType ftype;

      if (!gs_file_enumerator_iterate (direnum, &file_info, &child,
                                       cancellable, error))
        goto out;
      if (file_info == NULL)
        break;

      g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (child));

      ftype = g_file_info_get_file_type (file_info);
      if (ftype == G_FILE_TYPE_DIRECTORY)
        {
          if (!relabel_recursively (sepolicy, child, file_info, path_parts,
                                    cancellable, error))
            goto out;
        }
      else
        {
          if (!relabel_one_path (sepolicy, child, file_info, path_parts,
                                 cancellable, error))
            goto out;
        }

      g_ptr_array_remove_index (path_parts, path_parts->len - 1);
    }

  ret = TRUE;
 out:
  return ret;
}
Пример #4
0
static gboolean
move_to_dir (GFile        *src,
             GFile        *dest_dir,
             GCancellable *cancellable,
             GError      **error)
{
    gs_unref_object GFile *dest =
        g_file_get_child (dest_dir, gs_file_get_basename_cached (src));

    return gs_file_rename (src, dest, cancellable, error);
}
Пример #5
0
/**
 * ot_gfile_atomic_symlink_swap:
 * @path: Replace the contents of this symbolic link
 * @target: New symbolic link target
 * @cancellable:
 * @error
 *
 * Create a new temporary symbolic link, then use the Unix rename()
 * function to atomically replace @path with the new symbolic link.
 * Do not use this function inside directories such as /tmp as it uses
 * a predicatable file name.
 */
gboolean
ot_gfile_atomic_symlink_swap (GFile          *path,
                              const char     *target,
                              GCancellable   *cancellable,
                              GError        **error)
{
  gboolean ret = FALSE;
  g_autoptr(GFile) parent = g_file_get_parent (path);
  g_autofree char *tmpname = g_strconcat (gs_file_get_basename_cached (path), ".tmp", NULL);
  g_autoptr(GFile) tmppath = g_file_get_child (parent, tmpname);
  int parent_dfd = -1;

  if (!ot_gfile_ensure_unlinked (tmppath, cancellable, error))
    goto out;
  
  if (!g_file_make_symbolic_link (tmppath, target, cancellable, error))
    goto out;

  if (!gs_file_open_dir_fd (parent, &parent_dfd, cancellable, error))
    goto out;

  /* Ensure the link has hit disk */
  if (fsync (parent_dfd) != 0)
    {
      gs_set_error_from_errno (error, errno);
      goto out;
    }

  if (!gs_file_rename (tmppath, path, cancellable, error))
    goto out;

  /* And sync again for good measure */
  if (fsync (parent_dfd) != 0)
    {
      gs_set_error_from_errno (error, errno);
      goto out;
    }

  ret = TRUE;
 out:
  if (parent_dfd != -1) (void) close (parent_dfd);
  return ret;
}
Пример #6
0
static gboolean
do_kernel_prep (GFile         *yumroot,
                JsonObject    *treefile,
                GCancellable  *cancellable,
                GError       **error)
{
    gboolean ret = FALSE;
    gs_unref_object GFile *bootdir =
        g_file_get_child (yumroot, "boot");
    gs_unref_object GFile *kernel_path = NULL;
    gs_unref_object GFile *initramfs_path = NULL;
    const char *boot_checksum_str = NULL;
    GChecksum *boot_checksum = NULL;
    g_autofree char *kver = NULL;

    if (!find_kernel_and_initramfs_in_bootdir (bootdir, &kernel_path,
            &initramfs_path,
            cancellable, error))
        goto out;

    if (kernel_path == NULL)
    {
        gs_unref_object GFile *mod_dir = g_file_resolve_relative_path (yumroot, "usr/lib/modules");
        gs_unref_object GFile *modversion_dir = NULL;

        if (!find_ensure_one_subdirectory (mod_dir, &modversion_dir, cancellable, error))
            goto out;

        if (modversion_dir)
        {
            kver = g_file_get_basename (modversion_dir);
            if (!find_kernel_and_initramfs_in_bootdir (modversion_dir, &kernel_path,
                    &initramfs_path,
                    cancellable, error))
                goto out;
        }
    }

    if (kernel_path == NULL)
    {
        g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                     "Unable to find kernel (vmlinuz) in /boot or /usr/lib/modules");
        goto out;
    }

    if (initramfs_path)
    {
        g_print ("Removing RPM-generated '%s'\n",
                 gs_file_get_path_cached (initramfs_path));
        if (!gs_shutil_rm_rf (initramfs_path, cancellable, error))
            goto out;
    }

    if (!kver)
    {
        const char *kname = gs_file_get_basename_cached (kernel_path);
        const char *kver_p;

        kver_p = strchr (kname, '-');
        g_assert (kver_p);
        kver = g_strdup (kver_p + 1);
    }

    /* OSTree needs to own this */
    {
        gs_unref_object GFile *loaderdir = g_file_get_child (bootdir, "loader");
        if (!gs_shutil_rm_rf (loaderdir, cancellable, error))
            goto out;
    }

    {
        char *child_argv[] = { "depmod", (char*)kver, NULL };
        if (!run_sync_in_root (yumroot, "depmod", child_argv, error))
            goto out;
    }

    /* Ensure the /etc/machine-id file is present and empty. Apparently systemd
       doesn't work when the file is missing (as of systemd-219-9.fc22) but it is
       correctly populated if the file is there.  */
    g_print ("Creating empty machine-id\n");
    {
        const char *hardcoded_machine_id = "";
        gs_unref_object GFile *machineid_path =
            g_file_resolve_relative_path (yumroot, "etc/machine-id");
        if (!g_file_replace_contents (machineid_path, hardcoded_machine_id,
                                      strlen (hardcoded_machine_id),
                                      NULL, FALSE, 0, NULL,
                                      cancellable, error))
            goto out;
    }

    {
        gboolean reproducible;
        gs_unref_ptrarray GPtrArray *dracut_argv = g_ptr_array_new ();

        if (!dracut_supports_reproducible (yumroot, &reproducible, cancellable, error))
            goto out;

        g_ptr_array_add (dracut_argv, "dracut");
        g_ptr_array_add (dracut_argv, "-v");
        if (reproducible)
        {
            g_ptr_array_add (dracut_argv, "--reproducible");
            g_ptr_array_add (dracut_argv, "--gzip");
        }
        g_ptr_array_add (dracut_argv, "--tmpdir=/tmp");
        g_ptr_array_add (dracut_argv, "-f");
        g_ptr_array_add (dracut_argv, "/var/tmp/initramfs.img");
        g_ptr_array_add (dracut_argv, (char*)kver);

        if (json_object_has_member (treefile, "initramfs-args"))
        {
            guint i, len;
            JsonArray *initramfs_args;

            initramfs_args = json_object_get_array_member (treefile, "initramfs-args");
            len = json_array_get_length (initramfs_args);

            for (i = 0; i < len; i++)
            {
                const char *arg = _rpmostree_jsonutil_array_require_string_element (initramfs_args, i, error);
                if (!arg)
                    goto out;
                g_ptr_array_add (dracut_argv, (char*)arg);
            }
        }

        g_ptr_array_add (dracut_argv, NULL);

        if (!run_sync_in_root (yumroot, "dracut", (char**)dracut_argv->pdata, error))
            goto out;
    }

    initramfs_path = g_file_resolve_relative_path (yumroot, "var/tmp/initramfs.img");
    if (!g_file_query_exists (initramfs_path, NULL))
    {
        g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                     "Dracut failed to generate '%s'",
                     gs_file_get_path_cached (initramfs_path));
        goto out;
    }

    {
        gs_free char *initramfs_name = g_strconcat ("initramfs-", kver, ".img", NULL);
        gs_unref_object GFile *initramfs_dest =
            g_file_get_child (bootdir, initramfs_name);

        if (!gs_file_rename (initramfs_path, initramfs_dest,
                             cancellable, error))
            goto out;

        /* Transfer ownership */
        g_object_unref (initramfs_path);
        initramfs_path = initramfs_dest;
        initramfs_dest = NULL;
    }

    boot_checksum = g_checksum_new (G_CHECKSUM_SHA256);
    if (!_rpmostree_util_update_checksum_from_file (boot_checksum, kernel_path,
            cancellable, error))
        goto out;
    if (!_rpmostree_util_update_checksum_from_file (boot_checksum, initramfs_path,
            cancellable, error))
        goto out;

    boot_checksum_str = g_checksum_get_string (boot_checksum);

    {
        gs_free char *new_kernel_name =
            g_strconcat (gs_file_get_basename_cached (kernel_path), "-",
                         boot_checksum_str, NULL);
        gs_unref_object GFile *new_kernel_path =
            g_file_get_child (bootdir, new_kernel_name);
        gs_free char *new_initramfs_name =
            g_strconcat (gs_file_get_basename_cached (initramfs_path), "-",
                         boot_checksum_str, NULL);
        gs_unref_object GFile *new_initramfs_path =
            g_file_get_child (bootdir, new_initramfs_name);

        if (!gs_file_rename (kernel_path, new_kernel_path,
                             cancellable, error))
            goto out;
        if (!gs_file_rename (initramfs_path, new_initramfs_path,
                             cancellable, error))
            goto out;
    }

    ret = TRUE;
out:
    if (boot_checksum) g_checksum_free (boot_checksum);
    return ret;
}
Пример #7
0
gboolean
rpmostree_treefile_postprocessing (GFile         *yumroot,
                                   GFile         *context_directory,
                                   GBytes        *serialized_treefile,
                                   JsonObject    *treefile,
                                   GCancellable  *cancellable,
                                   GError       **error)
{
    gboolean ret = FALSE;
    guint i, len;
    JsonArray *units = NULL;
    JsonArray *remove = NULL;
    const char *default_target = NULL;
    const char *postprocess_script = NULL;

    if (json_object_has_member (treefile, "units"))
        units = json_object_get_array_member (treefile, "units");

    if (units)
        len = json_array_get_length (units);
    else
        len = 0;

    {
        gs_unref_object GFile *multiuser_wants_dir =
            g_file_resolve_relative_path (yumroot, "etc/systemd/system/multi-user.target.wants");

        if (!gs_file_ensure_directory (multiuser_wants_dir, TRUE, cancellable, error))
            goto out;

        for (i = 0; i < len; i++)
        {
            const char *unitname = _rpmostree_jsonutil_array_require_string_element (units, i, error);
            gs_unref_object GFile *unit_link_target = NULL;
            gs_free char *symlink_target = NULL;

            if (!unitname)
                goto out;

            symlink_target = g_strconcat ("/usr/lib/systemd/system/", unitname, NULL);
            unit_link_target = g_file_get_child (multiuser_wants_dir, unitname);

            if (g_file_query_file_type (unit_link_target, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_SYMBOLIC_LINK)
                continue;

            g_print ("Adding %s to multi-user.target.wants\n", unitname);

            if (!g_file_make_symbolic_link (unit_link_target, symlink_target,
                                            cancellable, error))
                goto out;
        }
    }

    {
        gs_unref_object GFile *target_treefile_dir_path =
            g_file_resolve_relative_path (yumroot, "usr/share/rpm-ostree");
        gs_unref_object GFile *target_treefile_path =
            g_file_get_child (target_treefile_dir_path, "treefile.json");
        const guint8 *buf;
        gsize len;

        if (!gs_file_ensure_directory (target_treefile_dir_path, TRUE,
                                       cancellable, error))
            goto out;

        g_print ("Writing '%s'\n", gs_file_get_path_cached (target_treefile_path));
        buf = g_bytes_get_data (serialized_treefile, &len);

        if (!g_file_replace_contents (target_treefile_path, (char*)buf, len,
                                      NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
                                      NULL, cancellable, error))
            goto out;
    }

    if (!_rpmostree_jsonutil_object_get_optional_string_member (treefile, "default_target",
            &default_target, error))
        goto out;

    if (default_target != NULL)
    {
        gs_unref_object GFile *default_target_path =
            g_file_resolve_relative_path (yumroot, "etc/systemd/system/default.target");
        gs_free char *dest_default_target_path =
            g_strconcat ("/usr/lib/systemd/system/", default_target, NULL);

        (void) gs_file_unlink (default_target_path, NULL, NULL);

        if (!g_file_make_symbolic_link (default_target_path, dest_default_target_path,
                                        cancellable, error))
            goto out;
    }

    if (json_object_has_member (treefile, "remove-files"))
    {
        remove = json_object_get_array_member (treefile, "remove-files");
        len = json_array_get_length (remove);
    }
    else
        len = 0;

    for (i = 0; i < len; i++)
    {
        const char *val = _rpmostree_jsonutil_array_require_string_element (remove, i, error);
        gs_unref_object GFile *child = NULL;

        if (!val)
            return FALSE;
        if (g_path_is_absolute (val))
        {
            g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                         "'remove' elements must be relative");
            goto out;
        }

        child = g_file_resolve_relative_path (yumroot, val);

        if (g_file_query_exists (child, NULL))
        {
            g_print ("Removing '%s'\n", val);
            if (!gs_shutil_rm_rf (child, cancellable, error))
                goto out;
        }
        else
        {
            g_printerr ("warning: Targeted path for remove-files does not exist: %s\n",
                        gs_file_get_path_cached (child));
        }
    }

    if (json_object_has_member (treefile, "remove-from-packages"))
    {
        g_autoptr(RpmOstreeRefSack) refsack = NULL;
        _cleanup_hypackagelist_ HyPackageList pkglist = NULL;
        guint i;

        remove = json_object_get_array_member (treefile, "remove-from-packages");
        len = json_array_get_length (remove);

        if (!rpmostree_get_pkglist_for_root (AT_FDCWD, gs_file_get_path_cached (yumroot),
                                             &refsack, &pkglist,
                                             cancellable, error))
        {
            g_prefix_error (error, "Reading package set: ");
            goto out;
        }

        for (i = 0; i < len; i++)
        {
            JsonArray *elt = json_array_get_array_element (remove, i);
            if (!handle_remove_files_from_package (yumroot, refsack, elt, cancellable, error))
                goto out;
        }
    }

    if (!_rpmostree_jsonutil_object_get_optional_string_member (treefile, "postprocess-script",
            &postprocess_script, error))
        goto out;

    if (postprocess_script)
    {
        const char *yumroot_path = gs_file_get_path_cached (yumroot);
        gs_unref_object GFile *src = g_file_resolve_relative_path (context_directory, postprocess_script);
        const char *bn = gs_file_get_basename_cached (src);
        gs_free char *binpath = g_strconcat ("/usr/bin/rpmostree-postprocess-", bn, NULL);
        gs_free char *destpath = g_strconcat (yumroot_path, binpath, NULL);
        gs_unref_object GFile *dest = g_file_new_for_path (destpath);
        /* Clone all the things */

        if (!g_file_copy (src, dest, 0, cancellable, NULL, NULL, error))
        {
            g_prefix_error (error, "Copying postprocess-script '%s' into target: ", bn);
            goto out;
        }

        g_print ("Executing postprocessing script '%s'\n", bn);

        {
            char *child_argv[] = { binpath, NULL };
            if (!run_sync_in_root (yumroot, binpath, child_argv, error))
            {
                g_prefix_error (error, "While executing postprocessing script '%s': ", bn);
                goto out;
            }
        }

        g_print ("Finished postprocessing script '%s'\n", bn);
    }

    ret = TRUE;
out:
    return ret;
}
Пример #8
0
static gboolean
cleanup_old_deployments (OstreeSysroot       *self,
                         GCancellable        *cancellable,
                         GError             **error)
{
    gboolean ret = FALSE;
    guint32 root_device;
    guint64 root_inode;
    guint i;
    gs_unref_object GFile *active_root = g_file_new_for_path ("/");
    gs_unref_hashtable GHashTable *active_deployment_dirs = NULL;
    gs_unref_hashtable GHashTable *active_boot_checksums = NULL;
    gs_unref_ptrarray GPtrArray *all_deployment_dirs = NULL;
    gs_unref_ptrarray GPtrArray *all_boot_dirs = NULL;

    if (!_ostree_sysroot_get_devino (active_root, &root_device, &root_inode,
                                     cancellable, error))
        goto out;

    active_deployment_dirs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
    active_boot_checksums = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL);

    for (i = 0; i < self->deployments->len; i++)
    {
        OstreeDeployment *deployment = self->deployments->pdata[i];
        GFile *deployment_path = ostree_sysroot_get_deployment_directory (self, deployment);
        char *bootcsum = g_strdup (ostree_deployment_get_bootcsum (deployment));
        /* Transfer ownership */
        g_hash_table_replace (active_deployment_dirs, deployment_path, deployment_path);
        g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum);
    }

    if (!list_all_deployment_directories (self, &all_deployment_dirs,
                                          cancellable, error))
        goto out;

    for (i = 0; i < all_deployment_dirs->len; i++)
    {
        OstreeDeployment *deployment = all_deployment_dirs->pdata[i];
        gs_unref_object GFile *deployment_path = ostree_sysroot_get_deployment_directory (self, deployment);
        gs_unref_object GFile *origin_path = ostree_sysroot_get_deployment_origin_path (deployment_path);
        if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
        {
            guint32 device;
            guint64 inode;

            if (!_ostree_sysroot_get_devino (deployment_path, &device, &inode,
                                             cancellable, error))
                goto out;

            /* This shouldn't happen, because higher levels should
             * disallow having the booted deployment not in the active
             * deployment list, but let's be extra safe. */
            if (device == root_device && inode == root_inode)
                continue;

            if (!gs_shutil_rm_rf (deployment_path, cancellable, error))
                goto out;
            if (!gs_shutil_rm_rf (origin_path, cancellable, error))
                goto out;
        }
    }

    if (!list_all_boot_directories (self, &all_boot_dirs,
                                    cancellable, error))
        goto out;

    for (i = 0; i < all_boot_dirs->len; i++)
    {
        GFile *bootdir = all_boot_dirs->pdata[i];
        gs_free char *osname = NULL;
        gs_free char *bootcsum = NULL;

        if (!parse_bootdir_name (gs_file_get_basename_cached (bootdir),
                                 &osname, &bootcsum))
            g_assert_not_reached ();

        if (g_hash_table_lookup (active_boot_checksums, bootcsum))
            continue;

        if (!gs_shutil_rm_rf (bootdir, cancellable, error))
            goto out;
    }

    ret = TRUE;
out:
    return ret;
}
Пример #9
0
gboolean
_ostree_sysroot_list_deployment_dirs_for_os (GFile               *osdir,
        GPtrArray           *inout_deployments,
        GCancellable        *cancellable,
        GError             **error)
{
    gboolean ret = FALSE;
    const char *osname = gs_file_get_basename_cached (osdir);
    gs_unref_object GFileEnumerator *dir_enum = NULL;
    gs_unref_object GFile *osdeploy_dir = NULL;
    GError *temp_error = NULL;

    osdeploy_dir = g_file_get_child (osdir, "deploy");

    dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO,
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          NULL, &temp_error);
    if (!dir_enum)
    {
        if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
            g_clear_error (&temp_error);
            goto done;
        }
        else
        {
            g_propagate_error (error, temp_error);
            goto out;
        }
    }

    while (TRUE)
    {
        const char *name;
        GFileInfo *file_info = NULL;
        GFile *child = NULL;
        gs_unref_object OstreeDeployment *deployment = NULL;
        gs_free char *csum = NULL;
        gint deployserial;

        if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
                                         cancellable, error))
            goto out;
        if (file_info == NULL)
            break;

        name = g_file_info_get_name (file_info);

        if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
            continue;

        if (!_ostree_sysroot_parse_deploy_path_name (name, &csum, &deployserial, error))
            goto out;

        deployment = ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1);
        g_ptr_array_add (inout_deployments, g_object_ref (deployment));
    }

done:
    ret = TRUE;
out:
    return ret;
}
Пример #10
0
static gboolean
do_kernel_prep (GFile         *yumroot,
                JsonObject    *treefile,
                GCancellable  *cancellable,
                GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GFile *bootdir = 
    g_file_get_child (yumroot, "boot");
  gs_unref_object GFile *kernel_path = NULL;
  gs_unref_object GFile *initramfs_path = NULL;
  const char *boot_checksum_str = NULL;
  GChecksum *boot_checksum = NULL;
  const char *kname;
  const char *kver;

  if (!find_kernel_and_initramfs_in_bootdir (bootdir, &kernel_path,
                                             &initramfs_path,
                                             cancellable, error))
    goto out;

  if (initramfs_path)
    {
      g_print ("Removing RPM-generated '%s'\n",
               gs_file_get_path_cached (initramfs_path));
      if (!gs_shutil_rm_rf (initramfs_path, cancellable, error))
        goto out;
    }

  kname = gs_file_get_basename_cached (kernel_path);
  kver = strchr (kname, '-');
  g_assert (kver);
  kver += 1;

  /* OSTree needs to own this */
  {
    gs_unref_object GFile *loaderdir = g_file_get_child (bootdir, "loader");
    if (!gs_shutil_rm_rf (loaderdir, cancellable, error))
      goto out;
  }

  {
    char *child_argv[] = { "depmod", (char*)kver, NULL };
    if (!run_sync_in_root (yumroot, "/usr/sbin/depmod", child_argv, error))
      goto out;
  }

  /* Copy of code from gnome-continuous; yes, we hardcode
     the machine id for now, because distributing pre-generated
     initramfs images with dracut/systemd at the moment
     effectively requires this.
     http://lists.freedesktop.org/archives/systemd-devel/2013-July/011770.html
  */
  g_print ("Hardcoding machine-id\n");
  {
    const char *hardcoded_machine_id = "45bb3b96146aa94f299b9eb43646eb35\n";
    gs_unref_object GFile *machineid_path =
      g_file_resolve_relative_path (yumroot, "etc/machine-id");
    if (!g_file_replace_contents (machineid_path, hardcoded_machine_id,
                                  strlen (hardcoded_machine_id),
                                  NULL, FALSE, 0, NULL,
                                  cancellable, error))
      goto out;
  }

  {
    gs_unref_ptrarray GPtrArray *dracut_argv = g_ptr_array_new ();

    g_ptr_array_add (dracut_argv, "dracut");
    g_ptr_array_add (dracut_argv, "-v");
    g_ptr_array_add (dracut_argv, "--tmpdir=/tmp");
    g_ptr_array_add (dracut_argv, "-f");
    g_ptr_array_add (dracut_argv, "/var/tmp/initramfs.img");
    g_ptr_array_add (dracut_argv, (char*)kver);

    if (json_object_has_member (treefile, "initramfs-args"))
      {
        guint i, len;
        JsonArray *initramfs_args;

        initramfs_args = json_object_get_array_member (treefile, "initramfs-args");
        len = json_array_get_length (initramfs_args);

        for (i = 0; i < len; i++)
          {
            const char *arg = _rpmostree_jsonutil_array_require_string_element (initramfs_args, i, error);
            if (!arg)
              goto out;
            g_ptr_array_add (dracut_argv, (char*)arg);
          }
      }

    g_ptr_array_add (dracut_argv, NULL);

    if (!run_sync_in_root (yumroot, "/usr/sbin/dracut", (char**)dracut_argv->pdata, error))
      goto out;
  }

  initramfs_path = g_file_resolve_relative_path (yumroot, "var/tmp/initramfs.img");
  if (!g_file_query_exists (initramfs_path, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Dracut failed to generate '%s'",
                   gs_file_get_path_cached (initramfs_path));
      goto out;
    }

  {
    gs_free char *initramfs_name = g_strconcat ("initramfs-", kver, ".img", NULL);
    gs_unref_object GFile *initramfs_dest =
      g_file_get_child (bootdir, initramfs_name);

    if (!gs_file_rename (initramfs_path, initramfs_dest,
                         cancellable, error))
      goto out;

    /* Transfer ownership */
    g_object_unref (initramfs_path);
    initramfs_path = initramfs_dest;
    initramfs_dest = NULL;
  }

  boot_checksum = g_checksum_new (G_CHECKSUM_SHA256);
  if (!_rpmostree_util_update_checksum_from_file (boot_checksum, kernel_path,
                                                  cancellable, error))
    goto out;
  if (!_rpmostree_util_update_checksum_from_file (boot_checksum, initramfs_path,
                                                  cancellable, error))
    goto out;

  boot_checksum_str = g_checksum_get_string (boot_checksum);
  
  {
    gs_free char *new_kernel_name =
      g_strconcat (gs_file_get_basename_cached (kernel_path), "-",
                   boot_checksum_str, NULL);
    gs_unref_object GFile *new_kernel_path =
      g_file_get_child (bootdir, new_kernel_name);
    gs_free char *new_initramfs_name =
      g_strconcat (gs_file_get_basename_cached (initramfs_path), "-",
                   boot_checksum_str, NULL);
    gs_unref_object GFile *new_initramfs_path =
      g_file_get_child (bootdir, new_initramfs_name);

    if (!gs_file_rename (kernel_path, new_kernel_path,
                         cancellable, error))
      goto out;
    if (!gs_file_rename (initramfs_path, new_initramfs_path,
                         cancellable, error))
      goto out;
  }

  ret = TRUE;
 out:
  if (boot_checksum) g_checksum_free (boot_checksum);
  return ret;
}
/**
 * ostree_repo_list_static_delta_names:
 * @self: Repo
 * @out_deltas: (out) (element-type utf8): String name of deltas (checksum-checksum.delta)
 * @cancellable: Cancellable
 * @error: Error
 *
 * This function synchronously enumerates all static deltas in the
 * repository, returning its result in @out_deltas.
 */ 
gboolean
ostree_repo_list_static_delta_names (OstreeRepo                  *self,
                                     GPtrArray                  **out_deltas,
                                     GCancellable                *cancellable,
                                     GError                     **error)
{
  gboolean ret = FALSE;
  gs_unref_ptrarray GPtrArray *ret_deltas = NULL;
  gs_unref_object GFileEnumerator *dir_enum = NULL;

  ret_deltas = g_ptr_array_new_with_free_func (g_free);

  if (g_file_query_exists (self->deltas_dir, NULL))
    {
      dir_enum = g_file_enumerate_children (self->deltas_dir, OSTREE_GIO_FAST_QUERYINFO,
                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                            NULL, error);
      if (!dir_enum)
        goto out;

      while (TRUE)
        {
          gs_unref_object GFileEnumerator *dir_enum2 = NULL;
          GFileInfo *file_info;
          GFile *child;

          if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
                                           NULL, error))
            goto out;
          if (file_info == NULL)
            break;

          if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
            continue;


          dir_enum2 = g_file_enumerate_children (child, OSTREE_GIO_FAST_QUERYINFO,
                                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                 NULL, error);
          if (!dir_enum2)
            goto out;

          while (TRUE)
            {
              GFileInfo *file_info2;
              GFile *child2;
              const char *name1;
              const char *name2;

              if (!gs_file_enumerator_iterate (dir_enum2, &file_info2, &child2,
                                               NULL, error))
                goto out;
              if (file_info2 == NULL)
                break;

              if (g_file_info_get_file_type (file_info2) != G_FILE_TYPE_DIRECTORY)
                continue;

              name1 = gs_file_get_basename_cached (child);
              name2 = gs_file_get_basename_cached (child2);

              {
                gs_unref_object GFile *meta_path = g_file_get_child (child2, "superblock");

                if (g_file_query_exists (meta_path, NULL))
                  {
                    gs_free char *buf = g_strconcat (name1, name2, NULL);
                    GString *out = g_string_new ("");
                    char checksum[65];
                    guchar csum[32];
                    const char *dash = strchr (buf, '-');

                    ostree_checksum_b64_inplace_to_bytes (buf, csum);
                    ostree_checksum_inplace_from_bytes (csum, checksum);
                    g_string_append (out, checksum);
                    if (dash)
                      {
                        g_string_append_c (out, '-');
                        ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
                        ostree_checksum_inplace_from_bytes (csum, checksum);
                        g_string_append (out, checksum);
                      }

                    g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
                  }
              }
            }
        }
    }

  ret = TRUE;
  gs_transfer_out_value (out_deltas, &ret_deltas);
 out:
  return ret;
}