#!/usr/local/bin/bash # DO NOT USE THIS SCRIPT # It is in a state of hot garbage and will probably be deleted soon print_help_and_exit() { echo "Please run this program with a source and a target dataset name as arguments" echo "e.g. $0 zpool/dataset1 zpool/dataset2" exit } SIMULATION=0 args=$(getopt n $*) test $? == 0 || print_help_and_exit set -- $args while :; do sleep 1 echo $1 case "$1" in --) shift; break ;; -n) SIMULATION=1 ; shift ;; esac done DATASET_ROOT=$1 DATASET_TARGET=$2 if ! zfs get mountpoint $DATASET_TARGET >/dev/null; then echo "Dataset $DATASET_TARGET does not exist and will be created." echo "You have 10 seconds to abort this with CTRL-C" sleep 10 if ! $SIMULATION; then zfs create $DATASET_TARGET fi fi if zfs get -H -t filesystem -o name,value -r snapdir zeus/data/projects | grep -v visible >/dev/null; then echo Please make all snapdirs visible: zfs get -H -t filesystem -o name,value -r snapdir zeus/data/projects exit 2 fi MOUNTPOINT_TARGET=$(zfs get -o value -H mountpoint $DATASET_TARGET) test ${SIMULATION:0} = 1 && test $MOUNTPOINT_TARGET == "" && MOUNTPOINT_TARGET="datapool/simulation" test -d "$MOUNTPOINT_TARGET" || print_help_and_exit # make sure, that ctrl-c also works in the inner loops trap exit INT # recursively contains all snapshot names (the part after the @) from root on, sorted and only once SNAPSHOTS=$(zfs list -H -oname -tsnap -r $DATASET_ROOT | cut -d@ -f2 | sort -u) DATASETS=$(zfs list -H -oname -t filesystem -r $DATASET_ROOT) test "${SIMULATION:-0}" = 1 && echo "SIMULATION MODE" $DATASETS echo "We are going to flatten the hierachy of this dataset:" printf "\t%s\n" $DATASETS echo -e "into the dataset with the name:" echo -e "\t$DATASET_TARGET" echo -e "mounted under:" echo -e "\t$MOUNTPOINT_TARGET" echo -e "with the following snapshots:" printf "\t%s\n" $SNAPSHOTS echo "" echo "You have 10 seconds to abort this with CTRL-C" sleep 10 set -- $SNAPSHOTS SNAPSHOTS_TOTAL=$# SNAPSHOT_CURRENT=0 set -- $DATASETS shift SUBDATASETS=$@ for SNAPSHOT in $SNAPSHOTS; do echo "" echo "" SNAPSHOT_CURRENT=$((SNAPSHOT_CURRENT + 1)) echo "[$SNAPSHOT_CURRENT/$SNAPSHOTS_TOTAL] Next snapshot is: $SNAPSHOT" for DATASET in $SUBDATASETS; do DATASET_RELATIVE=${DATASET##$DATASET_ROOT} MOUNTPOINT=$(zfs get -H -o value mountpoint $DATASET) echo "RELATIVE=$DATASET_RELATIVE" if [[ $MOUNTPOINT == "legacy" ]]; then MOUNTPOINT=$(findmnt -n -o target $DATASET) if test -d $MOUNTPOINT; then >&2 echo "Dataset has a legacy mountpoint, but was not found in the fstab: $DATASET" continue fi fi if [[ $MOUNTPOINT == "-" ]]; then >&2 echo "Dataset does not have a mount point or is a vdev: $DATASET" continue fi SNAPDIR=$MOUNTPOINT/.zfs/snapshot/$SNAPSHOT if test -d $SNAPDIR; then TARGET_DIR="${MOUNTPOINT_TARGET}${DATASET_RELATIVE}" echo -e \\trsync --info=stats3 --delete -a "$SNAPDIR/" "$TARGET_DIR/" if test "${SIMULATION:-0}" = 0; then mkdir -p "$TARGET_DIR" if ! rsync --info=stats3 --delete -a "$SNAPDIR/" "$TARGET_DIR/" ; then >&2 echo "rsync could not entirely copy from $SNAPDIR to $DATASET_TARGET" fi fi else echo -e "\tSKIP: Snapshot $SNAPSHOT does not exist for dataset $DATASET" fi done NEW_SNAPSHOT="$DATASET_TARGET@$SNAPSHOT" echo "" echo -e "\t> Concluding snapshot: ${NEW_SNAPSHOT} <" echo "" if test "${SIMULATION:-0}" = 0; then zfs snap $NEW_SNAPSHOT fi done