/** * rpmostreed_sysroot_populate : * * loads internals and starts monitoring * * Returns: True on success */ gboolean rpmostreed_sysroot_populate (RpmostreedSysroot *self, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFile) sysroot_file = NULL; const char *sysroot_path; g_return_val_if_fail (self != NULL, FALSE); sysroot_path = rpmostree_sysroot_get_path (RPMOSTREE_SYSROOT (self)); sysroot_file = g_file_new_for_path (sysroot_path); self->ot_sysroot = ostree_sysroot_new (sysroot_file); /* This creates and caches an OstreeRepo instance inside * OstreeSysroot to ensure subsequent ostree_sysroot_get_repo() * calls won't fail. */ if (!ostree_sysroot_get_repo (self->ot_sysroot, &self->repo, cancellable, error)) goto out; if (!sysroot_populate_deployments_unlocked (self, NULL, error)) goto out; if (self->monitor == NULL) { const char *sysroot_path = gs_file_get_path_cached (ostree_sysroot_get_path (self->ot_sysroot)); g_autofree char *sysroot_deploy_path = g_build_filename (sysroot_path, "ostree/deploy", NULL); g_autoptr(GFile) sysroot_deploy = g_file_new_for_path (sysroot_deploy_path); self->monitor = g_file_monitor (sysroot_deploy, 0, NULL, error); if (self->monitor == NULL) goto out; self->sig_changed = g_signal_connect (self->monitor, "changed", G_CALLBACK (on_deploy_changed), self); } ret = TRUE; out: return ret; }
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; }
gboolean ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GOptionContext *context; glnx_unref_object OstreeSysroot *sysroot = NULL; glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL; g_autofree char *origin_remote = NULL; g_autofree char *origin_ref = NULL; g_autofree char *origin_refspec = NULL; g_autofree char *new_revision = NULL; g_autoptr(GFile) deployment_path = NULL; g_autoptr(GFile) deployment_origin_path = NULL; glnx_unref_object OstreeDeployment *merge_deployment = NULL; glnx_unref_object OstreeDeployment *new_deployment = NULL; GSConsole *console = NULL; gboolean in_status_line = FALSE; glnx_unref_object OstreeAsyncProgress *progress = NULL; gboolean changed; OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed"); if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) goto out; if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, cancellable, error); if (!upgrader) goto out; console = gs_console_get (); if (console) { gs_console_begin_status_line (console, "", NULL, NULL); in_status_line = TRUE; progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console); } if (opt_allow_downgrade) upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER; if (!ostree_sysroot_upgrader_pull (upgrader, 0, upgraderpullflags, progress, &changed, cancellable, error)) goto out; if (in_status_line) { gs_console_end_status_line (console, NULL, NULL); in_status_line = FALSE; } if (!changed) { g_print ("No update available.\n"); } else { g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/"); if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) goto out; if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot)) { gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT, cancellable, error, "systemctl", "reboot", NULL); } } ret = TRUE; out: if (in_status_line) gs_console_end_status_line (console, NULL, NULL); if (context) g_option_context_free (context); return ret; }
gboolean ostree_admin_option_context_parse (GOptionContext *context, const GOptionEntry *main_entries, int *argc, char ***argv, OstreeAdminBuiltinFlags flags, OstreeSysroot **out_sysroot, GCancellable *cancellable, GError **error) { g_autoptr(GFile) sysroot_path = NULL; glnx_unref_object OstreeSysroot *sysroot = NULL; gboolean success = FALSE; /* Entries are listed in --help output in the order added. We add the * main entries ourselves so that we can add the --sysroot entry first. */ g_option_context_add_main_entries (context, global_admin_entries, NULL); if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) goto out; if (opt_sysroot != NULL) sysroot_path = g_file_new_for_path (opt_sysroot); sysroot = ostree_sysroot_new (sysroot_path); if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) { GFile *path = ostree_sysroot_get_path (sysroot); /* If sysroot path is "/" then user must be root. */ if (!g_file_has_parent (path, NULL) && getuid () != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "You must be root to perform this command"); goto out; } } if (opt_print_current_dir) { g_autoptr(GPtrArray) deployments = NULL; OstreeDeployment *first_deployment; g_autoptr(GFile) deployment_file = NULL; g_autofree char *deployment_path = NULL; if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unable to find a deployment in sysroot"); goto out; } first_deployment = deployments->pdata[0]; deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment); deployment_path = g_file_get_path (deployment_file); g_print ("%s\n", deployment_path); /* The g_autoptr, g_autofree etc. don't happen when we explicitly * exit, making valgrind complain about leaks */ g_clear_object (&sysroot); g_clear_object (&sysroot_path); g_clear_object (&deployment_file); g_clear_pointer (&deployments, g_ptr_array_unref); g_clear_pointer (&deployment_path, g_free); exit (EXIT_SUCCESS); } if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0) { /* Released when sysroot is finalized, or on process exit */ if (!ot_admin_sysroot_lock (sysroot, error)) goto out; } if (out_sysroot) *out_sysroot = g_steal_pointer (&sysroot); success = TRUE; out: return success; }
gboolean ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GOptionContext *context; const char *new_provided_refspec = NULL; gs_unref_object OstreeRepo *repo = NULL; gs_free char *origin_refspec = NULL; gs_free char *origin_remote = NULL; gs_free char *origin_ref = NULL; gs_free char *new_remote = NULL; gs_free char *new_ref = NULL; gs_free char *new_refspec = NULL; gs_free char *new_revision = NULL; gs_unref_object GFile *deployment_path = NULL; gs_unref_object GFile *deployment_origin_path = NULL; gs_unref_object OstreeDeployment *merge_deployment = NULL; gs_unref_object OstreeDeployment *new_deployment = NULL; gs_unref_object OstreeSysrootUpgrader *upgrader = NULL; gs_unref_object OstreeAsyncProgress *progress = NULL; gboolean changed; GSConsole *console = NULL; gboolean in_status_line = FALSE; GKeyFile *old_origin; GKeyFile *new_origin = NULL; context = g_option_context_new ("REF - Construct new tree from current origin and deploy it, if it changed"); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, error)) goto out; if (argc < 2) { ot_util_usage_error (context, "REF must be specified", error); goto out; } new_provided_refspec = argv[1]; if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, cancellable, error); if (!upgrader) goto out; old_origin = ostree_sysroot_upgrader_get_origin (upgrader); origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error)) goto out; /* Allow just switching remotes */ if (g_str_has_suffix (new_provided_refspec, ":")) { new_remote = g_strdup (new_provided_refspec); new_remote[strlen(new_remote)-1] = '\0'; new_ref = g_strdup (origin_ref); } else { if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error)) goto out; } if (!new_remote) new_refspec = g_strconcat (origin_remote, ":", new_ref, NULL); else new_refspec = g_strconcat (new_remote, ":", new_ref, NULL); if (strcmp (origin_refspec, new_refspec) == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Old and new refs are equal: %s", new_refspec); goto out; } new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error)) goto out; console = gs_console_get (); if (console) { gs_console_begin_status_line (console, "", NULL, NULL); in_status_line = TRUE; progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console); } /* Always allow older...there's not going to be a chronological * relationship necessarily. */ if (!ostree_sysroot_upgrader_pull (upgrader, 0, OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER, progress, &changed, cancellable, error)) goto out; if (in_status_line) { gs_console_end_status_line (console, NULL, NULL); in_status_line = FALSE; } if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) goto out; if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) goto out; g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref); ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL); if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) goto out; { gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/"); if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot)) { gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT, cancellable, error, "systemctl", "reboot", NULL); } } ret = TRUE; out: if (in_status_line) gs_console_end_status_line (console, NULL, NULL); if (new_origin) g_key_file_unref (new_origin); if (context) g_option_context_free (context); return ret; }