zfs send | recvの差分転送を楽にする（SSH対応版）

#要件
zfs send | recvで差分転送をするには、下記のような手順を踏む必要があります。

* 初回
    1. 送信側でtempスナップショットを作成
    1. tempスナップショットを送信
    1. 送信側および受信側でtempスナップショットをリネーム
* 2回目以降
    1. 送信側でtempスナップショットを作成
    1. tempスナップショットと前回のスナップショットの差分を送信
    1. 前回のスナップショットを削除
    1. 送信側および受信側でtempスナップショットをリネーム

#関数仕様
取り違えやすいため関数を作成しました。

```
send_recv_new <from_fsname> <from_ssh_host> <from_ssh_cipher_spec> <to_fsname> <to_ssh_host> <to_ssh_cipher_spec> <snapshot_name> <temp_snapshot_name>
send_recv <from_fsname> <from_ssh_host> <from_ssh_cipher_spec> <to_fsname> <to_ssh_host> <to_ssh_cipher_spec> <snapshot_name> <temp_snapshot_name>
```
SSHのホストに空文字列を渡せば、SSH接続せずローカルで処理します。また暗号化アルゴリズムに空文字列を渡せば、デフォルトの暗号化アルゴリズムを使います。具体的には次のように使ってください。

```
send_recv_new 'tank1/test' '' '' 'tank2/test' 'user@192.168.1.2' 'chacha20-poly1305@openssh.com' 'tank1_to_tank2' 'temp'
send_recv 'tank1/test' '' '' 'tank2/test' 'user@192.168.1.2' 'chacha20-poly1305@openssh.com' 'tank1_to_tank2' 'temp'
```

#コード
```
#!/bin/bash
ssh_wrapper () {
    local host=$1
    local cipher_spec=$2
    local command=$3

    if [ -n "$host" -a "''" != "$host" ]; then
        local command2='ssh'
        if [ -n "$cipher_spec" -a "''" != "$cipher_spec" ]; then
            command2=${command2}' -c '${cipher_spec}
        fi
        command2=${command2}' '${host}' '$(printf %q "$command")
        echo "$command2"
    else
        echo "$command"
    fi
}
send_recv_new () { #初回
    local from=$(printf %q "$1")
    local from_host=$(printf %q "$2")
    local from_cipher_spec=$(printf %q "$3")
    local to=$(printf %q "$4")
    local to_host=$(printf %q "$5")
    local to_cipher_spec=$(printf %q "$6")
    local snapshot=$(printf %q "$7")
    local temp=$(printf %q "$8")

    local c
    c=$(ssh_wrapper $from_host $from_cipher_spec "zfs snapshot ${from}@${temp}") && eval $c &&

    c=$(       ssh_wrapper $from_host $from_cipher_spec "zfs send ${from}@${temp}") &&
    c=$c' | '$(ssh_wrapper $to_host   $to_cipher_spec   "zfs recv ${to}") && eval $c &&

    c=$(ssh_wrapper $from_host $from_cipher_spec "zfs rename ${from}@${temp} @${snapshot}") && eval $c &&
    c=$(ssh_wrapper $to_host   $to_cipher_spec   "zfs rename ${to}@${temp}   @${snapshot}") && eval $c
}

inner_send_recv () { #内部処理
    local from=$1
    local from_host=$2
    local from_cipher_spec=$3
    local to=$4
    local to_host=$5
    local to_cipher_spec=$6
    local snapshot=$7
    local temp=$8

    local c
    c=$(       ssh_wrapper $from_host $from_cipher_spec "zfs send -i @${snapshot} ${from}@${temp}") &&
    c=$c' | '$(ssh_wrapper $to_host   $to_cipher_spec   "zfs recv -F ${to}") && eval $c &&

    c=$(ssh_wrapper $from_host $from_cipher_spec "zfs destroy ${from}@${snapshot}") && eval $c &&
    c=$(ssh_wrapper $from_host $from_cipher_spec "zfs rename ${from}@${temp} @${snapshot}") && eval $c &&

    c=$(ssh_wrapper $to_host $to_cipher_spec "zfs destroy ${to}@${snapshot}") && eval $c &&
    c=$(ssh_wrapper $to_host $to_cipher_spec "zfs rename ${to}@${temp} @${snapshot}") && eval $c
}
send_recv () { #2回目以降
    local from=$(printf %q "$1")
    local from_host=$(printf %q "$2")
    local from_cipher_spec=$(printf %q "$3")
    local to=$(printf %q "$4")
    local to_host=$(printf %q "$5")
    local to_cipher_spec=$(printf %q "$6")
    local snapshot=$(printf %q "$7")
    local temp=$(printf %q "$8")

    local c
    c=$(ssh_wrapper $from_host $from_cipher_spec "zfs snapshot ${from}@${temp}") && eval $c &&

    inner_send_recv $from $from_host $from_cipher_spec $to $to_host $to_cipher_spec $snapshot $temp
}
```