Skip to content

Instantly share code, notes, and snippets.

@silug
Created February 6, 2022 21:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save silug/570d8514710dab3e9c33c1e23d6e1cf1 to your computer and use it in GitHub Desktop.
Save silug/570d8514710dab3e9c33c1e23d6e1cf1 to your computer and use it in GitHub Desktop.
Clone a ZFS vdev
#!/bin/bash
set -e
dd_args=(
"-d"
"-b" "1M"
"-B" "4k"
"-w"
"-A"
)
warn() {
echo "$@" >&2
}
die() {
warn "$@"
exit 1
}
usage() {
warn "$( basename "$0" ) device [device [...]]"
}
get_first() {
key="$1"
text="$2"
value=$( echo "$text" | awk "(\$1 == \"$key:\") { print \$2; exit 0; }" )
echo "${value//\'/}"
}
get_pool() {
get_first "name" "$@"
}
get_guid() {
get_first "guid" "$@"
}
get_timestamp() {
text="$1"
timestamps=( $( echo "$text" | awk '($1 == "timestamp") { print $3 }' | sort -n ) )
echo "${timestamps[-1]}"
}
get_output_filename() {
base="$1"
n=1
while [ -f "${base}-${n}.img" ] ; do
warn "${base}-${n}.img exists."
(( n++ ))
done
echo "${base}-${n}.img"
}
if [ "$#" -lt 1 ] ; then
usage
exit 1
fi
cd /volumes/recovery/disks
for device in "$@" ; do
if [ ! -e "${device}1" ] ; then
die "Can't find first partition for device $device"
fi
zdb=$( zdb -l -u "${device}1" )
pool=$( get_pool "$zdb" )
guid=$( get_guid "$zdb" )
timestamp=$( get_timestamp "$zdb" )
echo "Recovering $guid from pool $pool last updated $( date --date="@$timestamp" )..."
mkdir -pv "${pool}/${guid}"
filename=$( get_output_filename "${pool}/${guid}/${timestamp}" )
logfile="${filename%.img}.log"
badfile="${filename%.img}.bad"
echo "Cloning $device to $filename (logging to $logfile)..."
dd_rescue "${dd_args[@]}" -l "$logfile" -o "$badfile" "$device" "$filename"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment