Ejemplo n.º 1
0
/**
 * rpmostree_prepare_rootfs_for_commit:
 *
 * Walk over the root filesystem and perform some core conversions
 * from RPM conventions to OSTree conventions.  For example:
 *
 *  * Move /etc to /usr/etc
 *  * Checksum the kernel in /boot
 *  * Migrate content in /var to systemd-tmpfiles
 */
gboolean
rpmostree_prepare_rootfs_for_commit (GFile         *rootfs,
                                     JsonObject    *treefile,
                                     GCancellable  *cancellable,
                                     GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GFile *rootfs_tmp = NULL;
  gs_free char *rootfs_tmp_path = NULL;

  rootfs_tmp_path = g_strconcat (gs_file_get_path_cached (rootfs), ".tmp", NULL);
  rootfs_tmp = g_file_new_for_path (rootfs_tmp_path);

  if (!gs_shutil_rm_rf (rootfs_tmp, cancellable, error))
    goto out;

  if (!create_rootfs_from_yumroot_content (rootfs_tmp, rootfs, treefile,
                                           cancellable, error))
    goto out;

  if (!gs_shutil_rm_rf (rootfs, cancellable, error))
    goto out;
  if (!gs_file_rename (rootfs_tmp, rootfs, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
/* Prepare a root filesystem, taking mainly the contents of /usr from yumroot */
static gboolean
create_rootfs_from_yumroot_content (GFile         *targetroot,
                                    GFile         *yumroot,
                                    JsonObject    *treefile,
                                    GCancellable  *cancellable,
                                    GError       **error)
{
    gboolean ret = FALSE;
    glnx_fd_close int src_rootfs_fd = -1;
    glnx_fd_close int target_root_dfd = -1;
    gs_unref_object GFile *kernel_path = NULL;
    gs_unref_object GFile *initramfs_path = NULL;
    gs_unref_hashtable GHashTable *preserve_groups_set = NULL;
    gboolean container = FALSE;

    if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (yumroot), TRUE,
                         &src_rootfs_fd, error))
        goto out;

    if (!_rpmostree_jsonutil_object_get_optional_boolean_member (treefile,
            "container",
            &container,
            error))
        goto out;

    g_print ("Preparing kernel\n");
    if (!container && !do_kernel_prep (yumroot, treefile, cancellable, error))
        goto out;

    g_print ("Initializing rootfs\n");
    if (!init_rootfs (targetroot, cancellable, error))
        goto out;

    if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (targetroot), TRUE, &target_root_dfd, error))
        goto out;

    g_print ("Migrating /etc/passwd to /usr/lib/\n");
    if (!rpmostree_passwd_migrate_except_root (yumroot, RPM_OSTREE_PASSWD_MIGRATE_PASSWD, NULL,
            cancellable, error))
        goto out;

    if (json_object_has_member (treefile, "etc-group-members"))
    {
        JsonArray *etc_group_members = json_object_get_array_member (treefile, "etc-group-members");
        preserve_groups_set = _rpmostree_jsonutil_jsarray_strings_to_set (etc_group_members);
    }

    g_print ("Migrating /etc/group to /usr/lib/\n");
    if (!rpmostree_passwd_migrate_except_root (yumroot, RPM_OSTREE_PASSWD_MIGRATE_GROUP,
            preserve_groups_set,
            cancellable, error))
        goto out;

    /* NSS configuration to look at the new files */
    {
        gs_unref_object GFile *yumroot_etc =
            g_file_resolve_relative_path (yumroot, "etc");

        if (!replace_nsswitch (yumroot_etc, cancellable, error))
            goto out;
    }

    /* We take /usr from the yum content */
    g_print ("Moving /usr to target\n");
    {
        gs_unref_object GFile *usr = g_file_get_child (yumroot, "usr");
        if (!move_to_dir (usr, targetroot, cancellable, error))
            goto out;
    }

    /* Except /usr/local -> ../var/usrlocal */
    g_print ("Linking /usr/local -> ../var/usrlocal\n");
    {
        gs_unref_object GFile *target_usrlocal =
            g_file_resolve_relative_path (targetroot, "usr/local");

        if (!gs_shutil_rm_rf (target_usrlocal, cancellable, error))
            goto out;

        if (!g_file_make_symbolic_link (target_usrlocal, "../var/usrlocal",
                                        cancellable, error))
            goto out;
    }

    /* And now we take the contents of /etc and put them in /usr/etc */
    g_print ("Moving /etc to /usr/etc\n");
    {
        gs_unref_object GFile *yumroot_etc =
            g_file_get_child (yumroot, "etc");
        gs_unref_object GFile *target_usretc =
            g_file_resolve_relative_path (targetroot, "usr/etc");

        if (!gs_file_rename (yumroot_etc, target_usretc,
                             cancellable, error))
            goto out;
    }

    if (!migrate_rpm_and_yumdb (targetroot, yumroot, cancellable, error))
        goto out;

    if (!convert_var_to_tmpfiles_d (src_rootfs_fd, target_root_dfd, cancellable, error))
        goto out;

    /* Move boot, but rename the kernel/initramfs to have a checksum */
    if (!container)
    {
        gs_unref_object GFile *yumroot_boot =
            g_file_get_child (yumroot, "boot");
        gs_unref_object GFile *target_boot =
            g_file_get_child (targetroot, "boot");
        gs_unref_object GFile *target_usrlib =
            g_file_resolve_relative_path (targetroot, "usr/lib");
        gs_unref_object GFile *target_usrlib_ostree_boot =
            g_file_resolve_relative_path (target_usrlib, "ostree-boot");
        RpmOstreePostprocessBootLocation boot_location =
            RPMOSTREE_POSTPROCESS_BOOT_LOCATION_BOTH;
        const char *boot_location_str = NULL;

        g_print ("Moving /boot\n");

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

        if (boot_location_str != NULL)
        {
            if (strcmp (boot_location_str, "legacy") == 0)
                boot_location = RPMOSTREE_POSTPROCESS_BOOT_LOCATION_LEGACY;
            else if (strcmp (boot_location_str, "both") == 0)
                boot_location = RPMOSTREE_POSTPROCESS_BOOT_LOCATION_BOTH;
            else if (strcmp (boot_location_str, "new") == 0)
                boot_location = RPMOSTREE_POSTPROCESS_BOOT_LOCATION_NEW;
            else
            {
                g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                             "Invalid boot location '%s'", boot_location_str);
                goto out;
            }
        }

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

        switch (boot_location)
        {
        case RPMOSTREE_POSTPROCESS_BOOT_LOCATION_LEGACY:
        {
            g_print ("Using boot location: legacy\n");
            if (!gs_file_rename (yumroot_boot, target_boot, cancellable, error))
                goto out;
        }
        break;
        case RPMOSTREE_POSTPROCESS_BOOT_LOCATION_BOTH:
        {
            g_print ("Using boot location: both\n");
            if (!gs_file_rename (yumroot_boot, target_boot, cancellable, error))
                goto out;
            /* Hardlink the existing content, only a little ugly as
             * we'll end up sha256'ing it twice, but oh well. */
            if (!gs_shutil_cp_al_or_fallback (target_boot, target_usrlib_ostree_boot, cancellable, error))
                goto out;
        }
        break;
        case RPMOSTREE_POSTPROCESS_BOOT_LOCATION_NEW:
        {
            g_print ("Using boot location: new\n");
            if (!gs_file_rename (yumroot_boot, target_usrlib_ostree_boot, cancellable, error))
                goto out;
        }
        break;
        }
    }

    /* Also carry along toplevel compat links */
    g_print ("Copying toplevel compat symlinks\n");
    {
        guint i;
        const char *toplevel_links[] = { "lib", "lib64", "lib32",
                                         "bin", "sbin"
                                       };
        for (i = 0; i < G_N_ELEMENTS (toplevel_links); i++)
        {
            gs_unref_object GFile *srcpath =
                g_file_get_child (yumroot, toplevel_links[i]);

            if (g_file_query_file_type (srcpath, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_SYMBOLIC_LINK)
            {
                if (!move_to_dir (srcpath, targetroot, cancellable, error))
                    goto out;
            }
        }
    }

    g_print ("Adding tmpfiles-ostree-integration.conf\n");
    {
        gs_unref_object GFile *src_pkglibdir = g_file_new_for_path (PKGLIBDIR);
        gs_unref_object GFile *src_tmpfilesd =
            g_file_get_child (src_pkglibdir, "tmpfiles-ostree-integration.conf");
        gs_unref_object GFile *target_tmpfilesd =
            g_file_resolve_relative_path (targetroot, "usr/lib/tmpfiles.d/tmpfiles-ostree-integration.conf");
        gs_unref_object GFile *target_tmpfilesd_parent = g_file_get_parent (target_tmpfilesd);

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

        if (!g_file_copy (src_tmpfilesd, target_tmpfilesd, 0,
                          cancellable, NULL, NULL, error))
            goto out;
    }

    ret = TRUE;
out:
    return ret;
}
Ejemplo n.º 5
0
static gboolean
migrate_rpm_and_yumdb (GFile          *targetroot,
                       GFile          *yumroot,
                       GCancellable   *cancellable,
                       GError        **error)

