예제 #1
0
/**
 * ostree_sysroot_ensure_initialized:
 * @self: Sysroot
 * @cancellable: Cancellable
 * @error: Error
 *
 * Ensure that @self is set up as a valid rootfs, by creating
 * /ostree/repo, among other things.
 */
gboolean
ostree_sysroot_ensure_initialized (OstreeSysroot  *self,
                                   GCancellable   *cancellable,
                                   GError        **error)
{
  gboolean ret = FALSE;
  g_autoptr(GFile) dir = NULL;
  g_autoptr(GFile) ostree_dir = NULL;
  g_autoptr(GFile) repo_dir = NULL;

  ostree_dir = g_file_get_child (self->path, "ostree");
  repo_dir = g_file_get_child (ostree_dir, "repo");
  if (!gs_file_ensure_directory (repo_dir, TRUE, cancellable, error))
    goto out;

  g_clear_object (&dir);
  dir = g_file_get_child (ostree_dir, "deploy");
  if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
    goto out;

  g_clear_object (&dir);
  dir = ot_gfile_get_child_build_path (ostree_dir, "repo", "objects", NULL);
  if (!g_file_query_exists (dir, NULL))
    {
      glnx_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir);
      if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
                               cancellable, error))
        goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
예제 #2
0
static gboolean
init_rootfs (GFile         *targetroot,
             GCancellable  *cancellable,
             GError       **error)
{
    gboolean ret = FALSE;
    gs_unref_object GFile *child = NULL;
    guint i;
    const char *toplevel_dirs[] = { "dev", "proc", "run", "sys", "var", "sysroot" };
    const Symlink symlinks[] = {
        { "var/opt", "opt" },
        { "var/srv", "srv" },
        { "var/mnt", "mnt" },
        { "var/roothome", "root" },
        { "var/home", "home" },
        { "run/media", "media" },
        { "sysroot/ostree", "ostree" },
        { "sysroot/tmp", "tmp" },
    };

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

    for (i = 0; i < G_N_ELEMENTS (toplevel_dirs); i++)
    {
        gs_unref_object GFile *dir = g_file_get_child (targetroot, toplevel_dirs[i]);

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

    for (i = 0; i < G_N_ELEMENTS (symlinks); i++)
    {
        const Symlink*linkinfo = symlinks + i;
        gs_unref_object GFile *src =
            g_file_resolve_relative_path (targetroot, linkinfo->src);

        if (!g_file_make_symbolic_link (src, linkinfo->target,
                                        cancellable, error))
            goto out;
    }

    ret = TRUE;
out:
    return ret;
}
예제 #3
0
gboolean      
_ostree_repo_write_ref (OstreeRepo    *self,
                        const char    *remote,
                        const char    *ref,
                        const char    *rev,
                        GCancellable  *cancellable,
                        GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GFile *dir = NULL;

  if (remote == NULL)
    dir = g_object_ref (self->local_heads_dir);
  else
    {
      dir = g_file_get_child (self->remote_heads_dir, remote);
      
      if (rev != NULL)
        {
          if (!gs_file_ensure_directory (dir, FALSE, cancellable, error))
            goto out;
        }
    }

  if (rev == NULL)
    {
      gs_unref_object GFile *child = g_file_resolve_relative_path (dir, ref);

      if (g_file_query_exists (child, cancellable))
        {
          if (!gs_file_unlink (child, cancellable, error))
            goto out;
        }
    }
  else
    {
      if (!write_checksum_file (dir, ref, rev, cancellable, error))
        goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
예제 #4
0
/**
 * gs_file_ensure_directory:
 * @dir: Path to create as directory
 * @with_parents: Also create parent directories
 * @cancellable: a #GCancellable
 * @error: a #GError
 *
 * Like g_file_make_directory(), except does not throw an error if the
 * directory already exists.
 */
gboolean
gs_file_ensure_directory (GFile         *dir,
                          gboolean       with_parents,
                          GCancellable  *cancellable,
                          GError       **error)
{
    gboolean ret = FALSE;
    GError *temp_error = NULL;
    GFile *parent = NULL;

    if (!g_file_make_directory (dir, cancellable, &temp_error))
    {
        if (with_parents &&
                g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
            parent = g_file_get_parent (dir);
            if (parent)
            {
                g_clear_error (&temp_error);

                if (!glnx_shutil_mkdir_p_at (AT_FDCWD,
                                             gs_file_get_path_cached (parent),
                                             0777,
                                             cancellable,
                                             error))
                    goto out;
            }
            if (!gs_file_ensure_directory (dir, FALSE, cancellable, error))
                goto out;
        }
        else if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
        {
            g_propagate_error (error, temp_error);
            goto out;
        }
        else
            g_clear_error (&temp_error);
    }

    ret = TRUE;
out:
    g_clear_object (&parent);
    return ret;
}
static gboolean
copy_exports (GFile    *source,
              GFile    *destination,
              const char *source_prefix,
              const char *required_prefix,
              GCancellable  *cancellable,
              GError       **error)
{
  if (!gs_file_ensure_directory (destination, TRUE, cancellable, error))
    return FALSE;

  /* The fds are closed by this call */
  if (!export_dir (AT_FDCWD, gs_file_get_path_cached (source), source_prefix,
                   AT_FDCWD, gs_file_get_path_cached (destination),
                   required_prefix, cancellable, error))
    return FALSE;

  return TRUE;
}
예제 #6
0
gboolean
ot_admin_builtin_os_init (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  GOptionContext *context;
  glnx_unref_object OstreeSysroot *sysroot = NULL;
  gboolean ret = FALSE;
  const char *osname = NULL;
  g_autoptr(GFile) deploy_dir = NULL;
  g_autoptr(GFile) dir = NULL;

  context = g_option_context_new ("OSNAME - Initialize empty state for given operating system");

  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_ensure_initialized (sysroot, cancellable, error))
    goto out;

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

  osname = argv[1];

  deploy_dir = ot_gfile_get_child_build_path (ostree_sysroot_get_path (sysroot), "ostree", "deploy", osname, NULL);

  /* Ensure core subdirectories of /var exist, since we need them for
   * dracut generation, and the host will want them too.
   */
  g_clear_object (&dir);
  dir = ot_gfile_get_child_build_path (deploy_dir, "var", "tmp", NULL);
  if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
    goto out;
  if (chmod (gs_file_get_path_cached (dir), 01777) < 0)
    {
      gs_set_error_from_errno (error, errno);
      goto out;
    }

  g_clear_object (&dir);
  dir = ot_gfile_get_child_build_path (deploy_dir, "var", "lib", NULL);
  if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
    goto out;

  g_clear_object (&dir);
  dir = ot_gfile_get_child_build_path (deploy_dir, "var", "run", NULL);
  if (!g_file_test (gs_file_get_path_cached (dir), G_FILE_TEST_IS_SYMLINK))
    {
      if (symlink ("../run", gs_file_get_path_cached (dir)) < 0)
        {
          gs_set_error_from_errno (error, errno);
          goto out;
        }
    }

  dir = ot_gfile_get_child_build_path (deploy_dir, "var", "lock", NULL);
  if (!g_file_test (gs_file_get_path_cached (dir), G_FILE_TEST_IS_SYMLINK))
    {
      if (symlink ("../run/lock", gs_file_get_path_cached (dir)) < 0)
        {
          gs_set_error_from_errno (error, errno);
          goto out;
        }
    }

  g_print ("%s initialized as OSTree root\n", gs_file_get_path_cached (deploy_dir));

  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  return ret;
}
예제 #7
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;
}
예제 #8
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;
}
예제 #9
0
static gboolean
write_checksum_file (GFile *parentdir,
                     const char *name,
                     const char *sha256,
                     GCancellable *cancellable,
                     GError **error)
{
  gboolean ret = FALSE;
  gsize bytes_written;
  int i;
  gs_unref_object GFile *parent = NULL;
  gs_unref_object GFile *child = NULL;
  gs_unref_object GOutputStream *out = NULL;
  gs_unref_ptrarray GPtrArray *components = NULL;

  if (!ostree_validate_checksum_string (sha256, error))
    goto out;

  if (ostree_validate_checksum_string (name, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Rev name '%s' looks like a checksum", name);
      goto out;
    }

  if (!ot_util_path_split_validate (name, &components, error))
    goto out;

  if (components->len == 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Invalid empty ref name");
      goto out;
    }

  parent = g_object_ref (parentdir);
  for (i = 0; i+1 < components->len; i++)
    {
      child = g_file_get_child (parent, (char*)components->pdata[i]);

      if (!gs_file_ensure_directory (child, FALSE, cancellable, error))
        goto out;

      g_clear_object (&parent);
      parent = child;
      child = NULL;
    }

  child = g_file_get_child (parent, components->pdata[components->len - 1]);
  if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, cancellable, error)) == NULL)
    goto out;
  if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, cancellable, error))
    goto out;
  if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, cancellable, error))
    goto out;
  if (!g_output_stream_close (out, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
gboolean
xdg_app_builtin_build_init (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(GFile) var_deploy_base = NULL;
  g_autoptr(GFile) var_deploy_files = NULL;
  g_autoptr(GFile) base = NULL;
  g_autoptr(GFile) files_dir = NULL;
  g_autoptr(GFile) var_dir = NULL;
  g_autoptr(GFile) var_tmp_dir = NULL;
  g_autoptr(GFile) var_run_dir = NULL;
  g_autoptr(GFile) metadata_file = NULL;
  const char *app_id;
  const char *directory;
  const char *sdk;
  const char *runtime;
  const char *branch = "master";
  g_autofree char *runtime_ref = NULL;
  g_autofree char *var_ref = NULL;
  g_autofree char *sdk_ref = NULL;
  g_autofree char *metadata_contents = NULL;

  context = g_option_context_new ("DIRECTORY APPNAME SDK RUNTIME [BRANCH] - Initialize a directory for building");

  if (!xdg_app_option_context_parse (context, options, &argc, &argv, XDG_APP_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
    return FALSE;

  if (argc < 5)
    return usage_error (context, "RUNTIME must be specified", error);

  directory = argv[1];
  app_id = argv[2];
  sdk = argv[3];
  runtime = argv[4];
  if (argc >= 6)
    branch = argv[5];

  if (!xdg_app_is_valid_name (app_id))
    return xdg_app_fail (error, "'%s' is not a valid application name", app_id);

  if (!xdg_app_is_valid_name (runtime))
    return xdg_app_fail (error, "'%s' is not a valid runtime name", runtime);

  if (!xdg_app_is_valid_name (sdk))
    return xdg_app_fail (error, "'%s' is not a valid sdk name", sdk);

  if (!xdg_app_is_valid_branch (branch))
    return xdg_app_fail (error, "'%s' is not a valid branch name", branch);

  runtime_ref = xdg_app_build_untyped_ref (runtime, branch, opt_arch);
  sdk_ref = xdg_app_build_untyped_ref (sdk, branch, opt_arch);

  base = g_file_new_for_commandline_arg (directory);

  if (!gs_file_ensure_directory (base, TRUE, cancellable, error))
    return FALSE;

  files_dir = g_file_get_child (base, "files");
  var_dir = g_file_get_child (base, "var");
  var_tmp_dir = g_file_get_child (var_dir, "tmp");
  var_run_dir = g_file_get_child (var_dir, "run");
  metadata_file = g_file_get_child (base, "metadata");

  if (g_file_query_exists (files_dir, cancellable))
    return xdg_app_fail (error, "Build directory %s already initialized", directory);

  if (opt_var)
    {
      var_ref = xdg_app_build_runtime_ref (opt_var, branch, opt_arch);

      var_deploy_base = xdg_app_find_deploy_dir_for_ref (var_ref, cancellable, error);
      if (var_deploy_base == NULL)
        return FALSE;

      var_deploy_files = g_file_get_child (var_deploy_base, "files");
    }

  if (!g_file_make_directory (files_dir, cancellable, error))
    return FALSE;

  if (var_deploy_files)
    {
      if (!gs_shutil_cp_a (var_deploy_files, var_dir, cancellable, error))
        return FALSE;
    }
  else
    {
      if (!g_file_make_directory (var_dir, cancellable, error))
        return FALSE;
    }

  if (!gs_file_ensure_directory (var_tmp_dir, FALSE, cancellable, error))
    return FALSE;

  if (!g_file_query_exists (var_run_dir, cancellable) &&
      !g_file_make_symbolic_link (var_run_dir, "/run", cancellable, error))
    return FALSE;

  metadata_contents = g_strdup_printf("[Application]\n"
                                      "name=%s\n"
                                      "runtime=%s\n"
                                      "sdk=%s\n",
                                      app_id, runtime_ref, sdk_ref);
  if (!g_file_replace_contents (metadata_file,
                                metadata_contents, strlen (metadata_contents), NULL, FALSE,
                                G_FILE_CREATE_REPLACE_DESTINATION,
                                NULL, cancellable, error))
    return FALSE;

  return TRUE;
}
gboolean
flatpak_builtin_build_init (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(GFile) var_deploy_base = NULL;
  g_autoptr(GFile) var_deploy_files = NULL;
  g_autoptr(GFile) base = NULL;
  g_autoptr(GFile) files_dir = NULL;
  g_autoptr(GFile) usr_dir = NULL;
  g_autoptr(GFile) var_dir = NULL;
  g_autoptr(GFile) var_tmp_dir = NULL;
  g_autoptr(GFile) var_run_dir = NULL;
  g_autoptr(GFile) metadata_file = NULL;
  g_autoptr(GString) metadata_contents = NULL;
  const char *app_id;
  const char *directory;
  const char *sdk;
  const char *runtime;
  const char *branch = "master";
  g_autofree char *runtime_ref = NULL;
  g_autofree char *var_ref = NULL;
  g_autofree char *sdk_ref = NULL;
  int i;

  context = g_option_context_new ("DIRECTORY APPNAME SDK RUNTIME [BRANCH] - Initialize a directory for building");

  if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
    return FALSE;

  if (argc < 5)
    return usage_error (context, "RUNTIME must be specified", error);

  directory = argv[1];
  app_id = argv[2];
  sdk = argv[3];
  runtime = argv[4];
  if (argc >= 6)
    branch = argv[5];

  if (!flatpak_is_valid_name (app_id))
    return flatpak_fail (error, "'%s' is not a valid application name", app_id);

  if (!flatpak_is_valid_name (runtime))
    return flatpak_fail (error, "'%s' is not a valid runtime name", runtime);

  if (!flatpak_is_valid_name (sdk))
    return flatpak_fail (error, "'%s' is not a valid sdk name", sdk);

  if (!flatpak_is_valid_branch (branch))
    return flatpak_fail (error, "'%s' is not a valid branch name", branch);

  runtime_ref = flatpak_build_untyped_ref (runtime, branch, opt_arch);
  sdk_ref = flatpak_build_untyped_ref (sdk, branch, opt_arch);

  base = g_file_new_for_commandline_arg (directory);

  if (!gs_file_ensure_directory (base, TRUE, cancellable, error))
    return FALSE;

  files_dir = g_file_get_child (base, "files");
  if (opt_sdk_dir)
    usr_dir = g_file_get_child (base, opt_sdk_dir);
  else
    usr_dir = g_file_get_child (base, "usr");
  var_dir = g_file_get_child (base, "var");
  var_tmp_dir = g_file_get_child (var_dir, "tmp");
  var_run_dir = g_file_get_child (var_dir, "run");
  metadata_file = g_file_get_child (base, "metadata");

  if (!opt_update &&
      g_file_query_exists (files_dir, cancellable))
    return flatpak_fail (error, "Build directory %s already initialized", directory);

  if (opt_writable_sdk)
    {
      g_autofree char *full_sdk_ref = g_strconcat ("runtime/", sdk_ref, NULL);
      g_autoptr(GError) my_error = NULL;
      g_autoptr(GFile) sdk_deploy_files = NULL;
      g_autoptr(FlatpakDeploy) sdk_deploy = NULL;

      sdk_deploy = flatpak_find_deploy_for_ref (full_sdk_ref, cancellable, error);
      if (sdk_deploy == NULL)
        return FALSE;

      if (!gs_shutil_rm_rf (usr_dir, NULL, &my_error))
        {
          if (!g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_propagate_error (error, g_steal_pointer (&my_error));
              return FALSE;
            }

          g_clear_error (&my_error);
        }

      sdk_deploy_files = flatpak_deploy_get_files (sdk_deploy);
      if (!flatpak_cp_a (sdk_deploy_files, usr_dir, FLATPAK_CP_FLAGS_NO_CHOWN, cancellable, error))
        return FALSE;

      if (opt_sdk_extensions)
        {
          g_autoptr(GKeyFile) metakey = flatpak_deploy_get_metadata (sdk_deploy);
          GList *extensions = NULL, *l;

          /* We leak this on failure, as we have no autoptr for deep lists.. */
          extensions = flatpak_list_extensions (metakey,
                                                opt_arch,
                                                branch);

          for (i = 0; opt_sdk_extensions[i] != NULL; i++)
            {
              const char *requested_extension = opt_sdk_extensions[i];
              gboolean found = FALSE;

              for (l = extensions; l != NULL; l = l->next)
                {
                  FlatpakExtension *ext = l->data;

                  if (strcmp (ext->installed_id, requested_extension) == 0 ||
                      strcmp (ext->id, requested_extension) == 0)
                    {
                      g_autoptr(GFile) ext_deploy_dir = flatpak_find_deploy_dir_for_ref (ext->ref, cancellable, NULL);
                      if (ext_deploy_dir != NULL)
                        {
                          g_autoptr(GFile) ext_deploy_files = g_file_get_child (ext_deploy_dir, "files");
                          g_autoptr(GFile) target = g_file_resolve_relative_path (usr_dir, ext->directory);
                          g_autoptr(GFile) target_parent = g_file_get_parent (target);

                          if (!gs_file_ensure_directory (target_parent, TRUE, cancellable, error))
                            return FALSE;

                          /* An extension overrides whatever is there before, so we clean up first */
                          if (!gs_shutil_rm_rf (target, cancellable, error))
                            return FALSE;

                          if (!flatpak_cp_a (ext_deploy_files, target, FLATPAK_CP_FLAGS_NO_CHOWN, cancellable, error))
                            return FALSE;

                          found = TRUE;
                        }
                      else
                        {
                          g_list_free_full (extensions, (GDestroyNotify) flatpak_extension_free);
                          return flatpak_fail (error, "Requested extension %s not installed\n", requested_extension);
                        }
                    }
                }

              if (!found)
                return flatpak_fail (error, "No extension %s in sdk\n", requested_extension);
            }
          g_list_free_full (extensions, (GDestroyNotify) flatpak_extension_free);
        }
    }

  if (opt_var)
    {
      var_ref = flatpak_build_runtime_ref (opt_var, branch, opt_arch);

      var_deploy_base = flatpak_find_deploy_dir_for_ref (var_ref, cancellable, error);
      if (var_deploy_base == NULL)
        return FALSE;

      var_deploy_files = g_file_get_child (var_deploy_base, "files");
    }

  if (opt_update)
    return TRUE;

  if (!g_file_make_directory (files_dir, cancellable, error))
    return FALSE;

  if (var_deploy_files)
    {
      if (!gs_shutil_cp_a (var_deploy_files, var_dir, cancellable, error))
        return FALSE;
    }
  else
    {
      if (!g_file_make_directory (var_dir, cancellable, error))
        return FALSE;
    }

  if (!gs_file_ensure_directory (var_tmp_dir, FALSE, cancellable, error))
    return FALSE;

  if (!g_file_query_exists (var_run_dir, cancellable) &&
      !g_file_make_symbolic_link (var_run_dir, "/run", cancellable, error))
    return FALSE;


  metadata_contents = g_string_new ("[Application]\n");
  g_string_append_printf (metadata_contents,
                          "name=%s\n"
                          "runtime=%s\n"
                          "sdk=%s\n",
                          app_id, runtime_ref, sdk_ref);
  if (opt_tags != NULL)
    {
      g_string_append (metadata_contents, "tags=");
      for (i = 0; opt_tags[i] != NULL; i++)
        {
          g_string_append (metadata_contents, opt_tags[i]);
          g_string_append_c (metadata_contents, ';');
        }
      g_string_append_c (metadata_contents, '\n');
    }

  if (!g_file_replace_contents (metadata_file,
                                metadata_contents->str, metadata_contents->len, NULL, FALSE,
                                G_FILE_CREATE_REPLACE_DESTINATION,
                                NULL, cancellable, error))
    return FALSE;

  return TRUE;
}
예제 #12
0
static gboolean
migrate_locale_dir (GFile      *source_dir,
                    GFile      *separate_dir,
                    const char *subdir,
                    GError    **error)
{
  g_autoptr(GFileEnumerator) dir_enum = NULL;
  GFileInfo *next;
  GError *temp_error = NULL;

  dir_enum = g_file_enumerate_children (source_dir, "standard::name,standard::type",
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        NULL, NULL);
  if (!dir_enum)
    return TRUE;

  while ((next = g_file_enumerator_next_file (dir_enum, NULL, &temp_error)))
    {
      g_autoptr(GFileInfo) child_info = next;
      g_autoptr(GFile) child = NULL;
      g_autoptr(GFile) locale_subdir = NULL;

      child = g_file_get_child (source_dir, g_file_info_get_name (child_info));

      if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
        {
          g_autoptr(GFile) child = NULL;
          const char *name = g_file_info_get_name (child_info);
          g_autofree char *language = g_strdup (name);
          g_autofree char *relative = NULL;
          g_autofree char *target = NULL;
          char *c;

          c = strchr (language, '@');
          if (c != NULL)
            *c = 0;
          c = strchr (language, '_');
          if (c != NULL)
            *c = 0;

          /* We ship english and C locales always */
          if (strcmp (language, "C") == 0 ||
              strcmp (language, "en") == 0)
            continue;

          child = g_file_get_child (source_dir, g_file_info_get_name (child_info));

          relative = g_build_filename (language, subdir, name, NULL);
          locale_subdir = g_file_resolve_relative_path (separate_dir, relative);
          if (!gs_file_ensure_directory (locale_subdir, TRUE,
                                         NULL, error))
            return FALSE;

          if (!flatpak_cp_a (child, locale_subdir,
                             FLATPAK_CP_FLAGS_MERGE | FLATPAK_CP_FLAGS_MOVE,
                             NULL, error))
            return FALSE;

          target = g_build_filename ("../../share/runtime/locale", relative, NULL);

          if (!g_file_make_symbolic_link (child, target,
                                          NULL, error))
            return FALSE;

        }
    }

  if (temp_error != NULL)
    {
      g_propagate_error (error, temp_error);
      return FALSE;
    }

  return TRUE;
}