/** * ostree_sysroot_get_deployment_origin_path: * @deployment_path: A deployment path * * Returns: (transfer full): Path to deployment origin file */ GFile * ostree_sysroot_get_deployment_origin_path (GFile *deployment_path) { g_autoptr(GFile) deployment_parent = g_file_get_parent (deployment_path); return ot_gfile_resolve_path_printf (deployment_parent, "%s.origin", gs_file_get_path_cached (deployment_path)); }
static gboolean cleanup_other_bootversions (OstreeSysroot *self, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int cleanup_bootversion; int cleanup_subbootversion; gs_unref_object GFile *cleanup_boot_dir = NULL; cleanup_bootversion = self->bootversion == 0 ? 1 : 0; cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) goto out; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d", cleanup_bootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) goto out; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.0", cleanup_bootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) goto out; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.1", cleanup_bootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) goto out; g_clear_object (&cleanup_boot_dir); cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) goto out; g_clear_object (&cleanup_boot_dir); ret = TRUE; out: return ret; }
static gboolean _ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader, int bootversion, GCancellable *cancellable, GError **error) { OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader); g_autoptr(GFile) new_config_path = NULL; g_autofree char *config_contents = NULL; g_autofree char *new_config_contents = NULL; g_autoptr(GPtrArray) new_lines = NULL; /* This should follow the symbolic link to the current bootversion. */ config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, cancellable, error); if (!config_contents) return FALSE; new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/uEnv.txt", bootversion); new_lines = g_ptr_array_new_with_free_func (g_free); if (!create_config_from_boot_loader_entries (self, bootversion, new_lines, cancellable, error)) return FALSE; new_config_contents = _ostree_sysroot_join_lines (new_lines); { g_autoptr(GBytes) new_config_contents_bytes = g_bytes_new_static (new_config_contents, strlen (new_config_contents)); if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, cancellable, error)) return FALSE; } return TRUE; }
static gboolean resolve_refspec (OstreeRepo *self, const char *remote, const char *ref, gboolean allow_noent, char **out_rev, GError **error) { gboolean ret = FALSE; __attribute__((unused)) GCancellable *cancellable = NULL; GError *temp_error = NULL; g_autofree char *ret_rev = NULL; g_autoptr(GFile) child = NULL; g_return_val_if_fail (ref != NULL, FALSE); /* We intentionally don't allow a ref that looks like a checksum */ if (ostree_validate_checksum_string (ref, NULL)) { ret_rev = g_strdup (ref); } else if (remote != NULL) { child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s", remote, ref); if (!g_file_query_exists (child, NULL)) g_clear_object (&child); } else { child = g_file_resolve_relative_path (self->local_heads_dir, ref); if (!g_file_query_exists (child, NULL)) { g_clear_object (&child); child = g_file_resolve_relative_path (self->remote_heads_dir, ref); if (!g_file_query_exists (child, NULL)) { g_clear_object (&child); if (!find_ref_in_remotes (self, ref, &child, error)) goto out; } } } if (child) { if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL) { g_propagate_error (error, temp_error); g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child)); goto out; } g_strchomp (ret_rev); if (!ostree_validate_checksum_string (ret_rev, error)) goto out; } else { if (!resolve_refspec_fallback (self, remote, ref, allow_noent, &ret_rev, cancellable, error)) goto out; } ot_transfer_out_value (out_rev, &ret_rev); ret = TRUE; out: return ret; }
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; }
static gboolean _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, int bootversion, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); gs_unref_object GFile *new_config_path = NULL; gs_free char *config_contents = NULL; gs_free char *new_config_contents = NULL; gs_unref_ptrarray GPtrArray *new_lines = NULL; gs_unref_ptrarray GPtrArray *tmp_lines = NULL; gs_free char *kernel_arg = NULL; gboolean saw_default = FALSE; gboolean regenerate_default = FALSE; gboolean parsing_label = FALSE; char **lines = NULL; char **iter; guint i; new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", bootversion); /* This should follow the symbolic link to the current bootversion. */ config_contents = gs_file_load_contents_utf8 (self->config_path, cancellable, error); if (!config_contents) goto out; lines = g_strsplit (config_contents, "\n", -1); new_lines = g_ptr_array_new_with_free_func (g_free); tmp_lines = g_ptr_array_new_with_free_func (g_free); /* Note special iteration condition here; we want to also loop one * more time at the end where line = NULL to ensure we finish off * processing the last LABEL. */ iter = lines; while (TRUE) { char *line = *iter; gboolean skip = FALSE; if (parsing_label && (line == NULL || !g_str_has_prefix (line, "\t"))) { parsing_label = FALSE; if (kernel_arg == NULL) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No KERNEL argument found after LABEL"); goto out; } /* If this is a non-ostree kernel, just emit the lines * we saw. */ if (!g_str_has_prefix (kernel_arg, "/ostree/")) { for (i = 0; i < tmp_lines->len; i++) { g_ptr_array_add (new_lines, tmp_lines->pdata[i]); tmp_lines->pdata[i] = NULL; /* Transfer ownership */ } } else { /* Otherwise, we drop the config on the floor - it * will be regenerated. */ g_ptr_array_set_size (tmp_lines, 0); } } if (line == NULL) break; if (!parsing_label && (g_str_has_prefix (line, "LABEL "))) { parsing_label = TRUE; g_ptr_array_set_size (tmp_lines, 0); } else if (parsing_label && g_str_has_prefix (line, "\tKERNEL ")) { g_free (kernel_arg); kernel_arg = g_strdup (line + strlen ("\tKERNEL ")); } else if (!parsing_label && (g_str_has_prefix (line, "DEFAULT "))) { saw_default = TRUE; /* XXX Searching for patterns in the title is rather brittle, * but this hack is at least noted in the code that builds * the title to hopefully avoid regressions. */ if (g_str_has_prefix (line, "DEFAULT ostree:") || /* old format */ strstr (line, "(ostree") != NULL) /* new format */ { regenerate_default = TRUE; } skip = TRUE; } if (skip) { g_free (line); } else { if (parsing_label) { g_ptr_array_add (tmp_lines, line); } else { g_ptr_array_add (new_lines, line); } } /* Transfer ownership */ *iter = NULL; iter++; } if (!saw_default) regenerate_default = TRUE; if (!append_config_from_boostree_loader_entries (self, regenerate_default, bootversion, new_lines, cancellable, error)) goto out; new_config_contents = _ostree_sysroot_join_lines (new_lines); { gs_unref_bytes GBytes *new_config_contents_bytes = g_bytes_new_static (new_config_contents, strlen (new_config_contents)); if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, cancellable, error)) goto out; } ret = TRUE; out: g_free (lines); /* Note we freed elements individually */ return ret; }
/** * ostree_repo_static_delta_execute_offline: * @self: Repo * @dir: Path to a directory containing static delta data * @skip_validation: If %TRUE, assume data integrity * @cancellable: Cancellable * @error: Error * * Given a directory representing an already-downloaded static delta * on disk, apply it, generating a new commit. The directory must be * named with the form "FROM-TO", where both are checksums, and it * must contain a file named "superblock", along with at least one part. */ gboolean ostree_repo_static_delta_execute_offline (OstreeRepo *self, GFile *dir, gboolean skip_validation, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint i, n; gs_unref_object GFile *meta_file = g_file_get_child (dir, "superblock"); gs_unref_variant GVariant *meta = NULL; gs_unref_variant GVariant *headers = NULL; gs_unref_variant GVariant *fallback = NULL; if (!ot_util_variant_map (meta_file, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), FALSE, &meta, error)) goto out; /* Parsing OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */ /* Write the to-commit object */ { gs_unref_variant GVariant *to_csum_v = NULL; gs_free char *to_checksum = NULL; gs_unref_variant GVariant *to_commit = NULL; gboolean have_to_commit; to_csum_v = g_variant_get_child_value (meta, 3); if (!ostree_validate_structureof_csum_v (to_csum_v, error)) goto out; to_checksum = ostree_checksum_from_bytes_v (to_csum_v); if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT, to_checksum, &have_to_commit, cancellable, error)) goto out; if (!have_to_commit) { to_commit = g_variant_get_child_value (meta, 4); if (!ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_COMMIT, to_checksum, to_commit, NULL, cancellable, error)) goto out; } } fallback = g_variant_get_child_value (meta, 7); if (g_variant_n_children (fallback) > 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot execute delta offline: contains nonempty http fallback entries"); goto out; } headers = g_variant_get_child_value (meta, 6); n = g_variant_n_children (headers); for (i = 0; i < n; i++) { guint64 size; guint64 usize; const guchar *csum; gboolean have_all; gs_unref_variant GVariant *header = NULL; gs_unref_variant GVariant *csum_v = NULL; gs_unref_variant GVariant *objects = NULL; gs_unref_object GFile *part_path = NULL; gs_unref_object GInputStream *raw_in = NULL; gs_unref_object GInputStream *in = NULL; header = g_variant_get_child_value (headers, i); g_variant_get (header, "(@aytt@ay)", &csum_v, &size, &usize, &objects); if (!_ostree_repo_static_delta_part_have_all_objects (self, objects, &have_all, cancellable, error)) goto out; /* If we already have these objects, don't bother executing the * static delta. */ if (have_all) continue; csum = ostree_checksum_bytes_peek_validate (csum_v, error); if (!csum) goto out; part_path = ot_gfile_resolve_path_printf (dir, "%u", i); in = (GInputStream*)g_file_read (part_path, cancellable, error); if (!in) goto out; if (!skip_validation) { gs_free char *expected_checksum = ostree_checksum_from_bytes (csum); if (!_ostree_static_delta_part_validate (self, part_path, i, expected_checksum, cancellable, error)) goto out; } { GMappedFile *mfile = gs_file_map_noatime (part_path, cancellable, error); gs_unref_bytes GBytes *bytes = NULL; if (!mfile) goto out; bytes = g_mapped_file_get_bytes (mfile); g_mapped_file_unref (mfile); if (!_ostree_static_delta_part_execute (self, objects, bytes, cancellable, error)) { g_prefix_error (error, "executing delta part %i: ", i); goto out; } } } ret = TRUE; out: return ret; }