From d6ebbc6ddfb6488a57fc68a9e05dc7542331cb8c Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 18 Oct 2024 14:59:35 +0000 Subject: [PATCH] snapshot: Cleanup old snapshots Signed-off-by: Michael Tremer --- src/libpakfire/include/pakfire/snapshot.h | 2 + src/libpakfire/pakfire.c | 5 + src/libpakfire/snapshot.c | 125 +++++++++++++++++++++- 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/libpakfire/include/pakfire/snapshot.h b/src/libpakfire/include/pakfire/snapshot.h index 0e540b3cc..e7fa1018b 100644 --- a/src/libpakfire/include/pakfire/snapshot.h +++ b/src/libpakfire/include/pakfire/snapshot.h @@ -45,5 +45,7 @@ int pakfire_snapshot_umount(struct pakfire_snapshot* snapshot); int pakfire_snapshot_make(struct pakfire_snapshot** snapshot, struct pakfire* pakfire, const char** packages); +int pakfire_snapshot_clean(struct pakfire* pakfire); + #endif /* PAKFIRE_PRIVATE */ #endif /* PAKFIRE_SNAPSHOT_H */ diff --git a/src/libpakfire/pakfire.c b/src/libpakfire/pakfire.c index d17176e59..5884d6aac 100644 --- a/src/libpakfire/pakfire.c +++ b/src/libpakfire/pakfire.c @@ -1117,6 +1117,11 @@ PAKFIRE_EXPORT int pakfire_clean(struct pakfire* pakfire, int flags) { if (r) return r; + // Clean all snapshots + r = pakfire_snapshot_clean(pakfire); + if (r < 0) + return r; + // Clean build environments r = pakfire_build_clean(pakfire, flags); if (r) diff --git a/src/libpakfire/snapshot.c b/src/libpakfire/snapshot.c index 80b8b1f11..599936b1f 100644 --- a/src/libpakfire/snapshot.c +++ b/src/libpakfire/snapshot.c @@ -19,11 +19,13 @@ #############################################################################*/ #include +#include #include #include #include #include #include +#include #include #include @@ -53,6 +55,7 @@ struct pakfire_snapshot { PAKFIRE_SNAPSHOT_INIT = 0, PAKFIRE_SNAPSHOT_MOUNTED, PAKFIRE_SNAPSHOT_UMOUNTED, + PAKFIRE_SNAPSHOT_DESTROYED, } state; }; @@ -96,7 +99,13 @@ int pakfire_snapshot_create( goto ERROR; } - // XXX Check and lock the snapshot + // Lock the snapshot + r = flock(s->fd, LOCK_SH); + if (r < 0) { + CTX_ERROR(s->ctx, "Could not lock %s: %m\n", s->path); + r = -errno; + goto ERROR; + } // Return the snapshot *snapshot = pakfire_snapshot_ref(s); @@ -350,6 +359,53 @@ int pakfire_snapshot_umount(struct pakfire_snapshot* snapshot) { return 0; } +static int pakfire_snapshot_destroy(struct pakfire_snapshot* snapshot) { + int r; + + // Check if the snapshot is mounted + switch (snapshot->state) { + case PAKFIRE_SNAPSHOT_MOUNTED: + CTX_DEBUG(snapshot->ctx, "Snapshot is mounted\n"); + return -EBUSY; + + default: + break; + } + + /* + Try to get an exclusive lock on the directory. + + If this fails, another process is using this snapshot. + */ + r = flock(snapshot->fd, LOCK_EX|LOCK_NB); + if (r < 0) { + switch (errno) { + case EWOULDBLOCK: + return -EBUSY; + + default: + CTX_DEBUG(snapshot->ctx, + "Could not acquire an exclusive lock on %s: %m\n", snapshot->path); + break; + } + } + + CTX_INFO(snapshot->ctx, "Destroying snapshot %s\n", snapshot->path); + + // Remove all files + r = pakfire_rmtree(snapshot->path, 0); + if (r < 0) { + CTX_ERROR(snapshot->ctx, "Could not destroy snapshot %s: %s\n", + snapshot->path, strerror(-r)); + return r; + } + + // Mark as destroyed + snapshot->state = PAKFIRE_SNAPSHOT_DESTROYED; + + return 0; +} + static int pakfire_snapshot_install_packages(struct pakfire* pakfire, const char** packages) { struct pakfire_transaction* transaction = NULL; int r; @@ -465,3 +521,70 @@ ERROR: return r; } + +/* + Cleans up any unused snapshots +*/ +int pakfire_snapshot_clean(struct pakfire* pakfire) { + struct pakfire_snapshot* snapshot = NULL; + char path[PATH_MAX]; + FTS* f = NULL; + int r; + + struct pakfire_ctx* ctx = pakfire_ctx(pakfire); + + // Make the path + r = pakfire_cache_path(pakfire, path, "%s", "snapshots"); + if (r < 0) + return r; + + char* paths[] = { + path, NULL, + }; + + // Open the directory + f = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, NULL); + + for (;;) { + FTSENT* node = fts_read(f); + if (!node) + break; + + // Skip the main directory + if (node->fts_level == 0) { + continue; + + // Skip any subdirectories + } else if (node->fts_level > 1) { + fts_set(f, node, FTS_SKIP); + continue; + } + + // We only care about directories + if (node->fts_info == FTS_D) + continue; + + // Open the snapshot + r = pakfire_snapshot_create(&snapshot, ctx, node->fts_path); + if (r < 0) + goto ERROR; + + // Destroy the snapshot + r = pakfire_snapshot_destroy(snapshot); + if (r < 0) + goto ERROR; + + // Free the snapshot + snapshot = pakfire_snapshot_unref(snapshot); + } + +ERROR: + if (snapshot) + pakfire_snapshot_unref(snapshot); + if (ctx) + pakfire_ctx_unref(ctx); + if (f) + fts_close(f); + + return r; +} -- 2.39.5