diff --git a/man/ostree-admin-pin.xml b/man/ostree-admin-pin.xml index ba3aa4a0c9..78edde4705 100644 --- a/man/ostree-admin-pin.xml +++ b/man/ostree-admin-pin.xml @@ -58,8 +58,10 @@ License along with this library. If not, see . Ensures the deployment at INDEX, will not be garbage - collected by default. This is termed "pinning". If the + collected by default. This is termed "pinning". If the -u option is provided, undoes a pinning operation. + INDEX can be >= 0 or one of booted, pending or + rollback strings. diff --git a/src/ostree/ot-admin-builtin-pin.c b/src/ostree/ot-admin-builtin-pin.c index de219d7e43..2ed8fbb756 100644 --- a/src/ostree/ot-admin-builtin-pin.c +++ b/src/ostree/ot-admin-builtin-pin.c @@ -31,6 +31,53 @@ static gboolean opt_unpin; static GOptionEntry options[] = { { "unpin", 'u', 0, G_OPTION_ARG_NONE, &opt_unpin, "Unset pin", NULL }, { NULL } }; +static gint64 +get_deployment_index_for_type (OstreeSysroot *sysroot, const char *deploy_index_str) +{ + g_autoptr (GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); + OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + if (booted_deployment && deploy_index_str[0] == 'b') + return ostree_deployment_get_index (booted_deployment); + + g_autoptr (OstreeDeployment) pending_deployment = NULL; + g_autoptr (OstreeDeployment) rollback_deployment = NULL; + if (booted_deployment) + ostree_sysroot_query_deployments_for (sysroot, NULL, &pending_deployment, &rollback_deployment); + + if (pending_deployment && deploy_index_str[0] == 'p') + return ostree_deployment_get_index (pending_deployment); + else if (rollback_deployment && deploy_index_str[0] == 'r') + return ostree_deployment_get_index (rollback_deployment); + + return -1; +} + +static gboolean +do_pinning (OstreeSysroot *sysroot, const gint64 deploy_index, GError **error) +{ + g_autoptr (OstreeDeployment) target_deployment + = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); + if (!target_deployment) + return FALSE; + + const gboolean current_pin = ostree_deployment_is_pinned (target_deployment); + const gboolean desired_pin = !opt_unpin; + if (current_pin == desired_pin) + { + g_print ("Deployment %lld is already %s\n", (long long int)deploy_index, + current_pin ? "pinned" : "unpinned"); + return TRUE; + } + else if (ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, error)) + { + g_print ("Deployment %lld is now %s\n", (long long int)deploy_index, + desired_pin ? "pinned" : "unpinned"); + return TRUE; + } + + return FALSE; +} + gboolean ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) @@ -54,32 +101,25 @@ ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation char *endptr = NULL; errno = 0; - const guint64 deploy_index = g_ascii_strtoull (deploy_index_str, &endptr, 10); - if (*endptr != '\0') - return glnx_throw (error, "Invalid index: %s", deploy_index_str); - if (errno == ERANGE) - return glnx_throw (error, "Index too large: %s", deploy_index_str); - - g_autoptr (OstreeDeployment) target_deployment - = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); - if (!target_deployment) - return FALSE; - - gboolean current_pin = ostree_deployment_is_pinned (target_deployment); - const gboolean desired_pin = !opt_unpin; - if (current_pin == desired_pin) + gint64 deploy_index; + if (!g_strcmp0 (deploy_index_str, "booted") || !g_strcmp0 (deploy_index_str, "pending") + || !g_strcmp0 (deploy_index_str, "rollback")) { - g_print ("Deployment %s is already %s\n", deploy_index_str, - current_pin ? "pinned" : "unpinned"); + deploy_index = get_deployment_index_for_type (sysroot, deploy_index_str); + if (deploy_index < 0) + return glnx_throw (error, "Deployment type not found: %s", deploy_index_str); } else { - if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, - error)) - return FALSE; - g_print ("Deployment %s is now %s\n", deploy_index_str, - desired_pin ? "pinned" : "unpinned"); + deploy_index = g_ascii_strtoull (deploy_index_str, &endptr, 10); + if (*endptr != '\0') + return glnx_throw (error, "Invalid index: %s", deploy_index_str); + else if (errno == ERANGE) + return glnx_throw (error, "Index too large: %s", deploy_index_str); } + + if (!do_pinning (sysroot, deploy_index, error)) + return FALSE; } return TRUE; diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c index 68a54751f0..53face6a2d 100644 --- a/src/ostree/ot-builtin-admin.c +++ b/src/ostree/ot-builtin-admin.c @@ -53,7 +53,8 @@ static OstreeCommand admin_subcommands[] = { { "stateroot-init", OSTREE_BUILTIN_FLAG_NO_REPO, ot_admin_builtin_os_init, "Initialize empty state for given operating system" }, { "pin", OSTREE_BUILTIN_FLAG_NO_REPO, ot_admin_builtin_pin, - "Change the \"pinning\" state of a deployment" }, + "Change the \"pinning\" state of a deployment, INDEX can be >= 0 or one of booted, pending or " + "rollback strings" }, { "post-copy", OSTREE_BUILTIN_FLAG_NO_REPO, ot_admin_builtin_post_copy, "Update the repo and deployments as needed after a copy" }, { "set-origin", OSTREE_BUILTIN_FLAG_NO_REPO, ot_admin_builtin_set_origin,