|
rpm-build |
0fba15 |
/*
|
|
rpm-build |
0fba15 |
* Copyright (C) 2013 Colin Walters <walters@verbum.org>
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* SPDX-License-Identifier: LGPL-2.0+
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* This library is free software; you can redistribute it and/or
|
|
rpm-build |
0fba15 |
* modify it under the terms of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
* License as published by the Free Software Foundation; either
|
|
rpm-build |
0fba15 |
* version 2 of the License, or (at your option) any later version.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
0fba15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
0fba15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
0fba15 |
* Lesser General Public License for more details.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
* License along with this library; if not, write to the
|
|
rpm-build |
0fba15 |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
rpm-build |
0fba15 |
* Boston, MA 02111-1307, USA.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "config.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "otutil.h"
|
|
rpm-build |
0fba15 |
#include "ostree-repo-private.h"
|
|
rpm-build |
0fba15 |
#include "ostree-linuxfsutil.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "ostree-sysroot-private.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* @deploydir_dfd: Directory FD for ostree/deploy
|
|
rpm-build |
0fba15 |
* @osname: Target osname
|
|
rpm-build |
0fba15 |
* @inout_deployments: All deployments in this subdir will be appended to this array
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd,
|
|
rpm-build |
0fba15 |
const char *osname,
|
|
rpm-build |
0fba15 |
GPtrArray *inout_deployments,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
|
rpm-build |
0fba15 |
gboolean exists;
|
|
rpm-build |
0fba15 |
const char *osdeploy_path = glnx_strjoina (osname, "/deploy");
|
|
rpm-build |
0fba15 |
if (!ot_dfd_iter_init_allow_noent (deploydir_dfd, osdeploy_path, &dfd_iter, &exists, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (!exists)
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
while (TRUE)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
struct dirent *dent;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (dent == NULL)
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (dent->d_type != DT_DIR)
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_autofree char *csum = NULL;
|
|
rpm-build |
0fba15 |
gint deployserial;
|
|
rpm-build |
0fba15 |
if (!_ostree_sysroot_parse_deploy_path_name (dent->d_name, &csum, &deployserial, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_ptr_array_add (inout_deployments, ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Return in @out_deployments a new array of OstreeDeployment loaded from the
|
|
rpm-build |
0fba15 |
* filesystem state.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
list_all_deployment_directories (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
GPtrArray **out_deployments,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autoptr(GPtrArray) ret_deployments =
|
|
rpm-build |
0fba15 |
g_ptr_array_new_with_free_func (g_object_unref);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
|
rpm-build |
0fba15 |
gboolean exists;
|
|
rpm-build |
0fba15 |
if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, "ostree/deploy", &dfd_iter, &exists, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (!exists)
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
while (TRUE)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
struct dirent *dent;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (dent == NULL)
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (dent->d_type != DT_DIR)
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!_ostree_sysroot_list_deployment_dirs_for_os (dfd_iter.fd, dent->d_name,
|
|
rpm-build |
0fba15 |
ret_deployments,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
ot_transfer_out_value (out_deployments, &ret_deployments);
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
parse_bootdir_name (const char *name,
|
|
rpm-build |
0fba15 |
char **out_osname,
|
|
rpm-build |
0fba15 |
char **out_csum)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const char *lastdash;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (out_osname)
|
|
rpm-build |
0fba15 |
*out_osname = NULL;
|
|
rpm-build |
0fba15 |
if (out_csum)
|
|
rpm-build |
0fba15 |
*out_csum = NULL;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
lastdash = strrchr (name, '-');
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!lastdash)
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ostree_validate_checksum_string (lastdash + 1, NULL))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (out_osname)
|
|
rpm-build |
0fba15 |
*out_osname = g_strndup (name, lastdash - name);
|
|
rpm-build |
0fba15 |
if (out_csum)
|
|
rpm-build |
0fba15 |
*out_csum = g_strdup (lastdash + 1);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
list_all_boot_directories (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
GPtrArray **out_bootdirs,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
gboolean ret = FALSE;
|
|
rpm-build |
0fba15 |
g_autoptr(GFile) boot_ostree = NULL;
|
|
rpm-build |
0fba15 |
g_autoptr(GPtrArray) ret_bootdirs = NULL;
|
|
rpm-build |
0fba15 |
GError *temp_error = NULL;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
boot_ostree = g_file_resolve_relative_path (self->path, "boot/ostree");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_autoptr(GFileEnumerator) dir_enum =
|
|
rpm-build |
0fba15 |
g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO,
|
|
rpm-build |
0fba15 |
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
|
rpm-build |
0fba15 |
cancellable, &temp_error);
|
|
rpm-build |
0fba15 |
if (!dir_enum)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_clear_error (&temp_error);
|
|
rpm-build |
0fba15 |
goto done;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_propagate_error (error, temp_error);
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
while (TRUE)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GFileInfo *file_info = NULL;
|
|
rpm-build |
0fba15 |
GFile *child = NULL;
|
|
rpm-build |
0fba15 |
const char *name;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!g_file_enumerator_iterate (dir_enum, &file_info, &child,
|
|
rpm-build |
0fba15 |
NULL, error))
|
|
rpm-build |
0fba15 |
goto out;
|
|
rpm-build |
0fba15 |
if (file_info == NULL)
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Only look at directories ending in -CHECKSUM; nothing else
|
|
rpm-build |
0fba15 |
* should be in here, but let's be conservative.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
name = g_file_info_get_name (file_info);
|
|
rpm-build |
0fba15 |
if (!parse_bootdir_name (name, NULL, NULL))
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_ptr_array_add (ret_bootdirs, g_object_ref (child));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
done:
|
|
rpm-build |
0fba15 |
ret = TRUE;
|
|
rpm-build |
0fba15 |
ot_transfer_out_value (out_bootdirs, &ret_bootdirs);
|
|
rpm-build |
0fba15 |
out:
|
|
rpm-build |
0fba15 |
return ret;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* A sysroot has at most one active "boot version" (pair of version,subversion)
|
|
rpm-build |
0fba15 |
* out of a total of 4 possible. This function deletes from the filesystem the 3
|
|
rpm-build |
0fba15 |
* other versions that aren't active.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
cleanup_other_bootversions (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const int cleanup_bootversion = self->bootversion == 0 ? 1 : 0;
|
|
rpm-build |
0fba15 |
const int cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0;
|
|
rpm-build |
0fba15 |
/* Reusable buffer for path */
|
|
rpm-build |
0fba15 |
g_autoptr(GString) buf = g_string_new ("");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* These directories are for the other major version */
|
|
rpm-build |
0fba15 |
g_string_truncate (buf, 0); g_string_append_printf (buf, "boot/loader.%d", cleanup_bootversion);
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d", cleanup_bootversion);
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.0", cleanup_bootversion);
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.1", cleanup_bootversion);
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* And finally the other subbootversion */
|
|
rpm-build |
0fba15 |
g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion);
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Delete a deployment directory */
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
_ostree_sysroot_rmrf_deployment (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
OstreeDeployment *deployment,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autofree char *origin_relpath = ostree_deployment_get_origin_relpath (deployment);
|
|
rpm-build |
0fba15 |
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
|
rpm-build |
0fba15 |
struct stat stbuf;
|
|
rpm-build |
0fba15 |
glnx_autofd int deployment_fd = -1;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE,
|
|
rpm-build |
0fba15 |
&deployment_fd, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!glnx_fstat (deployment_fd, &stbuf, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* This shouldn't happen, because higher levels should
|
|
rpm-build |
0fba15 |
* disallow having the booted deployment not in the active
|
|
rpm-build |
0fba15 |
* deployment list, but let's be extra safe. */
|
|
rpm-build |
0fba15 |
if (stbuf.st_dev == self->root_device &&
|
|
rpm-build |
0fba15 |
stbuf.st_ino == self->root_inode)
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* This deployment wasn't referenced, so delete it */
|
|
rpm-build |
0fba15 |
if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* As the bootloader configuration changes, we will have leftover deployments
|
|
rpm-build |
0fba15 |
* on disk. This function deletes all deployments which aren't actively
|
|
rpm-build |
0fba15 |
* referenced.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
cleanup_old_deployments (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
/* Gather the device/inode of the rootfs, so we can double
|
|
rpm-build |
0fba15 |
* check we won't delete it.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
struct stat root_stbuf;
|
|
rpm-build |
0fba15 |
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Load all active deployments referenced by bootloader configuration. */
|
|
rpm-build |
0fba15 |
g_autoptr(GHashTable) active_deployment_dirs =
|
|
rpm-build |
0fba15 |
g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL);
|
|
rpm-build |
0fba15 |
g_autoptr(GHashTable) active_boot_checksums =
|
|
rpm-build |
0fba15 |
g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL);
|
|
rpm-build |
0fba15 |
for (guint i = 0; i < self->deployments->len; i++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeDeployment *deployment = self->deployments->pdata[i];
|
|
rpm-build |
0fba15 |
char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
|
rpm-build |
0fba15 |
char *bootcsum = g_strdup (ostree_deployment_get_bootcsum (deployment));
|
|
rpm-build |
0fba15 |
/* Transfer ownership */
|
|
rpm-build |
0fba15 |
g_hash_table_replace (active_deployment_dirs, deployment_path, deployment_path);
|
|
rpm-build |
0fba15 |
g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Find all deployment directories, both active and inactive */
|
|
rpm-build |
0fba15 |
g_autoptr(GPtrArray) all_deployment_dirs = NULL;
|
|
rpm-build |
0fba15 |
if (!list_all_deployment_directories (self, &all_deployment_dirs,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
g_assert (all_deployment_dirs); /* Pacify static analysis */
|
|
rpm-build |
0fba15 |
for (guint i = 0; i < all_deployment_dirs->len; i++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeDeployment *deployment = all_deployment_dirs->pdata[i];
|
|
rpm-build |
0fba15 |
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (g_hash_table_lookup (active_deployment_dirs, deployment_path))
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!_ostree_sysroot_rmrf_deployment (self, deployment, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Clean up boot directories */
|
|
rpm-build |
0fba15 |
g_autoptr(GPtrArray) all_boot_dirs = NULL;
|
|
rpm-build |
0fba15 |
if (!list_all_boot_directories (self, &all_boot_dirs,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
for (guint i = 0; i < all_boot_dirs->len; i++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GFile *bootdir = all_boot_dirs->pdata[i];
|
|
rpm-build |
0fba15 |
g_autofree char *osname = NULL;
|
|
rpm-build |
0fba15 |
g_autofree char *bootcsum = NULL;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!parse_bootdir_name (glnx_basename (gs_file_get_path_cached (bootdir)),
|
|
rpm-build |
0fba15 |
&osname, &bootcsum))
|
|
rpm-build |
0fba15 |
g_assert_not_reached ();
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (g_hash_table_lookup (active_boot_checksums, bootcsum))
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (bootdir), cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Delete the ref bindings for a non-active boot version */
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
cleanup_ref_prefix (OstreeRepo *repo,
|
|
rpm-build |
0fba15 |
int bootversion,
|
|
rpm-build |
0fba15 |
int subbootversion,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autofree char *prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion);
|
|
rpm-build |
0fba15 |
g_autoptr(GHashTable) refs = NULL;
|
|
rpm-build |
0fba15 |
if (!ostree_repo_list_refs_ext (repo, prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
GLNX_HASH_TABLE_FOREACH (refs, const char *, ref)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!ostree_repo_set_ref_immediate (repo, NULL, ref, NULL, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* libostree holds a ref for each deployment's exact checksum to avoid it being
|
|
rpm-build |
0fba15 |
* GC'd even if the origin ref changes. This function resets those refs
|
|
rpm-build |
0fba15 |
* to match active deployments.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
generate_deployment_refs (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
OstreeRepo *repo,
|
|
rpm-build |
0fba15 |
int bootversion,
|
|
rpm-build |
0fba15 |
int subbootversion,
|
|
rpm-build |
0fba15 |
GPtrArray *deployments,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
int cleanup_bootversion = (bootversion == 0) ? 1 : 0;
|
|
rpm-build |
0fba15 |
int cleanup_subbootversion = (subbootversion == 0) ? 1 : 0;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!cleanup_ref_prefix (repo, cleanup_bootversion, 0,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!cleanup_ref_prefix (repo, cleanup_bootversion, 1,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!cleanup_ref_prefix (repo, bootversion, cleanup_subbootversion,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_autoptr(_OstreeRepoAutoTransaction) txn =
|
|
rpm-build |
0fba15 |
_ostree_repo_auto_transaction_start (repo, cancellable, error);
|
|
rpm-build |
0fba15 |
if (!txn)
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
for (guint i = 0; i < deployments->len; i++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeDeployment *deployment = deployments->pdata[i];
|
|
rpm-build |
0fba15 |
g_autofree char *refname = g_strdup_printf ("ostree/%d/%d/%u",
|
|
rpm-build |
0fba15 |
bootversion, subbootversion,
|
|
rpm-build |
0fba15 |
i);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
ostree_repo_transaction_set_refspec (repo, refname, ostree_deployment_get_csum (deployment));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/**
|
|
rpm-build |
0fba15 |
* ostree_sysroot_cleanup_prune_repo:
|
|
rpm-build |
0fba15 |
* @sysroot: Sysroot
|
|
rpm-build |
0fba15 |
* @options: Flags controlling pruning
|
|
rpm-build |
0fba15 |
* @out_objects_total: (out): Number of objects found
|
|
rpm-build |
0fba15 |
* @out_objects_pruned: (out): Number of objects deleted
|
|
rpm-build |
0fba15 |
* @out_pruned_object_size_total: (out): Storage size in bytes of objects deleted
|
|
rpm-build |
0fba15 |
* @cancellable: Cancellable
|
|
rpm-build |
0fba15 |
* @error: Error
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* Prune the system repository. This is a thin wrapper
|
|
rpm-build |
0fba15 |
* around ostree_repo_prune_from_reachable(); the primary
|
|
rpm-build |
0fba15 |
* addition is that this function automatically gathers
|
|
rpm-build |
0fba15 |
* all deployed commits into the reachable set.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* You generally want to at least set the `OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY`
|
|
rpm-build |
0fba15 |
* flag in @options. A commit traversal depth of `0` is assumed.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* Locking: exclusive
|
|
rpm-build |
0fba15 |
* Since: 2018.6
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
ostree_sysroot_cleanup_prune_repo (OstreeSysroot *sysroot,
|
|
rpm-build |
0fba15 |
OstreeRepoPruneOptions *options,
|
|
rpm-build |
0fba15 |
gint *out_objects_total,
|
|
rpm-build |
0fba15 |
gint *out_objects_pruned,
|
|
rpm-build |
0fba15 |
guint64 *out_pruned_object_size_total,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GLNX_AUTO_PREFIX_ERROR ("Pruning system repository", error);
|
|
rpm-build |
0fba15 |
OstreeRepo *repo = ostree_sysroot_repo (sysroot);
|
|
rpm-build |
0fba15 |
const guint depth = 0; /* Historical default */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!_ostree_sysroot_ensure_writable (sysroot, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Hold an exclusive lock by default across gathering refs and doing
|
|
rpm-build |
0fba15 |
* the prune.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
g_autoptr(OstreeRepoAutoLock) lock =
|
|
rpm-build |
0fba15 |
_ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
|
|
rpm-build |
0fba15 |
if (!lock)
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Ensure reachable has refs, but default to depth 0. This is
|
|
rpm-build |
0fba15 |
* what we've always done for the system repo, but perhaps down
|
|
rpm-build |
0fba15 |
* the line we could add a depth flag to the repo config or something?
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
if (!ostree_repo_traverse_reachable_refs (repo, depth, options->reachable, cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Since ostree was created we've been generating "deployment refs" in
|
|
rpm-build |
0fba15 |
* generate_deployment_refs() that look like ostree/0/1 etc. to ensure that
|
|
rpm-build |
0fba15 |
* anything doing a direct prune won't delete commits backing deployments.
|
|
rpm-build |
0fba15 |
* This bit might allow us to eventually drop that behavior, although we'd
|
|
rpm-build |
0fba15 |
* have to be very careful to ensure that all software is updated to use
|
|
rpm-build |
0fba15 |
* `ostree_sysroot_cleanup_prune_repo()`.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
for (guint i = 0; i < sysroot->deployments->len; i++)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const char *checksum = ostree_deployment_get_csum (sysroot->deployments->pdata[i]);
|
|
rpm-build |
0fba15 |
if (!ostree_repo_traverse_commit_union (repo, checksum, depth, options->reachable,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ostree_repo_prune_from_reachable (repo, options,
|
|
rpm-build |
0fba15 |
out_objects_total, out_objects_pruned,
|
|
rpm-build |
0fba15 |
out_pruned_object_size_total,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/**
|
|
rpm-build |
0fba15 |
* ostree_sysroot_cleanup:
|
|
rpm-build |
0fba15 |
* @self: Sysroot
|
|
rpm-build |
0fba15 |
* @cancellable: Cancellable
|
|
rpm-build |
0fba15 |
* @error: Error
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* Delete any state that resulted from a partially completed
|
|
rpm-build |
0fba15 |
* transaction, such as incomplete deployments.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
ostree_sysroot_cleanup (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
return _ostree_sysroot_cleanup_internal (self, TRUE, cancellable, error);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/**
|
|
rpm-build |
0fba15 |
* ostree_sysroot_prepare_cleanup:
|
|
rpm-build |
0fba15 |
* @self: Sysroot
|
|
rpm-build |
0fba15 |
* @cancellable: Cancellable
|
|
rpm-build |
0fba15 |
* @error: Error
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* Like ostree_sysroot_cleanup() in that it cleans up incomplete deployments
|
|
rpm-build |
0fba15 |
* and old boot versions, but does NOT prune the repository.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
ostree_sysroot_prepare_cleanup (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
return _ostree_sysroot_cleanup_internal (self, FALSE, cancellable, error);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
_ostree_sysroot_cleanup_internal (OstreeSysroot *self,
|
|
rpm-build |
0fba15 |
gboolean do_prune_repo,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_return_val_if_fail (OSTREE_IS_SYSROOT (self), FALSE);
|
|
rpm-build |
0fba15 |
g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, FALSE);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!_ostree_sysroot_ensure_writable (self, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!cleanup_other_bootversions (self, cancellable, error))
|
|
rpm-build |
0fba15 |
return glnx_prefix_error (error, "Cleaning bootversions");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!cleanup_old_deployments (self, cancellable, error))
|
|
rpm-build |
0fba15 |
return glnx_prefix_error (error, "Cleaning deployments");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
OstreeRepo *repo = ostree_sysroot_repo (self);
|
|
rpm-build |
0fba15 |
if (!generate_deployment_refs (self, repo,
|
|
rpm-build |
0fba15 |
self->bootversion,
|
|
rpm-build |
0fba15 |
self->subbootversion,
|
|
rpm-build |
0fba15 |
self->deployments,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return glnx_prefix_error (error, "Generating deployment refs");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (do_prune_repo)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
gint n_objects_total;
|
|
rpm-build |
0fba15 |
gint n_objects_pruned;
|
|
rpm-build |
0fba15 |
guint64 freed_space;
|
|
rpm-build |
0fba15 |
g_autoptr(GHashTable) reachable = ostree_repo_traverse_new_reachable ();
|
|
rpm-build |
0fba15 |
OstreeRepoPruneOptions opts = { OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY, reachable };
|
|
rpm-build |
0fba15 |
if (!ostree_sysroot_cleanup_prune_repo (self, &opts, &n_objects_total,
|
|
rpm-build |
0fba15 |
&n_objects_pruned, &freed_space,
|
|
rpm-build |
0fba15 |
cancellable, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* TODO remove printf in library */
|
|
rpm-build |
0fba15 |
if (freed_space > 0)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autofree char *freed_space_str = g_format_size_full (freed_space, 0);
|
|
rpm-build |
0fba15 |
g_print ("Freed objects: %s\n", freed_space_str);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|