aboutsummaryrefslogtreecommitdiff
path: root/zfs-squash-datasets.sh
blob: c61af4065177c7ae650410bea7fc5fea50422495 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
DATASET_ROOT=$1
DATASET_TARGET=$2

MOUNTPOINT_TARGET=$(zfs get -H mountpoint -o value $DATASET_TARGET)

if ! test -d "$MOUNTPOINT_TARGET"; then
    echo "Please run this program with a source and a target dataset name as arguments"
    echo "e.g. $0 zpool/dataset1 zpool/dataset2"
    exit
fi

# 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 -r $DATASET_ROOT -oname -tsnap | cut -d@ -f2 | sort  | uniq)
DATASETS=$(zfs list -H -r $DATASET_ROOT -oname -t filesystem)

echo "We are going to flatten the hierachy of this dataset:"
printf "    %s\n" $DATASETS
echo "into the dataset with the name:"
echo "    $DATASET_TARGET"
echo "mounted under:"
echo "    $MOUNTPOINT_TARGET"
echo ""
echo "You have 10 seconds to abort this with CTRL-C"
sleep 10

for SNAPSHOT in $SNAPSHOTS; do
    echo ""
    echo ""
    echo "==========================="
    echo "Next snapshot is: $SNAPSHOT"
    echo "==========================="

    for DATASET in $DATASETS; do

        MOUNTPOINT=$(zfs get -H mountpoint -o value $DATASET)

        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=$(realpath $MOUNTPOINT/.zfs/snapshot/$SNAPSHOT)
        if test -d $SNAPDIR; then
            TARGET_DIR="$(realpath $MOUNTPOINT_TARGET)$(realpath $MOUNTPOINT)"
            mkdir -p "$TARGET_DIR"
            echo rsync --info=stats3 -a "$SNAPDIR/" "$TARGET_DIR/"
            if ! rsync --info=stats3 -a "$SNAPDIR/" "$TARGET_DIR/" ; then
                >&2 echo "rsync could not entirely copy from $SNAPDIR to $DATASET_TARGET"
            fi
        fi
    done
    NEW_SNAPSHOT="$DATASET_TARGET@$SNAPSHOT"
    echo "Files copied, creating snapshot: $NEW_SNAPSHOT"
    zfs snap $NEW_SNAPSHOT
done

..