aboutsummaryrefslogtreecommitdiff
path: root/scripts/zfs-pre-snapshot
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/zfs-pre-snapshot')
-rwxr-xr-xscripts/zfs-pre-snapshot43
1 files changed, 43 insertions, 0 deletions
diff --git a/scripts/zfs-pre-snapshot b/scripts/zfs-pre-snapshot
new file mode 100755
index 0000000..ed914d0
--- /dev/null
+++ b/scripts/zfs-pre-snapshot
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Snapshot the root dataset before a pacman transaction, then prune to the most
+# recent $KEEP pre-pacman snapshots. Run from the zfs-snapshot.hook pacman hook
+# (PreTransaction). Sanoid doesn't manage these (they aren't autosnap_ names),
+# so retention is enforced here at creation time.
+#
+# Defaults match the live zroot layout; the ZFS_PRE_* env vars override them so
+# the pruning logic is unit-testable against a fake zfs on PATH.
+
+POOL="${ZFS_PRE_POOL:-zroot}"
+DATASET="${ZFS_PRE_DATASET:-$POOL/ROOT/default}"
+LOCKFILE="${ZFS_PRE_LOCKFILE:-/tmp/.zfs-pre-snapshot.lock}"
+MIN_INTERVAL="${ZFS_PRE_MIN_INTERVAL:-60}"
+KEEP="${ZFS_PRE_KEEP:-10}" # pre-pacman snapshots to retain (recent-transaction rollback)
+
+# Skip if a snapshot was created within the last $MIN_INTERVAL seconds. A single
+# pacman invocation can fire several transactions; this stops a burst of them
+# from each cutting a near-identical snapshot.
+if [ -f "$LOCKFILE" ]; then
+ last=$(stat -c %Y "$LOCKFILE" 2>/dev/null || echo 0)
+ now=$(date +%s)
+ if (( now - last < MIN_INTERVAL )); then
+ exit 0
+ fi
+fi
+
+TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
+SNAPSHOT_NAME="pre-pacman_$TIMESTAMP"
+
+if zfs snapshot "$DATASET@$SNAPSHOT_NAME"; then
+ echo "Created snapshot: $DATASET@$SNAPSHOT_NAME"
+ touch "$LOCKFILE"
+
+ # Keep only the most recent $KEEP pre-pacman snapshots; destroy older ones.
+ zfs list -H -o name -t snapshot -s creation "$DATASET" 2>/dev/null \
+ | grep '@pre-pacman_' \
+ | head -n -"$KEEP" \
+ | while read -r old; do
+ zfs destroy "$old" && echo "Pruned old snapshot: $old"
+ done
+else
+ echo "Warning: Failed to create snapshot" >&2
+fi