From 39d6cc755e79e1ca388c4740c8433b78733f8f37 Mon Sep 17 00:00:00 2001 From: David Kebler Date: Mon, 12 Feb 2024 12:53:25 -0800 Subject: [PATCH] rearrange some module locations auto load btrfs modules if btrfs-progs and btrbk are installed --- load/05-filesystem | 9 ++ modules/filesystem/btrfs/btrbk.lib | 187 +++++++++++++++++++++++ modules/{ => filesystem/btrfs}/btrfs.mod | 0 modules/{ => scripting}/debug.lib | 0 modules/utility/bindfs.lib | 109 +++++++++++++ modules/utility/dir.lib | 9 ++ modules/utility/file.lib | 37 ++++- 7 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 load/05-filesystem create mode 100644 modules/filesystem/btrfs/btrbk.lib rename modules/{ => filesystem/btrfs}/btrfs.mod (100%) rename modules/{ => scripting}/debug.lib (100%) create mode 100644 modules/utility/bindfs.lib diff --git a/load/05-filesystem b/load/05-filesystem new file mode 100644 index 0000000..92b3777 --- /dev/null +++ b/load/05-filesystem @@ -0,0 +1,9 @@ +#!/bin/bash +if which btrfs &> /dev/null; then +module_load btrfs +if which btrbk &> /dev/null; then module_load btrbk; fi +fi + + + + diff --git a/modules/filesystem/btrfs/btrbk.lib b/modules/filesystem/btrfs/btrbk.lib new file mode 100644 index 0000000..4774b73 --- /dev/null +++ b/modules/filesystem/btrfs/btrbk.lib @@ -0,0 +1,187 @@ +#!/bin/bash + +# dry run by default +# >btrbk_run +# with -e exectue +# >btrbk_run -e +# to only create the links +# >btrbk_run -e -n + +# sudo -E bash -c 'source $BASH_SHELL_BASE/module.base; module_load btrbk; btrbk_run toot' + + +btrbk_scripts_dir="$(dirname $(realpath "${BASH_SOURCE:-$0}"))" + +# will try to find a conf file with out without .conf extension in a few places +btrbk_conf () { + local file=${1:-btrbk.conf} + [[ -f $file ]] && echo $file && return + [[ -f $file.conf ]] && echo $file.conf && return + BTRBK_CONF_DIR=${BTRBK_CONF_DIR:-/snapshots/conf} +# echo $btrbk_scripts_dir +# echo $BTRBK_CONF_DIR + [[ -f $BTRBK_CONF_DIR/$file ]] && echo $BTRBK_CONF_DIR/$file && return + [[ -f $BTRBK_CONF_DIR/$file.conf ]] && echo $BTRBK_CONF_DIR/$file.conf && return + [[ -f /etc/btrbk/$file ]] && echo /etc/btrbk/$file && return + [[ -f /etc/btrbk/$file.conf ]] && echo /etc/btrbk/$file.conf && return + [[ -f /etc/btrbk.conf ]] && echo /etc/btrbk.conf && return + return 1 +} + +btrbk_clean () { + local file=$(btrbk_conf $1) + [[ ! $file ]] && return 1 + sudo btrbk -c $file clean $2 +} + +btrbk_src () { + local file=$(btrbk_conf $1) + [[ ! $file ]] && return 1 + sudo btrbk -c $file list config --format col:h:source_subvolume +} + +btrbk_dests () { +local file=$(btrbk_conf $1) +[[ ! $file ]] && return 1 +local dests=$(sudo btrbk -c $file list config --format col:h:snapshot_path | tail -1) +dests+=" $(sudo btrbk -c $file list target --format col:h:target_path)" +echo $dests +} + +btrbk_latest_links () { + +local dry_run="echo" +[[ $1 == "-e" ]] && dry_run="" && shift + +local file=$(btrbk_conf $1) +[[ ! $file ]] && echo unable to find conf file for ${1:-btrbk.conf} && return 1 +shift + +local latest=$(sudo btrbk -c $file list latest --format col:h:snapshot_subvolume | xargs -I % sh -c 'basename %' | sed '$!N; /^\(.*\)\n\1$/!P; D') +[[ ( ! $latest ) || $latest == "-" ]] && echo "no latest snapshots so can't make .latest links" && return 3 +local dests=$(btrbk_dests $file) + +if [[ $dry_run ]]; then + echo dry run for making latest links for following destinations, NOTE: use -e to actually make them + echo $dests + echo "-------------------" +fi + +echo making .latest symlinks in each destination +for dest in $dests; do +for snap in $latest; do +# [[ -e $dest/${snap%%.*}.latest ]] && $dry_run_echo sudo rm $dest/${snap%%.*}.latest +local cmd="sudo ln -srfn $dest/$snap $dest/${snap%%.*}.latest" +echo $cmd +[[ ! $dry_run ]] && $cmd +done +done + +} + +btrbk_run () { + +local dry_run="-n" +[[ $1 == "-e" ]] && dry_run="" && shift + +local file=$(btrbk_conf $1) +[[ ! $file ]] && echo unable to find conf file for ${1:-btrbk.conf} && return 1 +shift + +local src=$(btrbk_src $file) + +local snaps=$(sudo btrbk -c $file list source --format col:h:snapshot_name) + +local dests=$(sudo btrbk -c $file list config --format col:h:snapshot_path | tail -1) +local dests+=" $(btrbk -c $file list target --format col:h:target_path)" + +# todo distinguish local from remote destinations and deal with differently for latest link + +# any pre snap tasks +# for dest in $dests; do +# if [[ ! -d $dest ]]; then +# if confirm directory $dest does not exist, create; then +# sudo mkdir -p $dest +# else +# echo destination $dest directory MUST exist aborting brtbk run +# return 2 +# fi +# fi +# done + +echo using configuration file: $file +echo creating snapshots: $snaps +echo from $src +echo at these destinations $dests +echo additional passed arguments: $@ + +# do snaps and backups +[[ $dry_run ]] && echo backup dry run || echo Taking snapshost and making backups now... +sudo btrbk -c $file run $dry_run --progress $@ + +# post snap/backup + +btrbk_latest_links $([[ $dry_run ]] || printf "%s" -e) $file + +} + +(return 0 2>/dev/null) || btrbk_run $@ + + +latest_clone () { + + local src=$(realpath $1) + local dest=$(realpath $2) + shift 2 + module_load confirm + if [[ ! -d $dest ]]; then + if confirm "destination directory $dest does not exist, create it"; then + sudo mkdir -p $dest + else + 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 + local destsnap + for snap in $snaps; do + destsnap="$dest/$(basename $snap | cut -f 1 -d '.' )" + if [[ -d $destsnap ]]; then + if confirm -s snapshot $destsnap already exists do you want to over write it; then + sudo btrfs subvolume delete $destsnap + else + return 2 + fi + fi + sudo btrfs subvolume snapshot $@ $snap $destsnap + done + echo $dest + ls -la $dest + fi + +} + +# use snapshot to then snap latest to another location, have it edit the fstab file +# #!/bin/bash +# [[ $# -lt 2 ]] && echo "need to supply a and a snapshot name" && exit +# # echo sed 's/$name/'$name'/g' named.conf.tmpl > $subvoldir-$name.conf +# # echo sed -i 's/$subvoldir/'$subvoldir'/g' $subvoldir-$name.conf + +# named="$2" +# src=/mnt/linuxpart +# dest=/mnt/linuxpart + +# echo sudo mkdir -p $dest/$named +# echo sudo btrfs subvolume snapshot $src/$1/@root $dest/$named/@root +# echo sudo btrfs subvolume snapshot $src/$1/@opt $dest/$named/@opt +# echo sudo btrfs subvolume snapshot $src/$1/@home $dest/$named/@home +# echo sudo btrfs subvolume snapshot $src/@shell $dest/$named/@shell + +# sudo mkdir -p $dest/$named +# sudo btrfs subvolume snapshot $src/$1/@root $dest/$named/@root +# sudo btrfs subvolume snapshot $src/$1/@opt $dest/$named/@opt +# sudo btrfs subvolume snapshot $src/$1/@home $dest/$named/@home +# sudo btrfs subvolume snapshot $src/@shell $dest/$named/@shell + +# echo to edit: bfs_vscode $dest/$named \ No newline at end of file diff --git a/modules/btrfs.mod b/modules/filesystem/btrfs/btrfs.mod similarity index 100% rename from modules/btrfs.mod rename to modules/filesystem/btrfs/btrfs.mod diff --git a/modules/debug.lib b/modules/scripting/debug.lib similarity index 100% rename from modules/debug.lib rename to modules/scripting/debug.lib diff --git a/modules/utility/bindfs.lib b/modules/utility/bindfs.lib new file mode 100644 index 0000000..7dd4f91 --- /dev/null +++ b/modules/utility/bindfs.lib @@ -0,0 +1,109 @@ +#!/bin/bash + + +if ! which fusermount &> /dev/null; then + echo unabled to load bindfs module because bindfs is not installed + exit 1 +fi + +# echo loading bindfs + +export BFS_MOUNT_DIR=${BFS_MOUNT_DIR:-/mnt/bfs} + +if [ -v PS1 ]; then + alias rbfsu="dir_rebind_user" + alias rbfs="dir_rebind" + alias bfsu="dir_bind_user" + alias bfs="dir_bind" + alias bfsum="dir_bind_unmount" + alias bfse="bfs_vscode" + + sudo mkdir $BFS_MOUNT_DIR 2> /dev/null + sudo chown $USER:$USER $BFS_MOUNT_DIR +fi + +mounted () { + mountpoint "$1" &> /dev/null && echo yes || return 1 +} + +dir_bind_unmount () { + local usesudo + local mp=$1 + [[ ! $(mounted $mp) ]] && echo no mountpoint at $mp && mp=$BFS_MOUNT_DIR/$(basename $mp) + [[ ! $(mounted $mp) ]] && echo no mountpoint at $mp either, aborting && return 1 + [[ $EUID -ne 0 ]] && usesudo=sudo + if $usesudo fusermount -u $mp; then + echo unmounted $mp, removing empty mountpoint directory + rm -rf $mp + else + echo error, unable to unmount $mp + fi +} + +dir_bind_user () { + local usesudo; local dir;local user;local group;local mp + +if [ $# -lt 3 ]; then + echo "minimum 3 args needed to rebind " + echo passed were $@ + return 1 +fi + +[[ $EUID -ne 0 ]] && usesudo=sudo + +[[ $(id -u $1 2> /dev/null) ]] || { echo user $1 does not exist can not continue; return 2; } + +dir=$(realpath $2) +mp=$3 +[[ $(mounted $mp) ]] && echo something already mounted at $mp, aborting && return 1 +if ! $usesudo mkdir -p $mp; then echo unable to make mountpoint aborting; return 2; fi +$usesudo chown $1:$1 $mp +user=$(stat -c '%u' $dir) +group=$(stat -c '%g' $dir) +$usesudo bindfs --force-user=$1 --force-group=$1 --create-for-user=$user --create-for-group=$group --chown-ignore --chgrp-ignore $dir $mp +[[ $? -gt 0 ]] && echo error in call to bindfs + +if [[ $(mounted $mp) ]]; then + echo $dir has been mounted at $mp for user $1 + echo "to unmount use: dir_bind_unmount $mp or bfsum $mp" + else + echo unable to mount $dir at $mp as user $user + fi + + } + +dir_bind () { +mp=${2:-$BFS_MOUNT_DIR/$(basename $1)} +dir_bind_user $USER $1 $mp +if [ -v PS1 ]; then +echo enter \"u\" when you ready to unmount, otherwise any other key will leave mounted +read -n1 ans +echo -e "\n" +[[ $ans == "u" ]] && dir_bind_unmount $mp +fi +} + +dir_rebind () { +dir_bind_user $USER $1 $1 +} + +dir_rebind_user () { +dir_bind_user $1 $2 $2 +} + +bfs_vscode () { +mp=${2:-$BFS_MOUNT_DIR/$(basename $1)} +dir_bind_user $USER $1 $mp +/opt/bin/vscode $mp +if [ -v PS1 ]; then +echo when you ready to unmount FIRST close your vscode window then enter \"u\" +echo otherwise any other key will leave mounted +read -n1 ans +echo -e "\n" +[[ $ans == "u" ]] && dir_bind_unmount $mp +fi + +} + +(return 0 2>/dev/null) || dir_bind_user $@ + diff --git a/modules/utility/dir.lib b/modules/utility/dir.lib index c1c5e4e..64e2a09 100644 --- a/modules/utility/dir.lib +++ b/modules/utility/dir.lib @@ -54,3 +54,12 @@ echo copying..... eval $cmd } +dir_size () { + if sudo ls $1 >/dev/null ; then + sudo du -h --apparent-size --max-depth=1 $1 | sort -rh + else + echo $1 not a directory + fi +} + +# for dir in $(/bin/find -maxdepth 1 -name "*[cC]ache*" -type d ); do; echo $dir; done \ No newline at end of file diff --git a/modules/utility/file.lib b/modules/utility/file.lib index 3b64eba..58cf0e5 100644 --- a/modules/utility/file.lib +++ b/modules/utility/file.lib @@ -71,12 +71,24 @@ local NAMES local ENAMES local DEPTH=1 local HIDDEN +local raw +local mounted +local usesudo + +mounted="-mount" declare OPTION declare OPTARG declare OPTIND -while getopts 't:p:d:e:n:f:hl' OPTION; do + +while getopts 'mrst:p:d:e:n:f:hl' OPTION; do case "$OPTION" in + s) + usesudo=sudo + ;; + r) + raw=true + ;; t) TYPE=$OPTARG # echo "TYPE $TYPE" @@ -111,6 +123,10 @@ case "$OPTION" in l) LINKS=-L ;; + m) + # include mounted directories + mounted="" + ;; *) echo unknown option $OPTION ;; @@ -119,6 +135,11 @@ done shift $(( OPTIND - 1 )) +if [[ $raw ]]; then + echo executing raw find command + $usesudo $(which find) "$@" +fi + local DIR DIR="$*" if [ ! "$DIR" ]; then @@ -137,11 +158,12 @@ fi # echo dir $DIR local FIND -FIND="command find $LINKS $DIR" +FIND="$usesudo $(which find) $LINKS $DIR" FIND+=$([ ! $DEPTH == 0 ] && echo " -maxdepth $DEPTH ") # FIND+=" -type $([ $TYPE ] && echo "$TYPE" || echo "f")" TYPE=${TYPE:-f} -FIND+=" -type $TYPE " +debug exclude mounts: $mounted +FIND+=" $mounted -type $TYPE " # include HIDDEN files and directories IS FALSE BY DEFULT [[ ! $HIDDEN ]] && FIND+="! -path \"*/.*/*\" ! -name \".*\" " @@ -192,7 +214,6 @@ fi # done # fi - # echo # echo find dir: $DIR >&2 debug "find command: $FIND" @@ -219,6 +240,7 @@ source_dir () { } + prepend_file () { # ---------------------------------------------------------------------------------------------------------------------- # usage prepend_file @@ -243,3 +265,10 @@ return 0 # [End] } + + +# alias to add for live user +if [ -v PS1 ]; then + alias dfind="_find -t d -d 0 -n " + alias sdfind="_find -s -t d -d 0 -n " +fi