]> git.ipfire.org Git - pakfire.git/commitdiff
snapshot: Cleanup old snapshots
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 18 Oct 2024 14:59:35 +0000 (14:59 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 18 Oct 2024 14:59:35 +0000 (14:59 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/snapshot.h
src/libpakfire/pakfire.c
src/libpakfire/snapshot.c

index 0e540b3cc25241e40de17e1c563ae7186925cda9..e7fa1018bf10c17b28df5985d24cab4a500c8e99 100644 (file)
@@ -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 */
index d17176e5924fdfce77a9824dd149bf864f847144..5884d6aacfb0a78b1b8a2a2e79421643ca44777e 100644 (file)
@@ -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)
index 80b8b1f11ba4d85c8d39822bd52ebb0167d184cc..599936b1f2a808bd46b4a0a09670a4a37f86b0af 100644 (file)
 #############################################################################*/
 
 #include <errno.h>
+#include <fts.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <linux/limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/file.h>
 #include <sys/mount.h>
 
 #include <pakfire/logging.h>
@@ -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;
+}