gboolean _rpmostree_jsonutil_append_string_array_to (JsonObject *object, const char *member_name, GPtrArray *array, GError **error) { JsonArray *jarray = json_object_get_array_member (object, member_name); guint i, len; if (!jarray) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No member '%s' found", member_name); return FALSE; } len = json_array_get_length (jarray); for (i = 0; i < len; i++) { const char *v = _rpmostree_jsonutil_array_require_string_element (jarray, i, error); if (!v) return FALSE; g_ptr_array_add (array, g_strdup (v)); } return TRUE; }
static gboolean set_keyfile_string_array_from_json (GKeyFile *keyfile, const char *keyfile_group, const char *keyfile_key, JsonArray *a, GError **error) { gboolean ret = FALSE; guint len = json_array_get_length (a); guint i; g_autoptr(GPtrArray) instlangs_v = g_ptr_array_new (); for (i = 0; i < len; i++) { const char *elt = _rpmostree_jsonutil_array_require_string_element (a, i, error); if (!elt) goto out; g_ptr_array_add (instlangs_v, (char*)elt); } g_key_file_set_string_list (keyfile, keyfile_group, keyfile_key, (const char*const*)instlangs_v->pdata, instlangs_v->len); ret = TRUE; out: return ret; }
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; }
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 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; }
static gboolean compute_checksum_from_treefile_and_goal (RpmOstreeTreeComposeContext *self, HyGoal goal, GFile *contextdir, JsonArray *add_files, char **out_checksum, GError **error) { gboolean ret = FALSE; g_autofree char *ret_checksum = NULL; GChecksum *checksum = g_checksum_new (G_CHECKSUM_SHA256); /* Hash in the raw treefile; this means reordering the input packages * or adding a comment will cause a recompose, but let's be conservative * here. */ { gsize len; const guint8* buf = g_bytes_get_data (self->serialized_treefile, &len); g_checksum_update (checksum, buf, len); } if (add_files) { guint i, len = json_array_get_length (add_files); for (i = 0; i < len; i++) { g_autoptr(GFile) srcfile = NULL; const char *src, *dest; JsonArray *add_el = json_array_get_array_element (add_files, i); g_autoptr(GFile) child = NULL; if (!add_el) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Element in add-files is not an array"); goto out; } src = _rpmostree_jsonutil_array_require_string_element (add_el, 0, error); if (!src) goto out; dest = _rpmostree_jsonutil_array_require_string_element (add_el, 1, error); if (!dest) goto out; srcfile = g_file_resolve_relative_path (contextdir, src); if (!_rpmostree_util_update_checksum_from_file (checksum, srcfile, NULL, error)) goto out; g_checksum_update (checksum, (const guint8 *) dest, strlen (dest)); } } /* FIXME; we should also hash the post script */ /* Hash in each package */ rpmostree_dnf_add_checksum_goal (checksum, goal); ret_checksum = g_strdup (g_checksum_get_string (checksum)); ret = TRUE; out: gs_transfer_out_value (out_checksum, &ret_checksum); if (checksum) g_checksum_free (checksum); return ret; }