/** * 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; }
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; }
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; }
/** * 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; }
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; }
/* 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; }
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; }
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; }
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; }