comparison sbin/fzfs @ 428:824e88618376

The first version of "fzfs copy-tree" completed
author Franz Glasner <hg@dom66.de>
date Thu, 21 Sep 2023 18:42:41 +0200
parents 7056e5b7712d
children bbdb1ab0ea00
comparison
equal deleted inserted replaced
427:7056e5b7712d 428:824e88618376
258 local _ds_source _ds_target 258 local _ds_source _ds_target
259 local _opt_mountpoint _opt_mount_noauto _opt_nomount _opt_dry_run 259 local _opt_mountpoint _opt_mount_noauto _opt_nomount _opt_dry_run
260 260
261 local _ds_source_base _ds_source_snapshot _snapshot_suffix 261 local _ds_source_base _ds_source_snapshot _snapshot_suffix
262 local _ds_tree _ds _ds_relname _ds_canmount 262 local _ds_tree _ds _ds_relname _ds_canmount
263 local _rflags 263 local _arg_canmount _arg_mp1 _arg_mp2
264 264
265 _opt_mountpoint="" 265 _opt_mountpoint=""
266 _opt_mount_noauto="" 266 _opt_mount_noauto=""
267 _opt_nomount="" 267 _opt_nomount=""
268 _opt_dry_run="" 268 _opt_dry_run=""
295 [ -z "${_ds_source}" ] && { echo "ERROR: no source given" 1>&2; return 2; } 295 [ -z "${_ds_source}" ] && { echo "ERROR: no source given" 1>&2; return 2; }
296 [ -z "${_ds_target}" ] && { echo "ERROR: no target name given" 1>&2; return 2; } 296 [ -z "${_ds_target}" ] && { echo "ERROR: no target name given" 1>&2; return 2; }
297 297
298 if ! zfs get -H name "${_ds_source}" >/dev/null 2>&1; then 298 if ! zfs get -H name "${_ds_source}" >/dev/null 2>&1; then
299 echo "ERROR: source dataset does not exist: ${_ds_source}" 1>&2; 299 echo "ERROR: source dataset does not exist: ${_ds_source}" 1>&2;
300 return 1;
301 fi
302 if zfs get -H name "${_ds_target}" >/dev/null 2>&1; then
303 echo "ERROR: target dataset already exists: ${_ds_target}" 1>&2;
300 return 1; 304 return 1;
301 fi 305 fi
302 306
303 _ds_source_base="${_ds_source%@*}" 307 _ds_source_base="${_ds_source%@*}"
304 _ds_source_snapshot="${_ds_source##*@}" 308 _ds_source_snapshot="${_ds_source##*@}"
309 [ "${_ds_source_base}" = "${_ds_source}" ] || { echo "ERROR:" 1>&2; return 1; } 313 [ "${_ds_source_base}" = "${_ds_source}" ] || { echo "ERROR:" 1>&2; return 1; }
310 _ds_source_snapshot="" 314 _ds_source_snapshot=""
311 _snapshot_suffix="" 315 _snapshot_suffix=""
312 fi 316 fi
313 317
314 echo $_ds_source_base
315 echo $_ds_source_snapshot $_snapshot_suffix
316
317 _ds_tree="" 318 _ds_tree=""
318 319
319 while IFS=$'\n' read -r _ds; do 320 while IFS=$'\n' read -r _ds; do
320 if [ -z "${_ds_tree}" ]; then 321 if [ -z "${_ds_tree}" ]; then
321 _ds_tree="${_ds}" 322 _ds_tree="${_ds}"
322 else 323 else
323 _ds_tree="${_ds_tree}"$'\n'"${_ds}" 324 _ds_tree="${_ds_tree}"$'\n'"${_ds}"
324 fi 325 fi
325 echo "X: $_ds"
326 done <<EOF20ee7ea0781414fab8c305d3875d15e 326 done <<EOF20ee7ea0781414fab8c305d3875d15e
327 $(zfs list -H -r -t filesystem -o name -s name "${_ds_source_base}") 327 $(zfs list -H -r -t filesystem -o name -s name "${_ds_source_base}")
328 EOF20ee7ea0781414fab8c305d3875d15e 328 EOF20ee7ea0781414fab8c305d3875d15e
329 # Check the existence of all intermediate datasets and their shapshots 329 # Check the existence of all intermediate datasets and their shapshots
330 IFS=$'\n' 330 IFS=$'\n'
332 if ! zfs get -H name "${_ds}${_snapshot_suffix}" >/dev/null 2>&1; then 332 if ! zfs get -H name "${_ds}${_snapshot_suffix}" >/dev/null 2>&1; then
333 echo "ERROR: child dataset does not exist: ${_ds}${_snapshot_suffix}" 1>&2 333 echo "ERROR: child dataset does not exist: ${_ds}${_snapshot_suffix}" 1>&2
334 return 1 334 return 1
335 fi 335 fi
336 done 336 done
337 IFS=$'\n'
337 for _ds in ${_ds_tree}; do 338 for _ds in ${_ds_tree}; do
339 # Reset IFS
340 IFS=$' \t\n'
341
338 # Determine the relative name of the dataset 342 # Determine the relative name of the dataset
339 _ds_relname="${_ds#${_ds_source_base}}" 343 _ds_relname="${_ds#${_ds_source_base}}"
340 344
341 _ds_canmount=$(zfs get -H -o value canmount "${_ds}") 345 _ds_canmount=$(zfs get -H -o value canmount "${_ds}")
342 echo "REL: $_ds --- $_ds_relname --- $_ds_canmount"
343
344 _rflags=""
345 346
346 if [ "${_ds_canmount}" = "off" ]; then 347 if [ "${_ds_canmount}" = "off" ]; then
347 _rflags="-o canmount=off" 348 _arg_canmount="-o canmount=off"
348 else 349 else
349 _rflags="${_opt_mount_noauto}" 350 _arg_canmount="${_opt_mount_noauto}"
350 fi 351 fi
351 352
352 if [ -z "${_ds_relname}" ]; then 353 if [ -z "${_ds_relname}" ]; then
353 # 354 #
354 # Source root to target root 355 # Source root to target root
355 # 356 #
356 if [ -z "${_opt_mountpoint}" ]; then 357 if [ -z "${_opt_mountpoint}" ]; then
357 _rflags="${_rflags} -x mountpoint" 358 _arg_mp1=-x
359 _arg_mp2=mountpoint
358 else 360 else
359 _rflags="${_rflags} -o mountpoint='${_opt_mountpoint}'" 361 _arg_mp1=-o
362 _arg_mp2="mountpoint=${_opt_mountpoint}"
360 fi 363 fi
361 else 364 else
362 _rflags="${_rflags} -x mountpoint" 365 _arg_mp1=-x
363 fi 366 _arg_mp2=mountpoint
364 echo "zfs send -Lec -p -v '${_ds}${_ds_source_snapshot}' | zfs receive -v ${_opt_nomount} ${_rflags} '${_ds_target}${_ds_relname}'" 367 fi
368 if [ -z "${_opt_dry_run}" ]; then
369 zfs send -Lec -p -v "${_ds}${_snapshot_suffix}" | zfs receive -v ${_opt_nomount} ${_arg_canmount} ${_arg_mp1} "${_arg_mp2}" "${_ds_target}${_ds_relname}"
370 else
371 echo "Would execute: zfs send -Lec -p -v '${_ds}${_snapshot_suffix}' | zfs receive -v ${_opt_nomount} ${_arg_canmount} ${_arg_mp1} '${_arg_mp2}' '${_ds_target}${_ds_relname}'"
372 fi
373 # for the loop
374 IFS=$'\n'
365 done 375 done
376 # Reset to default
377 IFS=$' \t\n'
378 # Remove received snapshots
379 if [ -n "${_ds_source_snapshot}" ]; then
380 if [ -z "${_opt_dry_run}" ]; then
381 zfs destroy -rv "${_ds_target}${_snapshot_suffix}"
382 else
383 echo "Would execute: zfs destroy -rv '${_ds_target}${_snapshot_suffix}'"
384 fi
385 fi
366 } 386 }
367 387
368 388
369 #: 389 #:
370 #: Implement the "create-tree" command 390 #: Implement the "create-tree" command