From c42c9777a9c99afba359fcae8c145039e97cd818 Mon Sep 17 00:00:00 2001 From: David Kebler Date: Tue, 5 Mar 2024 13:50:09 -0800 Subject: [PATCH] add btrbk_named drop latest_clone add btrfs_clone and mp_subvol fix but s: to s in copy options add several path string helper function --- modules/filesystem/btrfs/btrbk.lib | 40 ++++++++++++++---- modules/filesystem/btrfs/btrfs.mod | 67 ++++++++++++++++++++++++++++-- modules/scripting/helpers.lib | 21 ++++++++++ modules/utility/copy.func | 2 +- 4 files changed, 118 insertions(+), 12 deletions(-) diff --git a/modules/filesystem/btrfs/btrbk.lib b/modules/filesystem/btrfs/btrbk.lib index 4774b73..0d3e951 100644 --- a/modules/filesystem/btrfs/btrbk.lib +++ b/modules/filesystem/btrfs/btrbk.lib @@ -11,6 +11,7 @@ btrbk_scripts_dir="$(dirname $(realpath "${BASH_SOURCE:-$0}"))" +module_load helpers # will try to find a conf file with out without .conf extension in a few places btrbk_conf () { @@ -128,12 +129,22 @@ btrbk_latest_links $([[ $dry_run ]] || printf "%s" -e) $file (return 0 2>/dev/null) || btrbk_run $@ -latest_clone () { +btrbk_named () { + + # btrfs subvolume list -o . -r --sort path,gen + # todo + # rw vs ro -r + # -f folder with extensions removed vs appended extension + # figure out latest instead of depending on .latest + # find unique names, then list and grep on those and use + # btrfs subvolume list -o . -r --sort path+gen - local src=$(realpath $1) - local dest=$(realpath $2) - shift 2 module_load confirm + local name; local names + local snapname=".latest" + [[ $1 == "-s" ]] && snapname="$2" && shift 2 + local src=$(realpath $1) + local dest=$(realpath $2) if [[ ! -d $dest ]]; then if confirm "destination directory $dest does not exist, create it"; then sudo mkdir -p $dest @@ -141,9 +152,23 @@ latest_clone () { return 1 fi fi - local snaps=$(ls $src | grep latest | sed 's/.\{1\}$//' | xargs -I % realpath $src/%) - [[ ! $snaps ]] && echo no latest snapshots in $src && ls -la $src && return 1 - if confirm create snapshots for $snaps in $dest; then + echo looking for snapshots in $src with extension matching $snapname + local snaps=$(ls $src | grep "\..*$snapname" | sed 's/.\{1\}$//' | xargs -I % realpath $src/%) + + # while read test; do + # echo $test + # done <<< "$( btrfs subvolume list -o . -r --sort path+gen | get just path | get only fname)" + + + [[ ! $snaps ]] && echo no snapshots with extension $snapname in $src && ls -la $src && return 1 + echo creating snapshots for + for snap in $snaps; do + name=$(get_only_fname $snap) + [[ $names == *"$name"* ]] && echo whoops! snapshots found for $(rm_ext $snap) using filter $snapname not unique, aborting && ls -la | grep $ && return 3 + names+=" $name" + echo $snap + done + if confirm in $dest; then local destsnap for snap in $snaps; do destsnap="$dest/$(basename $snap | cut -f 1 -d '.' )" @@ -156,6 +181,7 @@ latest_clone () { fi sudo btrfs subvolume snapshot $@ $snap $destsnap done + echo $dest ls -la $dest fi diff --git a/modules/filesystem/btrfs/btrfs.mod b/modules/filesystem/btrfs/btrfs.mod index dc229ec..1bde042 100644 --- a/modules/filesystem/btrfs/btrfs.mod +++ b/modules/filesystem/btrfs/btrfs.mod @@ -13,6 +13,7 @@ make_subvol() { [[ $EUID -ne 0 ]] && usesudo=sudo uid=${2:-$USER} gid=${3:-$uid} + mkdir -p $(dirname $1) &> /dev/null echo $usesudo $BTRFS_BIN subvolume create $1 $usesudo $BTRFS_BIN subvolume create $1 echo $usesudo chown $uid:$gid $1 @@ -112,12 +113,12 @@ folder_snapshot() { } mount_subvolume () { - echo sudo mount $1 -o subvol=$2 $3 - if mountpoint $3; then + # echo sudo mount $1 -o subvol=$2 $3 + if mountpoint $3 &> /dev/null; then echo $3 already a mountpoint, aborting subvolume mount else - mkdir -p $3 - sudo mount $1 -o subvol=$2 $3 + mkdir -p $3 &> /dev/null + if ! sudo mount $1 -o subvol=$2 $3 > /dev/null ; then echo "failed to mount $2"; return 1; fi fi } @@ -146,6 +147,64 @@ fi } + +# finds device and subvolume of a mountpoint (or a mountpoint above the given path) +mp_subvol () { + module_load filesystem + local mp; local subvol + mp=$(find_mountpoint $1) + path=${1//"$mp"/} + dev=$(mount | grep "$mp " | cut -f 1 -d ' ') + IFS=, read -r -a input <<< $(findmnt -nt btrfs | grep "$mp ") + for x in "${input[@]}"; do + eval $(echo $x | grep subvol=) + [[ $subvol ]] && echo $dev $subvol$path + done +} + +btrfs_clone () { + # btrfs_clone + # if [[ $# == "3" ]]; then + module_load filesystem + local src; local dest; local dr; local usesudo + [[ $EUID -ne 0 ]] && usesudo=sudo + dr="--dry-run" + [[ $1 == "-r" ]] && dr="" && shift + subvol=$1 + src=$2 + dest=$3 + $usesudo umount /tmp/source &> /dev/null + sudo mount $src /tmp/source + # $usesudo umount /tmp/dest &> /dev/null + # if mount_subvolume $src $subvol /tmp/source; then + if ! make_subvol $dest/$(basename $subvol) &> /dev/null; then echo unable to make subvolume $1 at $dest; return 2; fi + # $usesudo btrfs subvolume show $dest/$(basename $subvol) + # if mount_subvolume $(mp_subvol $dest/$(basename $subvol)) /tmp/dest; then + # echo cloning now + # # echo $usesudo btrfs-clone --toplevel $dr -v /tmp/source /tmp/dest + cmd="$usesudo btrbk $dr archive /tmp/source/$1 $dest/$1" + echo "command: $cmd" + if eval "$cmd"; then + echo "######### $dest/$1 #########" + ls -la /tmp/dest + echo "#################################" + else + echo clone failed + echo $cmd + fi + # else + # echo unable to mount a destination subvolume $1 at $3 + # fi + # else + # echo unable to mount source subvolume $1 from $2 + # return 1 + # fi + # confirm press any key to unmount temporary mountpoints /tmp/source, /tmp/dest + echo unmounting source + $usesudo umount /tmp/source &> /dev/null + # $usesudo umount /tmp/dest &> /dev/null +} + # alias alias btvl="sudo $BTRFS_BIN subvolume list" alias btrfs="sudo $BTRFS_BIN" diff --git a/modules/scripting/helpers.lib b/modules/scripting/helpers.lib index 7464494..f7c8d66 100644 --- a/modules/scripting/helpers.lib +++ b/modules/scripting/helpers.lib @@ -140,6 +140,27 @@ mkrfilename () { echo ${2:-/tmp/}${1:-file}.$RANDOM } +rm_ext () { +# sed -re 's/(^.*[^/])\.[^./]*$/\1/' <<< "$1" + echo "${1%.*}" +} + +get_ext () { + echo "${1##*.}" +} + +get_fname () { +# basename $1 + echo "${1##*/}" +} + +get_only_fname () { + rm_ext "$(get_fname "$1")" +} + +get_dir () { + echo "${1%/*}" +} #rows between matched rows # sed '1,/firstmatch/d;/secondmatch/,$d' diff --git a/modules/utility/copy.func b/modules/utility/copy.func index 1a8c20c..41fec41 100644 --- a/modules/utility/copy.func +++ b/modules/utility/copy.func @@ -52,7 +52,7 @@ EOF local OPTION local OPTARG local OPTIND - while getopts 'avMqpf:le:rcCmd:s:hnF' OPTION; do + while getopts 'avMqpf:le:rcCmd:shnF' OPTION; do # echo OPTION $OPTION ARG $OPTARG INDX $OPTIND case "$OPTION" in s)