{
    gboolean ret = FALSE;
    gs_unref_object GFile *usrbin_rpm =
        g_file_resolve_relative_path (targetroot, "usr/bin/rpm");
    gs_unref_object GFile *legacyrpm_path =
        g_file_resolve_relative_path (yumroot, "var/lib/rpm");
    gs_unref_object GFile *newrpm_path =
        g_file_resolve_relative_path (targetroot, "usr/share/rpm");
    gs_unref_object GFile *src_yum_rpmdb_indexes =
        g_file_resolve_relative_path (yumroot, "var/lib/yum");
    gs_unref_object GFile *target_yum_rpmdb_indexes =
        g_file_resolve_relative_path (targetroot, "usr/share/yumdb");
    gs_unref_object GFile *yumroot_yumlib =
        g_file_get_child (yumroot, "var/lib/yum");
    gs_unref_object GFileEnumerator *direnum = NULL;

    direnum = g_file_enumerate_children (legacyrpm_path, "standard::name",
                                         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                         cancellable, error);
    if (!direnum)
        goto out;

    while (TRUE)
    {
        const char *name;
        GFileInfo *file_info;
        GFile *child;

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

        name = g_file_info_get_name (file_info);

        if (g_str_has_prefix (name, "__db.") ||
                strcmp (name, ".dbenv.lock") == 0 ||
                strcmp (name, ".rpm.lock") == 0)
        {
            if (!gs_file_unlink (child, cancellable, error))
                goto out;
        }
    }

    (void) g_file_enumerator_close (direnum, cancellable, error);

    g_print ("Placing RPM db in /usr/share/rpm\n");
    if (!gs_file_rename (legacyrpm_path, newrpm_path, cancellable, error))
        goto out;

    /* Remove /var/lib/yum; we don't want it here. */
    if (!gs_shutil_rm_rf (yumroot_yumlib, cancellable, error))
        goto out;

    ret = TRUE;
out:
    return ret;
}
Ejemplo n.º 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;
}
Ejemplo n.º 7
0
static gboolean
migrate_rpm_and_yumdb (GFile          *targetroot,
                       GFile          *yumroot,
                       GCancellable   *cancellable,
                       GError        **error)

