comparison sbin/fzfs @ 380:6be930eb7490

Implement the "fzfs create-tree" command
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 20 Feb 2023 00:43:30 +0100
parents 1fc3b04b39fa
children 84d2735fe7f6
comparison
equal deleted inserted replaced
379:b4173e88c57c 380:6be930eb7490
26 26
27 -h Print this help message to stdout and exit 27 -h Print this help message to stdout and exit
28 28
29 COMMANDS: 29 COMMANDS:
30 30
31 create-tree [-A] [-M MOUNTPOINT] [-n] [-p] [-u] SOURCE-DATASET DEST-DATASET
32
31 mount [-O] [-N] [-P] [-u] [-n] DATASET [MOUNTPOINT] 33 mount [-O] [-N] [-P] [-u] [-n] DATASET [MOUNTPOINT]
32 34
33 umount DATASET 35 umount DATASET
34 36
35 unmount 37 unmount
36 38
37 ' 39 '
40
41
42 #:
43 #: Determine some important dataset properties that are set locally
44 #:
45 #: Args:
46 #: $1: the dataset
47 #: $2 ...: the properties to check for
48 #:
49 #: Output (stdout):
50 #: An option string suited for use in "zfs create"
51 #:
52 _get_local_properties() {
53 local ds
54
55 local _res _prop _value _source
56
57 ds="${1}"
58 shift
59
60 _res=""
61
62 for _prop in "$@" ; do
63 IFS=$'\t' read -r _value _source <<EOF73GHASGJKKJ354
64 $(zfs get -H -p -o value,source "${_prop}" "${ds}")
65 EOF73GHASGJKKJ354
66 case "${_source}" in
67 local)
68 if [ -z "${_res}" ]; then
69 _res="-o ${_prop}=${_value}"
70 else
71 _res="${_res} -o ${_prop}=${_value}"
72 fi
73 ;;
74 *)
75 # VOID
76 ;;
77 esac
78 done
79 echo "${_res}"
80 }
81
38 82
39 # 83 #
40 #: Implementation of the "mount" command. 84 #: Implementation of the "mount" command.
41 #: 85 #:
42 #: Mount a dataset and recursively all its children datasets. 86 #: Mount a dataset and recursively all its children datasets.
201 umount "${_mp}" || return 1 245 umount "${_mp}" || return 1
202 done 246 done
203 } 247 }
204 return 0 248 return 0
205 } 249 }
250
251
252 #:
253 #: Implement the "create-tree" command
254 #:
255 #: Create a ZFS dataset tree from a source tree tree including important properties
256 #:
257 command_create_tree() {
258 local _source_ds _target_ds
259 local _opt_dry_run _opt_mountpoint _opt_noauto _opt_nomount _opt_canmount_parent_only
260
261 local _opt _source_name _snapshot_name _current_name _current_type _relative_name _zfs_opts _zfs_canmount _zfs_mountpoint
262
263 _opt_noauto=""
264 _opt_dry_run=""
265 _opt_mountpoint=""
266 _opt_nomount=""
267 _opt_canmount_parent_only=""
268
269 while getopts "AM:npu" _opt ; do
270 case ${_opt} in
271 A)
272 _opt_noauto="-o canmount=noauto"
273 ;;
274 M)
275 _opt_mountpoint="${OPTARG}"
276 ;;
277 n)
278 _opt_dry_run="yes"
279 ;;
280 p)
281 _opt_canmount_parent_only="yes"
282 ;;
283 u)
284 _opt_nomount="-u"
285 ;;
286 \?|:)
287 return 2;
288 ;;
289 esac
290 done
291 shift $((OPTIND-1))
292 OPTIND=1
293
294 _source_ds="${1-}"
295 _target_ds="${2-}"
296
297 [ -z "${_source_ds}" ] && { echo "ERROR: no source dataset given" 1>&2; return 2; }
298 [ -z "${_target_ds}" ] && { echo "ERROR: no destination dataset given" 1>&2; return 2; }
299
300 _source_name="${_source_ds%@*}"
301 if [ "${_source_name}" != "${_source_ds}" ]; then
302 _snapshot_name="${_source_ds##*@}"
303 else
304 _snapshot_name=""
305 fi
306
307 [ -n "${_snapshot_name}" ] && { echo "ERROR: No snapshot sources are supported yet" 1>&2; return 2; }
308
309 zfs list -H -r -t filesystem -o name,type "${_source_ds}" \
310 | {
311 while IFS=$'\t' read -r _current_name _current_type ; do
312 # Determine the relative name of the dataset
313 _relative_name="${_current_name#${_source_name}}"
314 _relative_name="${_relative_name%@*}"
315 if [ "${_current_type}" != "filesystem" ]; then
316 echo "ERROR: Got a snapshot but expected a filesystem" 1>&2
317 return 1
318 fi
319 _zfs_opts="$(_get_local_properties "${_current_name}" atime exec setuid compression primarycache sync readonly)"
320 if [ -z "${_relative_name}" ]; then
321 #
322 # Root
323 #
324 if [ -z "${_opt_noauto}" ]; then
325 _zfs_canmount="$(_get_local_properties "${_current_name}" canmount)"
326 else
327 _zfs_canmount="${_opt_noauto}"
328 fi
329 if [ -n "${_opt_mountpoint}" ]; then
330 _zfs_mountpoint="${_opt_mountpoint}"
331 else
332 _zfs_mountpoint=""
333 fi
334
335 if [ "${_opt_dry_run}" = "yes" ]; then
336 if [ -z "${_zfs_mountpoint}" ]; then
337 echo "Would call: zfs create ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} ${_target_ds}${_relative_name}"
338 else
339 echo "Would call: zfs create ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} -o mountpoint=${_zfs_mountpoint} ${_target_ds}${_relative_name}"
340 fi
341 else
342 if [ -z "${_zfs_mountpoint}" ]; then
343 zfs create -v ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} "${_target_ds}${_relative_name}"
344 else
345 zfs create -v ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} -o "mountpoint=${_zfs_mountpoint}" "${_target_ds}${_relative_name}"
346 fi
347 fi
348 else
349 #
350 # Children
351 #
352 if [ -z "${_opt_noauto}" ]; then
353 if [ "${_opt_canmount_parent_only}" = "yes" ]; then
354 _zfs_canmount=""
355 else
356 _zfs_canmount="$(_get_local_properties "${_current_name}" canmount)"
357 fi
358 else
359 _zfs_canmount="${_opt_noauto}"
360 fi
361 if [ "${_opt_dry_run}" = "yes" ]; then
362 echo "Would call: zfs create ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} ${_target_ds}${_relative_name}"
363 else
364 zfs create -v ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} "${_target_ds}${_relative_name}"
365 fi
366 fi
367 done
368 }
369 return 0
370 }
371
206 372
207 # 373 #
208 # Global option handling 374 # Global option handling
209 # 375 #
210 while getopts "Vh" _opt ; do 376 while getopts "Vh" _opt ; do
243 command_mount "$@" 409 command_mount "$@"
244 ;; 410 ;;
245 umount|unmount) 411 umount|unmount)
246 command_umount "$@" 412 command_umount "$@"
247 ;; 413 ;;
414 create-tree)
415 command_create_tree "$@"
416 ;;
248 *) 417 *)
249 echo "ERROR: unknown command \`${command}'" 1>&2 418 echo "ERROR: unknown command \`${command}'" 1>&2
250 exit 2 419 exit 2
251 ;; 420 ;;
252 esac 421 esac