Handle nested subvolumes & remove broken git exclusion
All checks were successful
ShellCheck / shellcheck (push) Successful in 5s
Docker / build (push) Successful in 18s

This commit is contained in:
Andras Schmelczer 2026-09-27 14:58:14 +01:00
commit 88aed211de

88
src/interval.sh Executable file
View file

@ -0,0 +1,88 @@
#!/bin/bash
# Return whole seconds and a fractional part without floating-point rounding.
# Long multiplication keeps the range checks exact even for tiny fractions.
interval_duration() {
local value=$1 whole fraction multiplier carry=0 product='' digit index
if [[ ! $value =~ ^([0-9]+([.][0-9]*)?|[.][0-9]+)([smhd]?)$ ]]; then
echo 'SLEEP_TIME must be a positive duration in seconds, minutes, hours or days.' >&2
return 1
fi
case ${BASH_REMATCH[3]} in
''|s) multiplier=1 ;;
m) multiplier=60 ;;
h) multiplier=3600 ;;
d) multiplier=86400 ;;
esac
value=${BASH_REMATCH[1]}
whole=${value%%.*}
whole=${whole#"${whole%%[!0]*}"}
whole=${whole:-0}
if (( ${#whole} > 10 )); then
echo 'SLEEP_TIME must represent between 1 and 2147483647 seconds.' >&2
return 1
fi
fraction=''
[[ $value != *.* ]] || fraction=${value#*.}
for ((index = ${#fraction} - 1; index >= 0; index--)); do
digit=$((10#${fraction:index:1} * multiplier + carry))
product="$((digit % 10))$product"
carry=$((digit / 10))
done
whole=$((10#$whole * multiplier + carry))
product=${product%"${product##*[!0]}"}
if (( whole < 1 || whole > 2147483647 )) || { (( whole == 2147483647 )) && [[ -n $product ]]; }; then
echo 'SLEEP_TIME must represent between 1 and 2147483647 seconds.' >&2
return 1
fi
printf '%s %s\n' "$whole" "${product:-0}"
}
# /proc/uptime advances independently of wall-clock adjustments, in 10 ms ticks.
interval_now() {
local uptime _idle whole fraction
read -r uptime _idle < /proc/uptime || return 1
whole=${uptime%.*}
fraction=${uptime#*.}00
printf '%s\n' "$((10#$whole * 100 + 10#${fraction:0:2}))"
}
interval_budget() {
local duration
duration=$(interval_duration "$1") || return 1
printf '%s\n' "${duration%% *}"
}
interval_deadline() {
local duration whole fraction ticks now
duration=$(interval_duration "$1") || return 1
read -r whole fraction <<< "$duration"
fraction+='00'
ticks=$((whole * 100 + 10#${fraction:0:2}))
# Round up fractions and the current clock tick to preserve the minimum wait.
[[ ${fraction:2} != *[1-9]* ]] || ticks=$((ticks + 1))
now=$(interval_now) || return 1
printf '%s\n' "$((now + ticks + 1))"
}
interval_wait() {
local deadline=$1 now remaining delay
[[ $deadline =~ ^[0-9]{1,15}$ ]] || return 1
while true; do
now=$(interval_now) || return 1
remaining=$((10#$deadline - now))
(( remaining > 0 )) || return 0
printf -v delay '%d.%02d' "$((remaining / 100))" "$((remaining % 100))"
sleep "$delay" || return 1
done
}
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
case ${1:-} in
budget|deadline|wait)
[[ $# == 2 ]] || exit 1
"interval_$1" "$2"
;;
*) echo 'Expected budget, deadline or wait and a value.' >&2; exit 1 ;;
esac
fi