{
  gboolean ret = FALSE;
  gs_unref_object GFile *usrbin_rpm =
    g_file_resolve_relative_path (targetroot, "usr/bin/rpm");
  gs_unref_object GFile *legacyrpm_path =
    g_file_resolve_relative_path (yumroot, "var/lib/rpm");
  gs_unref_object GFile *newrpm_path =
    g_file_resolve_relative_path (targetroot, "usr/share/rpm");
  gs_unref_object GFile *src_yum_rpmdb_indexes =
    g_file_resolve_relative_path (yumroot, "var/lib/yum");
  gs_unref_object GFile *target_yum_rpmdb_indexes =
    g_file_resolve_relative_path (targetroot, "usr/share/yumdb");
  gs_unref_object GFile *yumroot_yumlib =
    g_file_get_child (yumroot, "var/lib/yum");
  gs_unref_object GFileEnumerator *direnum = NULL;

  direnum = g_file_enumerate_children (legacyrpm_path, "standard::name",
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable, error);
  if (!direnum)
    goto out;

  while (TRUE)
    {
      const char *name;
      GFileInfo *file_info;
      GFile *child;

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

      name = g_file_info_get_name (file_info);

      if (g_str_has_prefix (name, "__db.") ||
          strcmp (name, ".dbenv.lock") == 0 ||
          strcmp (name, ".rpm.lock") == 0)
        {
          if (!gs_file_unlink (child, cancellable, error))
            goto out;
        }
    }

  (void) g_file_enumerator_close (direnum, cancellable, error);
    
  g_print ("Placing RPM db in /usr/share/rpm\n");
  if (!gs_file_rename (legacyrpm_path, newrpm_path, cancellable, error))
    goto out;
    
  /* Move the yum database to usr/share/yumdb; disabled for now due
   * to bad conflict with OSTree's current
   * one-http-request-per-file.
   */
#if 0
  if (g_file_query_exists (src_yum_rpmdb_indexes, NULL))
    {
      g_print ("Moving %s to %s\n", gs_file_get_path_cached (src_yum_rpmdb_indexes),
               gs_file_get_path_cached (target_yum_rpmdb_indexes));
      if (!gs_file_rename (src_yum_rpmdb_indexes, target_yum_rpmdb_indexes,
                           cancellable, error))
        goto out;
        
      if (!clean_yumdb_extraneous_files (target_yum_rpmdb_indexes, cancellable, error))
        goto out;
    }
#endif

  /* Remove /var/lib/yum; we don't want it here. */
  if (!gs_shutil_rm_rf (yumroot_yumlib, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
0
static gboolean
linkcopy_internal_attempt (GFile          *src,
                           GFile          *dest,
                           GFile          *dest_parent,
                           GFileCopyFlags  flags,
                           gboolean        sync_data,
                           gboolean        enable_guestfs_fuse_workaround,
                           gboolean       *out_try_again,
                           GCancellable   *cancellable,
                           GError        **error)
{
    gboolean ret = FALSE;
    int res;
    char *tmp_name = NULL;
    GFile *tmp_dest = NULL;

    if (g_cancellable_set_error_if_cancelled (cancellable, error))
        goto out;

    tmp_name = gs_fileutil_gen_tmp_name (NULL, NULL);
    tmp_dest = g_file_get_child (dest_parent, tmp_name);

    res = link (gs_file_get_path_cached (src), gs_file_get_path_cached (tmp_dest));
    if (res == -1)
    {
        if (errno == EEXIST)
        {
            /* Nothing, fall through */
            *out_try_again = TRUE;
            ret = TRUE;
            goto out;
        }
        else if (errno == EXDEV || errno == EMLINK || errno == EPERM
                 || (enable_guestfs_fuse_workaround && errno == ENOENT))
        {
            if (!g_file_copy (src, tmp_dest, flags,
                              cancellable, NULL, NULL, error))
                goto out;
        }
        else
        {
            gs_set_prefix_error_from_errno (error, errno, "link");
            goto out;
        }
    }

    if (sync_data)
    {
        /* Now, we need to fsync */
        if (!gs_file_sync_data (tmp_dest, cancellable, error))
            goto out;
    }

    if (!gs_file_rename (tmp_dest, dest, cancellable, error))
        goto out;

    ret = TRUE;
    *out_try_again = FALSE;
out:
    g_clear_pointer (&tmp_name, g_free);
    g_clear_object (&tmp_dest);
    return ret;
}