]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
Add scripts/snapper-sync to sync highest snapshot number
authorCheng-Ling Lai <jameslai.tech@gmail.com>
Tue, 21 Apr 2026 09:18:37 +0000 (17:18 +0800)
committerCheng-Ling Lai <jameslai.tech@gmail.com>
Thu, 23 Apr 2026 08:46:50 +0000 (16:46 +0800)
scripts/Makefile.am
scripts/snapper-sync [new file with mode: 0755]

index 48a379658b0f107b9ab6ca1b79722d2b98ec3fd7..ecdd04b8274cc13644faf84377799dbe8d553ca0 100644 (file)
@@ -16,7 +16,8 @@ pam_snapper_SCRIPTS =                 \
 
 endif
 
-EXTRA_DIST = snapper-hourly $(pam_snapper_SCRIPTS)
+EXTRA_DIST = snapper-hourly snapper-sync $(pam_snapper_SCRIPTS)
 
 install-data-local:
        install -D snapper-hourly $(DESTDIR)/etc/cron.hourly/suse.de-snapper
+       install -D snapper-sync $(DESTDIR)/usr/sbin
diff --git a/scripts/snapper-sync b/scripts/snapper-sync
new file mode 100755 (executable)
index 0000000..b49d07b
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+set -eu
+
+# Check for the required binaries
+check_binary() {
+  command -v "$1" >/dev/null 2>&1 || {
+    echo >&2 "Error: '$1' is required but not found in PATH."
+    exit 1
+  }
+}
+
+check_binary jq
+check_binary mkdir
+check_binary snapper
+check_binary snbk
+
+# Construct a list of dictionaries containing the necessary snapshot information,
+# including the name of the backup-config, the name of the source-config, and the snapshot
+# number
+config_mapping=$(
+  snbk --machine-readable json list-configs |
+  jq -r '."backup-configs" | map({key: .name, value: .config}) | from_entries'
+)
+
+if outputs=$(snbk --machine-readable json list); then
+  snapshots=$(
+    echo $outputs |
+    jq --argjson config_mapping "$config_mapping" '
+      .snapshots | . |= map(. + {config: $config_mapping[.name]})
+    '
+  )
+else
+  echo >&2 "Error: 'snbk list' failed with exit status $?"
+  exit 1
+fi
+
+# Create the snapshot placeholder with the highest number if missing
+echo "$config_mapping" | jq -r 'keys[]' | while read -r backup_config; do
+
+  # Query the name of source-config for the currently processed backup-config
+  source_config=$(echo "$config_mapping" | jq -r ".[\"$backup_config\"]")
+
+  # Query the highest snapshot number across backup-configs with the same source-config
+  max_num=$(
+    echo "$snapshots" |
+    jq -r "[.[] | select(.config == \"$source_config\")] | max_by(.number) | .number"
+  )
+
+  # Query the source subvolume path
+  subvol_path=$(
+    snapper --machine-readable json -c "$source_config" get-config | jq -r '.SUBVOLUME'
+  )
+
+  # Check and make the snapshot placeholder with the highest number
+  target_path="$subvol_path/.snapshots/$max_num"
+  if [ -d "$target_path" ]; then
+    echo "$target_path exists."
+  else
+    mkdir "$target_path"
+    echo "$target_path created."
+  fi
+
+done