host info updates
[distro-setup] / check-subvol-stale
index f012c4f97459f38d0e24ff75df3f13c7fca68dfb..9b5e88da97df8d36736230f350b0bf8fbc0f1d89 100644 (file)
@@ -1,12 +1,19 @@
 #!/bin/bash
-# Copyright (C) 2016 Ian Kelling
-#
+# I, Ian Kelling, follow the GNU license recommendations at
+# https://www.gnu.org/licenses/license-recommendations.en.html. They
+# recommend that small programs, < 300 lines, be licensed under the
+# Apache License 2.0. This file contains or is part of one or more small
+# programs. If a small program grows beyond 300 lines, I plan to switch
+# its license to GPL.
+
+# Copyright 2024 Ian Kelling
+
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-#
+
 #     http://www.apache.org/licenses/LICENSE-2.0
-#
+
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # limitations under the License.
 
 
+
 [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
 
-source /usr/local/lib/err
+set -e; . /usr/local/lib/bash-bear; set +e
 
 shopt -s nullglob
 
@@ -77,9 +85,11 @@ stale-file() {
   fi
 
 }
+pre="check-subvol-stale:${SSH_CLIENT:+ $HOSTNAME:}"
+
 d() {
   if $verbose; then
-    printf "%s\n" "$*"
+    printf "$pre %s\n" "$*"
   fi
 }
 
@@ -97,8 +107,10 @@ mapper-dev() {
     done
   fi
 }
-
+tmpf=$(mktemp)
+d tmpf=$tmpf
 for d; do
+
   if $subvol_path; then
     svp=$d
     root_dir=${d%/*}
@@ -142,14 +154,55 @@ for d; do
     d "svp=$svp # subvolume path"
   fi
 
-  snaps=($root_dir/btrbk/$subvol_dir.20*) # Assumes we are in the 21st century.
-  if [[ ! ${snaps[*]} ]]; then
+  # note: relying on null glob
+  ls_args=($root_dir/btrbk/$subvol_dir.20*)
+  if (( ${#ls_args[@]} )); then
+    # Assumes we are in the 21st century.
+    ls -1dvrq $root_dir/btrbk/$subvol_dir.20* >$tmpf
+    mapfile -t snaps <$tmpf
+  else
     # no snapshots yet
-    # TODO: make this an error and override with a cli flag
+    # TODO: consider making this an error and override with a cli flag
     echo "$0: warning: no snapshots found at $root_dir/btrbk/$subvol_dir.20*. this is expected for a brand new volume"
     continue
   fi
 
+  # last_snap by date.
+  last_snap="${snaps[0]}"
+
+  case $last_snap in
+    $root_dir/btrbk/$subvol_dir.20*) : ;;
+    *)
+      echo "$0: error: unexpected last_snap:$last_snap"
+      exit 1
+      ;;
+  esac
+
+  d last_snap=$last_snap
+  ## alternate slower alternative which would not rely on ls sorting:
+  # last_snap=$(
+  #   for s in ${snaps[@]}; do
+  #     f=${s##*/}
+  #     unix_time=$(date -d $(sed -r  's/(.{4})(..)(.{5})(..)(.*)/\1-\2-\3:\4:\5/' <<<${f#$vol.}) +%s)
+  #     printf "%s %s\n" $unix_time $s # part of the pipeline
+  #     # sort will fail
+  #   done | sort -r | head -n 1 | awk '{print $2}' || [[ ${PIPESTATUS[1]} == 141 || ${PIPESTATUS[0]} == 32 ]]
+  #          )
+  # if [[ ! $last_snap ]]; then
+  #   # should not happen.
+  #   echo "$0: error: could not find latest snapshot for $svp among ${snaps[*]}" >&2
+  #   exit 1
+  # fi
+
+  if [[ ! -e $svp ]]; then
+    echo "$0: warning: subvol does not exist: $svp"
+    echo "$0 assuming this host was just for receiving and latest snap is freshest"
+    freshest_snap=$last_snap
+    stale=true
+    stale-file
+    continue
+  fi
+
   # get info on last received sub
   last_received=
   last_received_cgen=0
@@ -161,39 +214,17 @@ for d; do
       if [[ $cgen -gt $last_received_cgen ]]; then
         last_received_cgen=$cgen
         last_received=$f
+      elif [[ $last_received ]]; then
+        # optimization: we are looking in reverse order by date, so if
+        # we find one that has a lesser cgen, assume the rest will all
+        # be lesser.
+        break
       fi
     fi
   done
   d last_received_cgen=$last_received_cgen
   d last_received=$last_received
 
-  # Get last_snap by date.
-  # when a btrbk bugfix makes it into the distro,
-  # we might replace this with btrbk list latest /mnt/root/$vol | ...
-  last_snap=$(
-    for s in ${snaps[@]}; do
-      f=${s##*/}
-      unix_time=$(date -d $(sed -r  's/(.{4})(..)(.{5})(..)(.*)/\1-\2-\3:\4:\5/' <<<${f#$vol.}) +%s)
-      printf "%s %s\n" $unix_time $s # part of the pipeline
-      # sort will fail
-    done | sort -r | head -n 1 | awk '{print $2}' || [[ ${PIPESTATUS[1]} == 141 || ${PIPESTATUS[0]} == 32 ]]
-           )
-  if [[ ! $last_snap ]]; then
-    # should not happen.
-    echo "$0: error: could not find latest snapshot for $svp among ${snaps[*]}" >&2
-    exit 1
-  fi
-  d last_snap=$last_snap
-
-  if [[ ! -e $svp ]]; then
-    echo "$0: warning: subvol does not exist: $svp"
-    echo "$0 assuming this host was just for receiving and latest snap is freshest"
-    freshest_snap=$last_snap
-    stale=true
-    stale-file
-    continue
-  fi
-
 
   # if there is a last_received, we can assume stale or fresh if we are newer/older
   if [[ $last_received ]]; then
@@ -215,7 +246,7 @@ for d; do
   stale=true
   # fresh if $svp has $last_snap as a snapshot,
   if btrfs sub show $svp 2>/dev/null | sed '0,/^\s*Snapshot(s):/d;s/^\s*//' | \
-      grep -xF ${last_snap#$root_dir/} ; then
+      grep -xF ${last_snap#"$root_dir"/} >/dev/null; then
     stale=false
   else # or else $svp is a snapshot of $last_snap. we use a uuid
     # comparison, which if I remember from the docs, is a bit more
@@ -228,3 +259,4 @@ for d; do
 
   stale-file
 done
+rm $tmpf