]> git.proxmox.com Git - mirror_zfs.git/blob - contrib/pyzfs/libzfs_core/_libzfs_core.py
FreeBSD: Add zfs_link_create() error handling
[mirror_zfs.git] / contrib / pyzfs / libzfs_core / _libzfs_core.py
1 #
2 # Copyright 2015 ClusterHQ
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 """
18 Python wrappers for libzfs_core interfaces.
19
20 As a rule, there is a Python function for each C function.
21 The signatures of the Python functions generally follow those of the
22 functions, but the argument types are natural to Python.
23 nvlists are wrapped as dictionaries or lists depending on their usage.
24 Some parameters have default values depending on typical use for
25 increased convenience. Output parameters are not used and return values
26 are directly returned. Error conditions are signalled by exceptions
27 rather than by integer error codes.
28 """
29 from __future__ import absolute_import, division, print_function
30
31 import errno
32 import functools
33 import fcntl
34 import os
35 import struct
36 import threading
37 from . import exceptions
38 from . import _error_translation as errors
39 from .bindings import libzfs_core
40 from ._constants import ( # noqa: F401
41 MAXNAMELEN,
42 ZCP_DEFAULT_INSTRLIMIT,
43 ZCP_DEFAULT_MEMLIMIT,
44 WRAPPING_KEY_LEN,
45 zfs_key_location,
46 zfs_keyformat,
47 zio_encrypt
48 )
49 from .ctypes import (
50 int32_t,
51 uint64_t
52 )
53 from ._nvlist import nvlist_in, nvlist_out
54
55
56 def _uncommitted(depends_on=None):
57 '''
58 Mark an API function as being an uncommitted extension that might not be
59 available.
60
61 :param function depends_on: the function that would be checked instead of
62 a decorated function. For example, if the decorated function uses
63 another uncommitted function.
64
65 This decorator transforms a decorated function to raise
66 :exc:`NotImplementedError` if the C libzfs_core library does not provide
67 a function with the same name as the decorated function.
68
69 The optional `depends_on` parameter can be provided if the decorated
70 function does not directly call the C function but instead calls another
71 Python function that follows the typical convention.
72 One example is :func:`lzc_list_snaps` that calls :func:`lzc_list` that
73 calls ``lzc_list`` in libzfs_core.
74
75 This decorator is implemented using :func:`is_supported`.
76 '''
77 def _uncommitted_decorator(func, depends_on=depends_on):
78 @functools.wraps(func)
79 def _f(*args, **kwargs):
80 if not is_supported(_f):
81 raise NotImplementedError(func.__name__)
82 return func(*args, **kwargs)
83 if depends_on is not None:
84 _f._check_func = depends_on
85 return _f
86 return _uncommitted_decorator
87
88
89 def lzc_create(name, ds_type='zfs', props=None, key=None):
90 '''
91 Create a ZFS filesystem or a ZFS volume ("zvol").
92
93 :param bytes name: a name of the dataset to be created.
94 :param str ds_type: the type of the dataset to be created,
95 currently supported types are "zfs" (the default) for a filesystem and
96 "zvol" for a volume.
97 :param props: a `dict` of ZFS dataset property name-value pairs
98 (empty by default).
99 :type props: dict of bytes:Any
100 :param key: dataset encryption key data (empty by default).
101 :type key: bytes
102
103 :raises FilesystemExists: if a dataset with the given name already exists.
104 :raises ParentNotFound: if a parent dataset of the requested dataset does
105 not exist.
106 :raises PropertyInvalid: if one or more of the specified properties is
107 invalid or has an invalid type or value.
108 :raises NameInvalid: if the name is not a valid dataset name.
109 :raises NameTooLong: if the name is too long.
110 :raises WrongParent: if the parent dataset of the requested dataset is not
111 a filesystem (e.g. ZVOL)
112 '''
113 if props is None:
114 props = {}
115 if key is None:
116 key = b""
117 else:
118 key = bytes(key)
119 if ds_type == 'zfs':
120 ds_type = _lib.DMU_OST_ZFS
121 elif ds_type == 'zvol':
122 ds_type = _lib.DMU_OST_ZVOL
123 else:
124 raise exceptions.DatasetTypeInvalid(ds_type)
125 nvlist = nvlist_in(props)
126 ret = _lib.lzc_create(name, ds_type, nvlist, key, len(key))
127 errors.lzc_create_translate_error(ret, name, ds_type, props)
128
129
130 def lzc_clone(name, origin, props=None):
131 '''
132 Clone a ZFS filesystem or a ZFS volume ("zvol") from a given snapshot.
133
134 :param bytes name: a name of the dataset to be created.
135 :param bytes origin: a name of the origin snapshot.
136 :param props: a `dict` of ZFS dataset property name-value pairs
137 (empty by default).
138 :type props: dict of bytes:Any
139
140 :raises FilesystemExists: if a dataset with the given name already exists.
141 :raises DatasetNotFound: if either a parent dataset of the requested
142 dataset or the origin snapshot does not exist.
143 :raises PropertyInvalid: if one or more of the specified properties is
144 invalid or has an invalid type or value.
145 :raises FilesystemNameInvalid: if the name is not a valid dataset name.
146 :raises SnapshotNameInvalid: if the origin is not a valid snapshot name.
147 :raises NameTooLong: if the name or the origin name is too long.
148 :raises PoolsDiffer: if the clone and the origin have different pool names.
149
150 .. note::
151 Because of a deficiency of the underlying C interface
152 :exc:`.DatasetNotFound` can mean that either a parent filesystem of
153 the target or the origin snapshot does not exist.
154 It is currently impossible to distinguish between the cases.
155 :func:`lzc_hold` can be used to check that the snapshot exists and
156 ensure that it is not destroyed before cloning.
157 '''
158 if props is None:
159 props = {}
160 nvlist = nvlist_in(props)
161 ret = _lib.lzc_clone(name, origin, nvlist)
162 errors.lzc_clone_translate_error(ret, name, origin, props)
163
164
165 def lzc_rollback(name):
166 '''
167 Roll back a filesystem or volume to its most recent snapshot.
168
169 Note that the latest snapshot may change if a new one is concurrently
170 created or the current one is destroyed. lzc_rollback_to can be used
171 to roll back to a specific latest snapshot.
172
173 :param bytes name: a name of the dataset to be rolled back.
174 :return: a name of the most recent snapshot.
175 :rtype: bytes
176
177 :raises FilesystemNotFound: if the dataset does not exist.
178 :raises SnapshotNotFound: if the dataset does not have any snapshots.
179 :raises NameInvalid: if the dataset name is invalid.
180 :raises NameTooLong: if the dataset name is too long.
181 '''
182 # Account for terminating NUL in C strings.
183 snapnamep = _ffi.new('char[]', MAXNAMELEN + 1)
184 ret = _lib.lzc_rollback(name, snapnamep, MAXNAMELEN + 1)
185 errors.lzc_rollback_translate_error(ret, name)
186 return _ffi.string(snapnamep)
187
188
189 def lzc_rollback_to(name, snap):
190 '''
191 Roll back this filesystem or volume to the specified snapshot, if possible.
192
193 :param bytes name: a name of the dataset to be rolled back.
194 :param bytes snap: a name of the snapshot to be rolled back.
195
196 :raises FilesystemNotFound: if the dataset does not exist.
197 :raises SnapshotNotFound: if the dataset does not have any snapshots.
198 :raises NameInvalid: if the dataset name is invalid.
199 :raises NameTooLong: if the dataset name is too long.
200 :raises SnapshotNotLatest: if the snapshot is not the latest.
201 '''
202 ret = _lib.lzc_rollback_to(name, snap)
203 errors.lzc_rollback_to_translate_error(ret, name, snap)
204
205
206 def lzc_snapshot(snaps, props=None):
207 '''
208 Create snapshots.
209
210 All snapshots must be in the same pool.
211
212 Optionally snapshot properties can be set on all snapshots.
213 Currently only user properties (prefixed with "user:") are supported.
214
215 Either all snapshots are successfully created or none are created if
216 an exception is raised.
217
218 :param snaps: a list of names of snapshots to be created.
219 :type snaps: list of bytes
220 :param props: a `dict` of ZFS dataset property name-value pairs
221 (empty by default).
222 :type props: dict of bytes:bytes
223
224 :raises SnapshotFailure: if one or more snapshots could not be created.
225
226 .. note::
227 :exc:`.SnapshotFailure` is a compound exception that provides at least
228 one detailed error object in :attr:`SnapshotFailure.errors` `list`.
229
230 .. warning::
231 The underlying implementation reports an individual, per-snapshot error
232 only for :exc:`.SnapshotExists` condition and *sometimes* for
233 :exc:`.NameTooLong`.
234 In all other cases a single error is reported without connection to any
235 specific snapshot name(s).
236
237 This has the following implications:
238
239 * if multiple error conditions are encountered only one of them is
240 reported
241
242 * unless only one snapshot is requested then it is impossible to tell
243 how many snapshots are problematic and what they are
244
245 * only if there are no other error conditions :exc:`.SnapshotExists`
246 is reported for all affected snapshots
247
248 * :exc:`.NameTooLong` can behave either in the same way as
249 :exc:`.SnapshotExists` or as all other exceptions.
250 The former is the case where the full snapshot name exceeds the
251 maximum allowed length but the short snapshot name (after '@') is
252 within the limit.
253 The latter is the case when the short name alone exceeds the maximum
254 allowed length.
255 '''
256 snaps_dict = {name: None for name in snaps}
257 errlist = {}
258 snaps_nvlist = nvlist_in(snaps_dict)
259 if props is None:
260 props = {}
261 props_nvlist = nvlist_in(props)
262 with nvlist_out(errlist) as errlist_nvlist:
263 ret = _lib.lzc_snapshot(snaps_nvlist, props_nvlist, errlist_nvlist)
264 errors.lzc_snapshot_translate_errors(ret, errlist, snaps, props)
265
266
267 lzc_snap = lzc_snapshot
268
269
270 def lzc_destroy_snaps(snaps, defer):
271 '''
272 Destroy snapshots.
273
274 They must all be in the same pool.
275 Snapshots that do not exist will be silently ignored.
276
277 If 'defer' is not set, and a snapshot has user holds or clones, the
278 destroy operation will fail and none of the snapshots will be
279 destroyed.
280
281 If 'defer' is set, and a snapshot has user holds or clones, it will be
282 marked for deferred destruction, and will be destroyed when the last hold
283 or clone is removed/destroyed.
284
285 The operation succeeds if all snapshots were destroyed (or marked for
286 later destruction if 'defer' is set) or didn't exist to begin with.
287
288 :param snaps: a list of names of snapshots to be destroyed.
289 :type snaps: list of bytes
290 :param bool defer: whether to mark busy snapshots for deferred destruction
291 rather than immediately failing.
292
293 :raises SnapshotDestructionFailure: if one or more snapshots could not be
294 created.
295
296 .. note::
297 :exc:`.SnapshotDestructionFailure` is a compound exception that
298 provides at least one detailed error object in
299 :attr:`SnapshotDestructionFailure.errors` `list`.
300
301 Typical error is :exc:`SnapshotIsCloned` if `defer` is `False`.
302 The snapshot names are validated quite loosely and invalid names are
303 typically ignored as nonexisting snapshots.
304
305 A snapshot name referring to a filesystem that doesn't exist is
306 ignored.
307 However, non-existent pool name causes :exc:`PoolNotFound`.
308 '''
309 snaps_dict = {name: None for name in snaps}
310 errlist = {}
311 snaps_nvlist = nvlist_in(snaps_dict)
312 with nvlist_out(errlist) as errlist_nvlist:
313 ret = _lib.lzc_destroy_snaps(snaps_nvlist, defer, errlist_nvlist)
314 errors.lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer)
315
316
317 def lzc_bookmark(bookmarks):
318 '''
319 Create bookmarks.
320
321 :param bookmarks: a dict that maps names of wanted bookmarks to names of
322 existing snapshots or bookmarks.
323 :type bookmarks: dict of bytes to bytes
324 :raises BookmarkFailure: if any of the bookmarks can not be created for any
325 reason.
326
327 The bookmarks `dict` maps from name of the bookmark
328 (e.g. :file:`{pool}/{fs}#{bmark}`) to the name of the snapshot
329 (e.g. :file:`{pool}/{fs}@{snap}`) or existint bookmark
330 :file:`{pool}/{fs}@{snap}`. All the bookmarks and snapshots must
331 be in the same pool.
332 '''
333 errlist = {}
334 nvlist = nvlist_in(bookmarks)
335 with nvlist_out(errlist) as errlist_nvlist:
336 ret = _lib.lzc_bookmark(nvlist, errlist_nvlist)
337 errors.lzc_bookmark_translate_errors(ret, errlist, bookmarks)
338
339
340 def lzc_get_bookmarks(fsname, props=None):
341 '''
342 Retrieve a listing of bookmarks for the given file system.
343
344 :param bytes fsname: a name of the filesystem.
345 :param props: a `list` of properties that will be returned for each
346 bookmark.
347 :type props: list of bytes
348 :return: a `dict` that maps the bookmarks' short names to their properties.
349 :rtype: dict of bytes:dict
350
351 :raises FilesystemNotFound: if the filesystem is not found.
352
353 The following are valid properties on bookmarks:
354
355 guid : integer
356 globally unique identifier of the snapshot the bookmark refers to
357 createtxg : integer
358 txg when the snapshot the bookmark refers to was created
359 creation : integer
360 timestamp when the snapshot the bookmark refers to was created
361
362 Any other properties passed in ``props`` are ignored without reporting
363 any error.
364 Values in the returned dictionary map the names of the requested properties
365 to their respective values.
366 '''
367 bmarks = {}
368 if props is None:
369 props = []
370 props_dict = {name: None for name in props}
371 nvlist = nvlist_in(props_dict)
372 with nvlist_out(bmarks) as bmarks_nvlist:
373 ret = _lib.lzc_get_bookmarks(fsname, nvlist, bmarks_nvlist)
374 errors.lzc_get_bookmarks_translate_error(ret, fsname, props)
375 return bmarks
376
377
378 def lzc_destroy_bookmarks(bookmarks):
379 '''
380 Destroy bookmarks.
381
382 :param bookmarks: a list of the bookmarks to be destroyed. The bookmarks
383 are specified as :file:`{fs}#{bmark}`.
384 :type bookmarks: list of bytes
385
386 :raises BookmarkDestructionFailure: if any of the bookmarks may not be
387 destroyed.
388
389 The bookmarks must all be in the same pool.
390 Bookmarks that do not exist will be silently ignored.
391 This also includes the case where the filesystem component of the bookmark
392 name does not exist.
393 However, an invalid bookmark name will cause :exc:`.NameInvalid` error
394 reported in :attr:`SnapshotDestructionFailure.errors`.
395
396 Either all bookmarks that existed are destroyed or an exception is raised.
397 '''
398 errlist = {}
399 bmarks_dict = {name: None for name in bookmarks}
400 nvlist = nvlist_in(bmarks_dict)
401 with nvlist_out(errlist) as errlist_nvlist:
402 ret = _lib.lzc_destroy_bookmarks(nvlist, errlist_nvlist)
403 errors.lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks)
404
405
406 def lzc_snaprange_space(firstsnap, lastsnap):
407 '''
408 Calculate a size of data referenced by snapshots in the inclusive range
409 between the ``firstsnap`` and the ``lastsnap`` and not shared with any
410 other datasets.
411
412 :param bytes firstsnap: the name of the first snapshot in the range.
413 :param bytes lastsnap: the name of the last snapshot in the range.
414 :return: the calculated stream size, in bytes.
415 :rtype: `int` or `long`
416
417 :raises SnapshotNotFound: if either of the snapshots does not exist.
418 :raises NameInvalid: if the name of either snapshot is invalid.
419 :raises NameTooLong: if the name of either snapshot is too long.
420 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
421 ``snapname``.
422 :raises PoolsDiffer: if the snapshots belong to different pools.
423
424 ``lzc_snaprange_space`` calculates total size of blocks that exist
425 because they are referenced only by one or more snapshots in the given
426 range but no other dataset.
427 In other words, this is the set of blocks that were born after the snap
428 before firstsnap, and died before the snap after the last snap.
429 Yet another interpretation is that the result of ``lzc_snaprange_space``
430 is the size of the space that would be freed if the snapshots in the range
431 are destroyed.
432
433 If the same snapshot is given as both the ``firstsnap`` and the
434 ``lastsnap``.
435 In that case ``lzc_snaprange_space`` calculates space used by the snapshot.
436 '''
437 valp = _ffi.new('uint64_t *')
438 ret = _lib.lzc_snaprange_space(firstsnap, lastsnap, valp)
439 errors.lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap)
440 return int(valp[0])
441
442
443 def lzc_hold(holds, fd=None):
444 '''
445 Create *user holds* on snapshots. If there is a hold on a snapshot,
446 the snapshot can not be destroyed. (However, it can be marked for
447 deletion by :func:`lzc_destroy_snaps` ( ``defer`` = `True` ).)
448
449 :param holds: the dictionary of names of the snapshots to hold mapped to
450 the hold names.
451 :type holds: dict of bytes : bytes
452 :type fd: int or None
453 :param fd: if not None then it must be the result of :func:`os.open`
454 called as ``os.open("/dev/zfs", O_EXCL)``.
455 :type fd: int or None
456 :return: a list of the snapshots that do not exist.
457 :rtype: list of bytes
458
459 :raises HoldFailure: if a hold was impossible on one or more of the
460 snapshots.
461 :raises BadHoldCleanupFD: if ``fd`` is not a valid file descriptor
462 associated with :file:`/dev/zfs`.
463
464 The snapshots must all be in the same pool.
465
466 If ``fd`` is not None, then when the ``fd`` is closed (including on process
467 termination), the holds will be released. If the system is shut down
468 uncleanly, the holds will be released when the pool is next opened
469 or imported.
470
471 Holds for snapshots which don't exist will be skipped and have an entry
472 added to the return value, but will not cause an overall failure.
473 No exceptions is raised if all holds, for snapshots that existed, were
474 successfully created.
475 Otherwise :exc:`.HoldFailure` exception is raised and no holds will be
476 created.
477 :attr:`.HoldFailure.errors` may contain a single element for an error that
478 is not specific to any hold / snapshot, or it may contain one or more
479 elements detailing specific error per each affected hold.
480 '''
481 errlist = {}
482 if fd is None:
483 fd = -1
484 nvlist = nvlist_in(holds)
485 with nvlist_out(errlist) as errlist_nvlist:
486 ret = _lib.lzc_hold(nvlist, fd, errlist_nvlist)
487 errors.lzc_hold_translate_errors(ret, errlist, holds, fd)
488 # If there is no error (no exception raised by _handleErrList), but errlist
489 # is not empty, then it contains missing snapshots.
490 assert all(errlist[x] == errno.ENOENT for x in errlist)
491 return list(errlist.keys())
492
493
494 def lzc_release(holds):
495 '''
496 Release *user holds* on snapshots.
497
498 If the snapshot has been marked for
499 deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
500 any clones, and all the user holds are removed, then the snapshot will be
501 destroyed.
502
503 The snapshots must all be in the same pool.
504
505 :param holds: a ``dict`` where keys are snapshot names and values are
506 lists of hold tags to remove.
507 :type holds: dict of bytes : list of bytes
508 :return: a list of any snapshots that do not exist and of any tags that do
509 not exist for existing snapshots.
510 Such tags are qualified with a corresponding snapshot name using the
511 following format :file:`{pool}/{fs}@{snap}#{tag}`
512 :rtype: list of bytes
513
514 :raises HoldReleaseFailure: if one or more existing holds could not be
515 released.
516
517 Holds which failed to release because they didn't exist will have an entry
518 added to errlist, but will not cause an overall failure.
519
520 This call is success if ``holds`` was empty or all holds that
521 existed, were successfully removed.
522 Otherwise an exception will be raised.
523 '''
524 errlist = {}
525 holds_dict = {}
526 for snap in holds:
527 hold_list = holds[snap]
528 if not isinstance(hold_list, list):
529 raise TypeError('holds must be in a list')
530 holds_dict[snap] = {hold: None for hold in hold_list}
531 nvlist = nvlist_in(holds_dict)
532 with nvlist_out(errlist) as errlist_nvlist:
533 ret = _lib.lzc_release(nvlist, errlist_nvlist)
534 errors.lzc_release_translate_errors(ret, errlist, holds)
535 # If there is no error (no exception raised by _handleErrList), but errlist
536 # is not empty, then it contains missing snapshots and tags.
537 assert all(errlist[x] == errno.ENOENT for x in errlist)
538 return list(errlist.keys())
539
540
541 def lzc_get_holds(snapname):
542 '''
543 Retrieve list of *user holds* on the specified snapshot.
544
545 :param bytes snapname: the name of the snapshot.
546 :return: holds on the snapshot along with their creation times
547 in seconds since the epoch
548 :rtype: dict of bytes : int
549 '''
550 holds = {}
551 with nvlist_out(holds) as nvlist:
552 ret = _lib.lzc_get_holds(snapname, nvlist)
553 errors.lzc_get_holds_translate_error(ret, snapname)
554 return holds
555
556
557 def lzc_send(snapname, fromsnap, fd, flags=None):
558 '''
559 Generate a zfs send stream for the specified snapshot and write it to
560 the specified file descriptor.
561
562 :param bytes snapname: the name of the snapshot to send.
563 :param fromsnap: if not None the name of the starting snapshot
564 for the incremental stream.
565 :type fromsnap: bytes or None
566 :param int fd: the file descriptor to write the send stream to.
567 :param flags: the flags that control what enhanced features can be used in
568 the stream.
569 :type flags: list of bytes
570
571 :raises SnapshotNotFound: if either the starting snapshot is not `None` and
572 does not exist, or if the ending snapshot does not exist.
573 :raises NameInvalid: if the name of either snapshot is invalid.
574 :raises NameTooLong: if the name of either snapshot is too long.
575 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
576 ``snapname``.
577 :raises PoolsDiffer: if the snapshots belong to different pools.
578 :raises IOError: if an input / output error occurs while writing to ``fd``.
579 :raises UnknownStreamFeature: if the ``flags`` contain an unknown flag
580 name.
581
582 If ``fromsnap`` is None, a full (non-incremental) stream will be sent.
583 If ``fromsnap`` is not None, it must be the full name of a snapshot or
584 bookmark to send an incremental from, e.g.
585 :file:`{pool}/{fs}@{earlier_snap}` or :file:`{pool}/{fs}#{earlier_bmark}`.
586
587 The specified snapshot or bookmark must represent an earlier point in the
588 history of ``snapname``.
589 It can be an earlier snapshot in the same filesystem or zvol as
590 ``snapname``, or it can be the origin of ``snapname``'s filesystem, or an
591 earlier snapshot in the origin, etc.
592 ``fromsnap`` must be strictly an earlier snapshot, specifying the same
593 snapshot as both ``fromsnap`` and ``snapname`` is an error.
594
595 If ``flags`` contains *"large_blocks"*, the stream is permitted
596 to contain ``DRR_WRITE`` records with ``drr_length`` > 128K,
597 and ``DRR_OBJECT`` records with ``drr_blksz`` > 128K.
598
599 If ``flags`` contains *"embedded_data"*, the stream is permitted
600 to contain ``DRR_WRITE_EMBEDDED`` records with
601 ``drr_etype`` == ``BP_EMBEDDED_TYPE_DATA``,
602 which the receiving system must support (as indicated by support
603 for the *embedded_data* feature).
604
605 If ``flags`` contains *"compress"*, the stream is generated by using
606 compressed WRITE records for blocks which are compressed on disk and
607 in memory. If the *lz4_compress* feature is active on the sending
608 system, then the receiving system must have that feature enabled as well.
609
610 If ``flags`` contains *"raw"*, the stream is generated, for encrypted
611 datasets, by sending data exactly as it exists on disk. This allows
612 backups to be taken even if encryption keys are not currently loaded.
613
614 .. note::
615 ``lzc_send`` can actually accept a filesystem name as the ``snapname``.
616 In that case ``lzc_send`` acts as if a temporary snapshot was created
617 after the start of the call and before the stream starts being
618 produced.
619
620 .. note::
621 ``lzc_send`` does not return until all of the stream is written to
622 ``fd``.
623
624 .. note::
625 ``lzc_send`` does *not* close ``fd`` upon returning.
626 '''
627 if fromsnap is not None:
628 c_fromsnap = fromsnap
629 else:
630 c_fromsnap = _ffi.NULL
631 c_flags = 0
632 if flags is None:
633 flags = []
634 for flag in flags:
635 c_flag = {
636 'embedded_data': _lib.LZC_SEND_FLAG_EMBED_DATA,
637 'large_blocks': _lib.LZC_SEND_FLAG_LARGE_BLOCK,
638 'compress': _lib.LZC_SEND_FLAG_COMPRESS,
639 'raw': _lib.LZC_SEND_FLAG_RAW,
640 }.get(flag)
641 if c_flag is None:
642 raise exceptions.UnknownStreamFeature(flag)
643 c_flags |= c_flag
644
645 ret = _lib.lzc_send(snapname, c_fromsnap, fd, c_flags)
646 errors.lzc_send_translate_error(ret, snapname, fromsnap, fd, flags)
647
648
649 def lzc_send_space(snapname, fromsnap=None, flags=None):
650 '''
651 Estimate size of a full or incremental backup stream
652 given the optional starting snapshot and the ending snapshot.
653
654 :param bytes snapname: the name of the snapshot for which the estimate
655 should be done.
656 :param fromsnap: the optional starting snapshot name.
657 If not `None` then an incremental stream size is estimated, otherwise
658 a full stream is estimated.
659 :type fromsnap: `bytes` or `None`
660 :param flags: the flags that control what enhanced features can be used
661 in the stream.
662 :type flags: list of bytes
663
664 :return: the estimated stream size, in bytes.
665 :rtype: `int` or `long`
666
667 :raises SnapshotNotFound: if either the starting snapshot is not `None` and
668 does not exist, or if the ending snapshot does not exist.
669 :raises NameInvalid: if the name of either snapshot is invalid.
670 :raises NameTooLong: if the name of either snapshot is too long.
671 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
672 ``snapname``.
673 :raises PoolsDiffer: if the snapshots belong to different pools.
674
675 ``fromsnap``, if not ``None``, must be strictly an earlier snapshot,
676 specifying the same snapshot as both ``fromsnap`` and ``snapname`` is an
677 error.
678 '''
679 if fromsnap is not None:
680 c_fromsnap = fromsnap
681 else:
682 c_fromsnap = _ffi.NULL
683 c_flags = 0
684 if flags is None:
685 flags = []
686 for flag in flags:
687 c_flag = {
688 'embedded_data': _lib.LZC_SEND_FLAG_EMBED_DATA,
689 'large_blocks': _lib.LZC_SEND_FLAG_LARGE_BLOCK,
690 'compress': _lib.LZC_SEND_FLAG_COMPRESS,
691 'raw': _lib.LZC_SEND_FLAG_RAW,
692 }.get(flag)
693 if c_flag is None:
694 raise exceptions.UnknownStreamFeature(flag)
695 c_flags |= c_flag
696 valp = _ffi.new('uint64_t *')
697
698 ret = _lib.lzc_send_space(snapname, c_fromsnap, c_flags, valp)
699 errors.lzc_send_space_translate_error(ret, snapname, fromsnap)
700 return int(valp[0])
701
702
703 def lzc_receive(snapname, fd, force=False, raw=False, origin=None, props=None):
704 '''
705 Receive from the specified ``fd``, creating the specified snapshot.
706
707 :param bytes snapname: the name of the snapshot to create.
708 :param int fd: the file descriptor from which to read the stream.
709 :param bool force: whether to roll back or destroy the target filesystem
710 if that is required to receive the stream.
711 :param bool raw: whether this is a "raw" stream.
712 :param origin: the optional origin snapshot name if the stream is for a
713 clone.
714 :type origin: bytes or None
715 :param props: the properties to set on the snapshot as *received*
716 properties.
717 :type props: dict of bytes : Any
718
719 :raises IOError: if an input / output error occurs while reading from the
720 ``fd``.
721 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
722 :raises DatasetExists: if the stream is a full stream and the destination
723 filesystem already exists.
724 :raises DatasetExists: if ``force`` is `True` but the destination
725 filesystem could not be rolled back to a matching snapshot because a
726 newer snapshot exists and it is an origin of a cloned filesystem.
727 :raises StreamMismatch: if an incremental stream is received and the latest
728 snapshot of the destination filesystem does not match the source
729 snapshot of the stream.
730 :raises StreamMismatch: if a full stream is received and the destination
731 filesystem already exists and it has at least one snapshot, and
732 ``force`` is `False`.
733 :raises StreamMismatch: if an incremental clone stream is received but the
734 specified ``origin`` is not the actual received origin.
735 :raises DestinationModified: if an incremental stream is received and the
736 destination filesystem has been modified since the last snapshot and
737 ``force`` is `False`.
738 :raises DestinationModified: if a full stream is received and the
739 destination filesystem already exists and it does not have any
740 snapshots, and ``force`` is `False`.
741 :raises DatasetNotFound: if the destination filesystem and its parent do
742 not exist.
743 :raises DatasetNotFound: if the ``origin`` is not `None` and does not
744 exist.
745 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
746 could not be rolled back to a matching snapshot because a newer
747 snapshot is held and could not be destroyed.
748 :raises DatasetBusy: if another receive operation is being performed on the
749 destination filesystem.
750 :raises BadStream: if the stream is corrupt or it is not recognized or it
751 is a compound stream or it is a clone stream, but ``origin`` is `None`.
752 :raises BadStream: if a clone stream is received and the destination
753 filesystem already exists.
754 :raises StreamFeatureNotSupported: if the stream has a feature that is not
755 supported on this side.
756 :raises NameInvalid: if the name of either snapshot is invalid.
757 :raises NameTooLong: if the name of either snapshot is too long.
758 :raises WrongParent: if the parent dataset of the received destination is
759 not a filesystem (e.g. ZVOL)
760
761 .. note::
762 The ``origin`` is ignored if the actual stream is an incremental stream
763 that is not a clone stream and the destination filesystem exists.
764 If the stream is a full stream and the destination filesystem does not
765 exist then the ``origin`` is checked for existence: if it does not
766 exist :exc:`.DatasetNotFound` is raised, otherwise
767 :exc:`.StreamMismatch` is raised, because that snapshot can not have
768 any relation to the stream.
769
770 .. note::
771 If ``force`` is `True` and the stream is incremental then the
772 destination filesystem is rolled back to a matching source snapshot if
773 necessary. Intermediate snapshots are destroyed in that case.
774
775 However, none of the existing snapshots may have the same name as
776 ``snapname`` even if such a snapshot were to be destroyed.
777 The existing ``snapname`` snapshot always causes
778 :exc:`.SnapshotExists` to be raised.
779
780 If ``force`` is `True` and the stream is a full stream then the
781 destination filesystem is replaced with the received filesystem unless
782 the former has any snapshots. This prevents the destination filesystem
783 from being rolled back / replaced.
784
785 .. note::
786 This interface does not work on dedup'd streams
787 (those with ``DMU_BACKUP_FEATURE_DEDUP``).
788
789 .. note::
790 ``lzc_receive`` does not return until all of the stream is read from
791 ``fd`` and applied to the pool.
792
793 .. note::
794 ``lzc_receive`` does *not* close ``fd`` upon returning.
795 '''
796
797 if origin is not None:
798 c_origin = origin
799 else:
800 c_origin = _ffi.NULL
801 if props is None:
802 props = {}
803 nvlist = nvlist_in(props)
804 ret = _lib.lzc_receive(snapname, nvlist, c_origin, force, raw, fd)
805 errors.lzc_receive_translate_errors(
806 ret, snapname, fd, force, raw, False, False, origin, None
807 )
808
809
810 lzc_recv = lzc_receive
811
812
813 def lzc_exists(name):
814 '''
815 Check if a dataset (a filesystem, or a volume, or a snapshot)
816 with the given name exists.
817
818 :param bytes name: the dataset name to check.
819 :return: `True` if the dataset exists, `False` otherwise.
820 :rtype: bool
821
822 .. note::
823 ``lzc_exists`` can not be used to check for existence of bookmarks.
824 '''
825 ret = _lib.lzc_exists(name)
826 return bool(ret)
827
828
829 @_uncommitted()
830 def lzc_change_key(fsname, crypt_cmd, props=None, key=None):
831 '''
832 Change encryption key on the specified dataset.
833
834 :param bytes fsname: the name of the dataset.
835 :param str crypt_cmd: the encryption "command" to be executed, currently
836 supported values are "new_key", "inherit", "force_new_key" and
837 "force_inherit".
838 :param props: a `dict` of encryption-related property name-value pairs;
839 only "keyformat", "keylocation" and "pbkdf2iters" are supported
840 (empty by default).
841 :type props: dict of bytes:Any
842 :param key: dataset encryption key data (empty by default).
843 :type key: bytes
844
845 :raises PropertyInvalid: if ``props`` contains invalid values.
846 :raises FilesystemNotFound: if the dataset does not exist.
847 :raises UnknownCryptCommand: if ``crypt_cmd`` is invalid.
848 :raises EncryptionKeyNotLoaded: if the encryption key is not currently
849 loaded and therefore cannot be changed.
850 '''
851 if props is None:
852 props = {}
853 if key is None:
854 key = b""
855 else:
856 key = bytes(key)
857 cmd = {
858 'new_key': _lib.DCP_CMD_NEW_KEY,
859 'inherit': _lib.DCP_CMD_INHERIT,
860 'force_new_key': _lib.DCP_CMD_FORCE_NEW_KEY,
861 'force_inherit': _lib.DCP_CMD_FORCE_INHERIT,
862 }.get(crypt_cmd)
863 if cmd is None:
864 raise exceptions.UnknownCryptCommand(crypt_cmd)
865 nvlist = nvlist_in(props)
866 ret = _lib.lzc_change_key(fsname, cmd, nvlist, key, len(key))
867 errors.lzc_change_key_translate_error(ret, fsname)
868
869
870 @_uncommitted()
871 def lzc_load_key(fsname, noop, key):
872 '''
873 Load or verify encryption key on the specified dataset.
874
875 :param bytes fsname: the name of the dataset.
876 :param bool noop: if `True` the encryption key will only be verified,
877 not loaded.
878 :param key: dataset encryption key data.
879 :type key: bytes
880
881 :raises FilesystemNotFound: if the dataset does not exist.
882 :raises EncryptionKeyAlreadyLoaded: if the encryption key is already
883 loaded.
884 :raises EncryptionKeyInvalid: if the encryption key provided is incorrect.
885 '''
886 ret = _lib.lzc_load_key(fsname, noop, key, len(key))
887 errors.lzc_load_key_translate_error(ret, fsname, noop)
888
889
890 @_uncommitted()
891 def lzc_unload_key(fsname):
892 '''
893 Unload encryption key from the specified dataset.
894
895 :param bytes fsname: the name of the dataset.
896
897 :raises FilesystemNotFound: if the dataset does not exist.
898 :raises DatasetBusy: if the encryption key is still being used. This
899 usually occurs when the dataset is mounted.
900 :raises EncryptionKeyNotLoaded: if the encryption key is not currently
901 loaded.
902 '''
903 ret = _lib.lzc_unload_key(fsname)
904 errors.lzc_unload_key_translate_error(ret, fsname)
905
906
907 def lzc_channel_program(
908 poolname, program, instrlimit=ZCP_DEFAULT_INSTRLIMIT,
909 memlimit=ZCP_DEFAULT_MEMLIMIT, params=None
910 ):
911 '''
912 Executes a script as a ZFS channel program on pool ``poolname``.
913
914 :param bytes poolname: the name of the pool.
915 :param bytes program: channel program text.
916 :param int instrlimit: execution time limit, in milliseconds.
917 :param int memlimit: execution memory limit, in bytes.
918 :param bytes params: a `list` of parameters passed to the channel program
919 (empty by default).
920 :type params: dict of bytes:Any
921 :return: a dictionary of result values procuced by the channel program,
922 if any.
923 :rtype: dict
924
925 :raises PoolNotFound: if the pool does not exist.
926 :raises ZCPLimitInvalid: if either instruction or memory limit are invalid.
927 :raises ZCPSyntaxError: if the channel program contains syntax errors.
928 :raises ZCPTimeout: if the channel program took too long to execute.
929 :raises ZCPSpaceError: if the channel program exhausted the memory limit.
930 :raises ZCPMemoryError: if the channel program return value was too large.
931 :raises ZCPPermissionError: if the user lacks the permission to run the
932 channel program. Channel programs must be run as root.
933 :raises ZCPRuntimeError: if the channel program encountered a runtime
934 error.
935 '''
936 output = {}
937 params_nv = nvlist_in({b"argv": params})
938 with nvlist_out(output) as outnvl:
939 ret = _lib.lzc_channel_program(
940 poolname, program, instrlimit, memlimit, params_nv, outnvl)
941 errors.lzc_channel_program_translate_error(
942 ret, poolname, output.get(b"error"))
943 return output.get(b"return")
944
945
946 def lzc_channel_program_nosync(
947 poolname, program, instrlimit=ZCP_DEFAULT_INSTRLIMIT,
948 memlimit=ZCP_DEFAULT_MEMLIMIT, params=None
949 ):
950 '''
951 Executes a script as a read-only ZFS channel program on pool ``poolname``.
952 A read-only channel program works programmatically the same way as a
953 normal channel program executed with
954 :func:`lzc_channel_program`. The only difference is it runs exclusively in
955 open-context and therefore can return faster.
956 The downside to that, is that the program cannot change on-disk state by
957 calling functions from the zfs.sync submodule.
958
959 :param bytes poolname: the name of the pool.
960 :param bytes program: channel program text.
961 :param int instrlimit: execution time limit, in milliseconds.
962 :param int memlimit: execution memory limit, in bytes.
963 :param bytes params: a `list` of parameters passed to the channel program
964 (empty by default).
965 :type params: dict of bytes:Any
966 :return: a dictionary of result values procuced by the channel program,
967 if any.
968 :rtype: dict
969
970 :raises PoolNotFound: if the pool does not exist.
971 :raises ZCPLimitInvalid: if either instruction or memory limit are invalid.
972 :raises ZCPSyntaxError: if the channel program contains syntax errors.
973 :raises ZCPTimeout: if the channel program took too long to execute.
974 :raises ZCPSpaceError: if the channel program exhausted the memory limit.
975 :raises ZCPMemoryError: if the channel program return value was too large.
976 :raises ZCPPermissionError: if the user lacks the permission to run the
977 channel program. Channel programs must be run as root.
978 :raises ZCPRuntimeError: if the channel program encountered a runtime
979 error.
980 '''
981 output = {}
982 params_nv = nvlist_in({b"argv": params})
983 with nvlist_out(output) as outnvl:
984 ret = _lib.lzc_channel_program_nosync(
985 poolname, program, instrlimit, memlimit, params_nv, outnvl)
986 errors.lzc_channel_program_translate_error(
987 ret, poolname, output.get(b"error"))
988 return output.get(b"return")
989
990
991 def lzc_receive_resumable(
992 snapname, fd, force=False, raw=False, origin=None, props=None
993 ):
994 '''
995 Like :func:`lzc_receive`, but if the receive fails due to premature stream
996 termination, the intermediate state will be preserved on disk. In this
997 case, ECKSUM will be returned. The receive may subsequently be resumed
998 with a resuming send stream generated by lzc_send_resume().
999
1000 :param bytes snapname: the name of the snapshot to create.
1001 :param int fd: the file descriptor from which to read the stream.
1002 :param bool force: whether to roll back or destroy the target filesystem
1003 if that is required to receive the stream.
1004 :param bool raw: whether this is a "raw" stream.
1005 :param origin: the optional origin snapshot name if the stream is for a
1006 clone.
1007 :type origin: bytes or None
1008 :param props: the properties to set on the snapshot as *received*
1009 properties.
1010 :type props: dict of bytes : Any
1011
1012 :raises IOError: if an input / output error occurs while reading from the
1013 ``fd``.
1014 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1015 :raises DatasetExists: if the stream is a full stream and the destination
1016 filesystem already exists.
1017 :raises DatasetExists: if ``force`` is `True` but the destination
1018 filesystem could not be rolled back to a matching snapshot because a
1019 newer snapshot exists and it is an origin of a cloned filesystem.
1020 :raises StreamMismatch: if an incremental stream is received and the latest
1021 snapshot of the destination filesystem does not match the source
1022 snapshot of the stream.
1023 :raises StreamMismatch: if a full stream is received and the destination
1024 filesystem already exists and it has at least one snapshot, and
1025 ``force`` is `False`.
1026 :raises StreamMismatch: if an incremental clone stream is received but the
1027 specified ``origin`` is not the actual received origin.
1028 :raises DestinationModified: if an incremental stream is received and the
1029 destination filesystem has been modified since the last snapshot and
1030 ``force`` is `False`.
1031 :raises DestinationModified: if a full stream is received and the
1032 destination filesystem already exists and it does not have any
1033 snapshots, and ``force`` is `False`.
1034 :raises DatasetNotFound: if the destination filesystem and its parent do
1035 not exist.
1036 :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1037 exist.
1038 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1039 could not be rolled back to a matching snapshot because a newer
1040 snapshot is held and could not be destroyed.
1041 :raises DatasetBusy: if another receive operation is being performed on the
1042 destination filesystem.
1043 :raises BadStream: if the stream is corrupt or it is not recognized or it
1044 is a compound stream or it is a clone stream, but ``origin`` is `None`.
1045 :raises BadStream: if a clone stream is received and the destination
1046 filesystem already exists.
1047 :raises StreamFeatureNotSupported: if the stream has a feature that is not
1048 supported on this side.
1049 :raises NameInvalid: if the name of either snapshot is invalid.
1050 :raises NameTooLong: if the name of either snapshot is too long.
1051 '''
1052
1053 if origin is not None:
1054 c_origin = origin
1055 else:
1056 c_origin = _ffi.NULL
1057 if props is None:
1058 props = {}
1059 nvlist = nvlist_in(props)
1060 ret = _lib.lzc_receive_resumable(
1061 snapname, nvlist, c_origin, force, raw, fd)
1062 errors.lzc_receive_translate_errors(
1063 ret, snapname, fd, force, raw, False, False, origin, None)
1064
1065
1066 def lzc_receive_with_header(
1067 snapname, fd, begin_record, force=False, resumable=False, raw=False,
1068 origin=None, props=None
1069 ):
1070 '''
1071 Like :func:`lzc_receive`, but allows the caller to read the begin record
1072 and then to pass it in.
1073
1074 That could be useful if the caller wants to derive, for example,
1075 the snapname or the origin parameters based on the information contained in
1076 the begin record.
1077 :func:`receive_header` can be used to receive the begin record from the
1078 file descriptor.
1079
1080 :param bytes snapname: the name of the snapshot to create.
1081 :param int fd: the file descriptor from which to read the stream.
1082 :param begin_record: the stream's begin record.
1083 :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1084 structure.
1085 :param bool force: whether to roll back or destroy the target filesystem
1086 if that is required to receive the stream.
1087 :param bool resumable: whether this stream should be treated as resumable.
1088 If the receive fails due to premature stream termination, the
1089 intermediate state will be preserved on disk and may subsequently be
1090 resumed with :func:`lzc_send_resume`.
1091 :param bool raw: whether this is a "raw" stream.
1092 :param origin: the optional origin snapshot name if the stream is for a
1093 clone.
1094 :type origin: bytes or None
1095 :param props: the properties to set on the snapshot as *received*
1096 properties.
1097 :type props: dict of bytes : Any
1098
1099 :raises IOError: if an input / output error occurs while reading from the
1100 ``fd``.
1101 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1102 :raises DatasetExists: if the stream is a full stream and the destination
1103 filesystem already exists.
1104 :raises DatasetExists: if ``force`` is `True` but the destination
1105 filesystem could not be rolled back to a matching snapshot because a
1106 newer snapshot exists and it is an origin of a cloned filesystem.
1107 :raises StreamMismatch: if an incremental stream is received and the latest
1108 snapshot of the destination filesystem does not match the source
1109 snapshot of the stream.
1110 :raises StreamMismatch: if a full stream is received and the destination
1111 filesystem already exists and it has at least one snapshot, and
1112 ``force`` is `False`.
1113 :raises StreamMismatch: if an incremental clone stream is received but the
1114 specified ``origin`` is not the actual received origin.
1115 :raises DestinationModified: if an incremental stream is received and the
1116 destination filesystem has been modified since the last snapshot and
1117 ``force`` is `False`.
1118 :raises DestinationModified: if a full stream is received and the
1119 destination filesystem already exists and it does not have any
1120 snapshots, and ``force`` is `False`.
1121 :raises DatasetNotFound: if the destination filesystem and its parent do
1122 not exist.
1123 :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1124 exist.
1125 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1126 could not be rolled back to a matching snapshot because a newer
1127 snapshot is held and could not be destroyed.
1128 :raises DatasetBusy: if another receive operation is being performed on the
1129 destination filesystem.
1130 :raises BadStream: if the stream is corrupt or it is not recognized or it
1131 is a compound stream or it is a clone stream, but ``origin`` is `None`.
1132 :raises BadStream: if a clone stream is received and the destination
1133 filesystem already exists.
1134 :raises StreamFeatureNotSupported: if the stream has a feature that is not
1135 supported on this side.
1136 :raises NameInvalid: if the name of either snapshot is invalid.
1137 :raises NameTooLong: if the name of either snapshot is too long.
1138 '''
1139
1140 if origin is not None:
1141 c_origin = origin
1142 else:
1143 c_origin = _ffi.NULL
1144 if props is None:
1145 props = {}
1146 nvlist = nvlist_in(props)
1147 ret = _lib.lzc_receive_with_header(
1148 snapname, nvlist, c_origin, force, resumable, raw, fd, begin_record)
1149 errors.lzc_receive_translate_errors(
1150 ret, snapname, fd, force, raw, False, False, origin, None)
1151
1152
1153 def receive_header(fd):
1154 '''
1155 Read the begin record of the ZFS backup stream from the given file
1156 descriptor.
1157
1158 This is a helper function for :func:`lzc_receive_with_header`.
1159
1160 :param int fd: the file descriptor from which to read the stream.
1161 :return: a tuple with two elements where the first one is a Python `dict`
1162 representing the fields of the begin record and the second one is an
1163 opaque object suitable for passing to :func:`lzc_receive_with_header`.
1164 :raises IOError: if an input / output error occurs while reading from the
1165 ``fd``.
1166
1167 At present the following fields can be of interest in the header:
1168
1169 drr_toname : bytes
1170 the name of the snapshot for which the stream has been created
1171 drr_toguid : integer
1172 the GUID of the snapshot for which the stream has been created
1173 drr_fromguid : integer
1174 the GUID of the starting snapshot in the case the stream is
1175 incremental, zero otherwise
1176 drr_flags : integer
1177 the flags describing the stream's properties
1178 drr_type : integer
1179 the type of the dataset for which the stream has been created
1180 (volume, filesystem)
1181 '''
1182 # read sizeof(dmu_replay_record_t) bytes directly into the memory backing
1183 # 'record'
1184 record = _ffi.new("dmu_replay_record_t *")
1185 _ffi.buffer(record)[:] = os.read(fd, _ffi.sizeof(record[0]))
1186 # get drr_begin member and its representation as a Python dict
1187 drr_begin = record.drr_u.drr_begin
1188 header = {}
1189 for field, descr in _ffi.typeof(drr_begin).fields:
1190 if descr.type.kind == 'primitive':
1191 header[field] = getattr(drr_begin, field)
1192 elif descr.type.kind == 'enum':
1193 header[field] = getattr(drr_begin, field)
1194 elif descr.type.kind == 'array' and descr.type.item.cname == 'char':
1195 header[field] = _ffi.string(getattr(drr_begin, field))
1196 else:
1197 raise TypeError(
1198 'Unexpected field type in drr_begin: ' + str(descr.type))
1199 return (header, record)
1200
1201
1202 @_uncommitted()
1203 def lzc_receive_one(
1204 snapname, fd, begin_record, force=False, resumable=False, raw=False,
1205 origin=None, props=None, cleanup_fd=-1, action_handle=0
1206 ):
1207 '''
1208 Like :func:`lzc_receive`, but allows the caller to pass all supported
1209 arguments and retrieve all values returned. The only additional input
1210 parameter is 'cleanup_fd' which is used to set a cleanup-on-exit file
1211 descriptor.
1212
1213 :param bytes snapname: the name of the snapshot to create.
1214 :param int fd: the file descriptor from which to read the stream.
1215 :param begin_record: the stream's begin record.
1216 :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1217 structure.
1218 :param bool force: whether to roll back or destroy the target filesystem
1219 if that is required to receive the stream.
1220 :param bool resumable: whether this stream should be treated as resumable.
1221 If the receive fails due to premature stream termination, the
1222 intermediate state will be preserved on disk and may subsequently be
1223 resumed with :func:`lzc_send_resume`.
1224 :param bool raw: whether this is a "raw" stream.
1225 :param origin: the optional origin snapshot name if the stream is for a
1226 clone.
1227 :type origin: bytes or None
1228 :param props: the properties to set on the snapshot as *received*
1229 properties.
1230 :type props: dict of bytes : Any
1231 :param int cleanup_fd: file descriptor used to set a cleanup-on-exit file
1232 descriptor.
1233 :param int action_handle: variable used to pass the handle for guid/ds
1234 mapping: this should be set to zero on first call and will contain an
1235 updated handle on success, which should be passed in subsequent calls.
1236
1237 :return: a tuple with two elements where the first one is the number of
1238 bytes read from the file descriptor and the second one is the
1239 action_handle return value.
1240
1241 :raises IOError: if an input / output error occurs while reading from the
1242 ``fd``.
1243 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1244 :raises DatasetExists: if the stream is a full stream and the destination
1245 filesystem already exists.
1246 :raises DatasetExists: if ``force`` is `True` but the destination
1247 filesystem could not be rolled back to a matching snapshot because a
1248 newer snapshot exists and it is an origin of a cloned filesystem.
1249 :raises StreamMismatch: if an incremental stream is received and the latest
1250 snapshot of the destination filesystem does not match the source
1251 snapshot of the stream.
1252 :raises StreamMismatch: if a full stream is received and the destination
1253 filesystem already exists and it has at least one snapshot, and
1254 ``force`` is `False`.
1255 :raises StreamMismatch: if an incremental clone stream is received but the
1256 specified ``origin`` is not the actual received origin.
1257 :raises DestinationModified: if an incremental stream is received and the
1258 destination filesystem has been modified since the last snapshot and
1259 ``force`` is `False`.
1260 :raises DestinationModified: if a full stream is received and the
1261 destination filesystem already exists and it does not have any
1262 snapshots, and ``force`` is `False`.
1263 :raises DatasetNotFound: if the destination filesystem and its parent do
1264 not exist.
1265 :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1266 exist.
1267 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1268 could not be rolled back to a matching snapshot because a newer
1269 snapshot is held and could not be destroyed.
1270 :raises DatasetBusy: if another receive operation is being performed on the
1271 destination filesystem.
1272 :raises BadStream: if the stream is corrupt or it is not recognized or it
1273 is a compound stream or it is a clone stream, but ``origin`` is `None`.
1274 :raises BadStream: if a clone stream is received and the destination
1275 filesystem already exists.
1276 :raises StreamFeatureNotSupported: if the stream has a feature that is not
1277 supported on this side.
1278 :raises ReceivePropertyFailure: if one or more of the specified properties
1279 is invalid or has an invalid type or value.
1280 :raises NameInvalid: if the name of either snapshot is invalid.
1281 :raises NameTooLong: if the name of either snapshot is too long.
1282 '''
1283
1284 if origin is not None:
1285 c_origin = origin
1286 else:
1287 c_origin = _ffi.NULL
1288 if action_handle is not None:
1289 c_action_handle = _ffi.new("uint64_t *")
1290 else:
1291 c_action_handle = _ffi.NULL
1292 c_read_bytes = _ffi.new("uint64_t *")
1293 c_errflags = _ffi.new("uint64_t *")
1294 if props is None:
1295 props = {}
1296 nvlist = nvlist_in(props)
1297 properrs = {}
1298 with nvlist_out(properrs) as c_errors:
1299 ret = _lib.lzc_receive_one(
1300 snapname, nvlist, c_origin, force, resumable, raw, fd,
1301 begin_record, cleanup_fd, c_read_bytes, c_errflags,
1302 c_action_handle, c_errors)
1303 errors.lzc_receive_translate_errors(
1304 ret, snapname, fd, force, raw, False, False, origin, properrs)
1305 return (int(c_read_bytes[0]), action_handle)
1306
1307
1308 @_uncommitted()
1309 def lzc_receive_with_cmdprops(
1310 snapname, fd, begin_record, force=False, resumable=False, raw=False,
1311 origin=None, props=None, cmdprops=None, key=None, cleanup_fd=-1,
1312 action_handle=0
1313 ):
1314 '''
1315 Like :func:`lzc_receive_one`, but allows the caller to pass an additional
1316 'cmdprops' argument. The 'cmdprops' nvlist contains both override
1317 ('zfs receive -o') and exclude ('zfs receive -x') properties.
1318
1319 :param bytes snapname: the name of the snapshot to create.
1320 :param int fd: the file descriptor from which to read the stream.
1321 :param begin_record: the stream's begin record.
1322 :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1323 structure.
1324 :param bool force: whether to roll back or destroy the target filesystem
1325 if that is required to receive the stream.
1326 :param bool resumable: whether this stream should be treated as resumable.
1327 If the receive fails due to premature stream termination, the
1328 intermediate state will be preserved on disk and may subsequently be
1329 resumed with :func:`lzc_send_resume`.
1330 :param bool raw: whether this is a "raw" stream.
1331 :param origin: the optional origin snapshot name if the stream is for a
1332 clone.
1333 :type origin: bytes or None
1334 :param props: the properties to set on the snapshot as *received*
1335 properties.
1336 :type props: dict of bytes : Any
1337 :param cmdprops: the properties to set on the snapshot as local overrides
1338 to *received* properties. `bool` values are forcefully inherited while
1339 every other value is set locally as if the command "zfs set" was
1340 invoked immediately before the receive.
1341 :type cmdprops: dict of bytes : Any
1342 :param key: raw bytes representing user's wrapping key
1343 :type key: bytes
1344 :param int cleanup_fd: file descriptor used to set a cleanup-on-exit file
1345 descriptor.
1346 :param int action_handle: variable used to pass the handle for guid/ds
1347 mapping: this should be set to zero on first call and will contain an
1348 updated handle on success, it should be passed in subsequent calls.
1349
1350 :return: a tuple with two elements where the first one is the number of
1351 bytes read from the file descriptor and the second one is the
1352 action_handle return value.
1353
1354 :raises IOError: if an input / output error occurs while reading from the
1355 ``fd``.
1356 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1357 :raises DatasetExists: if the stream is a full stream and the destination
1358 filesystem already exists.
1359 :raises DatasetExists: if ``force`` is `True` but the destination
1360 filesystem could not be rolled back to a matching snapshot because a
1361 newer snapshot exists and it is an origin of a cloned filesystem.
1362 :raises StreamMismatch: if an incremental stream is received and the latest
1363 snapshot of the destination filesystem does not match the source
1364 snapshot of the stream.
1365 :raises StreamMismatch: if a full stream is received and the destination
1366 filesystem already exists and it has at least one snapshot, and
1367 ``force`` is `False`.
1368 :raises StreamMismatch: if an incremental clone stream is received but the
1369 specified ``origin`` is not the actual received origin.
1370 :raises DestinationModified: if an incremental stream is received and the
1371 destination filesystem has been modified since the last snapshot and
1372 ``force`` is `False`.
1373 :raises DestinationModified: if a full stream is received and the
1374 destination filesystem already exists and it does not have any
1375 snapshots, and ``force`` is `False`.
1376 :raises DatasetNotFound: if the destination filesystem and its parent do
1377 not exist.
1378 :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1379 exist.
1380 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1381 could not be rolled back to a matching snapshot because a newer
1382 snapshot is held and could not be destroyed.
1383 :raises DatasetBusy: if another receive operation is being performed on the
1384 destination filesystem.
1385 :raises BadStream: if the stream is corrupt or it is not recognized or it
1386 is a compound stream or it is a clone stream, but ``origin`` is `None`.
1387 :raises BadStream: if a clone stream is received and the destination
1388 filesystem already exists.
1389 :raises StreamFeatureNotSupported: if the stream has a feature that is not
1390 supported on this side.
1391 :raises ReceivePropertyFailure: if one or more of the specified properties
1392 is invalid or has an invalid type or value.
1393 :raises NameInvalid: if the name of either snapshot is invalid.
1394 :raises NameTooLong: if the name of either snapshot is too long.
1395 '''
1396
1397 if origin is not None:
1398 c_origin = origin
1399 else:
1400 c_origin = _ffi.NULL
1401 if action_handle is not None:
1402 c_action_handle = _ffi.new("uint64_t *")
1403 else:
1404 c_action_handle = _ffi.NULL
1405 c_read_bytes = _ffi.new("uint64_t *")
1406 c_errflags = _ffi.new("uint64_t *")
1407 if props is None:
1408 props = {}
1409 if cmdprops is None:
1410 cmdprops = {}
1411 if key is None:
1412 key = b""
1413 else:
1414 key = bytes(key)
1415
1416 nvlist = nvlist_in(props)
1417 cmdnvlist = nvlist_in(cmdprops)
1418 properrs = {}
1419 with nvlist_out(properrs) as c_errors:
1420 ret = _lib.lzc_receive_with_cmdprops(
1421 snapname, nvlist, cmdnvlist, key, len(key), c_origin,
1422 force, resumable, raw, fd, begin_record, cleanup_fd, c_read_bytes,
1423 c_errflags, c_action_handle, c_errors)
1424 errors.lzc_receive_translate_errors(
1425 ret, snapname, fd, force, raw, False, False, origin, properrs)
1426 return (int(c_read_bytes[0]), action_handle)
1427
1428
1429 @_uncommitted()
1430 def lzc_receive_with_heal(
1431 snapname, fd, begin_record, force=False, corrective=True, resumable=False,
1432 raw=False, origin=None, props=None, cmdprops=None, key=None, cleanup_fd=-1,
1433 action_handle=0
1434 ):
1435 '''
1436 Like :func:`lzc_receive_cmdprops`, but allows the caller to pass an
1437 additional 'corrective' argument. The 'corrective' boolean set to true
1438 indicates that a corruption healing receive should be performed.
1439
1440 :param bytes snapname: the name of the snapshot to create.
1441 :param int fd: the file descriptor from which to read the stream.
1442 :param begin_record: the stream's begin record.
1443 :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1444 structure.
1445 :param bool force: whether to roll back or destroy the target filesystem
1446 if that is required to receive the stream.
1447 :param bool corrective: whether this stream should be used to heal data.
1448 :param bool resumable: whether this stream should be treated as resumable.
1449 If the receive fails due to premature stream termination, the
1450 intermediate state will be preserved on disk and may subsequently be
1451 resumed with :func:`lzc_send_resume`.
1452 :param bool raw: whether this is a "raw" stream.
1453 :param origin: the optional origin snapshot name if the stream is for a
1454 clone.
1455 :type origin: bytes or None
1456 :param props: the properties to set on the snapshot as *received*
1457 properties.
1458 :type props: dict of bytes : Any
1459 :param cmdprops: the properties to set on the snapshot as local overrides
1460 to *received* properties. `bool` values are forcefully inherited while
1461 every other value is set locally as if the command "zfs set" was
1462 invoked immediately before the receive.
1463 :type cmdprops: dict of bytes : Any
1464 :param key: raw bytes representing user's wrapping key
1465 :type key: bytes
1466 :param int cleanup_fd: file descriptor used to set a cleanup-on-exit file
1467 descriptor.
1468 :param int action_handle: variable used to pass the handle for guid/ds
1469 mapping: this should be set to zero on first call and will contain an
1470 updated handle on success, it should be passed in subsequent calls.
1471
1472 :return: a tuple with two elements where the first one is the number of
1473 bytes read from the file descriptor and the second one is the
1474 action_handle return value.
1475
1476 :raises IOError: if an input / output error occurs while reading from the
1477 ``fd``.
1478 :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1479 :raises DatasetExists: if the stream is a full stream and the destination
1480 filesystem already exists.
1481 :raises DatasetExists: if ``force`` is `True` but the destination
1482 filesystem could not be rolled back to a matching snapshot because a
1483 newer snapshot exists and it is an origin of a cloned filesystem.
1484 :raises StreamMismatch: if an incremental stream is received and the latest
1485 snapshot of the destination filesystem does not match the source
1486 snapshot of the stream.
1487 :raises StreamMismatch: if a full stream is received and the destination
1488 filesystem already exists and it has at least one snapshot, and
1489 ``force`` is `False`.
1490 :raises StreamMismatch: if an incremental clone stream is received but the
1491 specified ``origin`` is not the actual received origin.
1492 :raises DestinationModified: if an incremental stream is received and the
1493 destination filesystem has been modified since the last snapshot and
1494 ``force`` is `False`.
1495 :raises DestinationModified: if a full stream is received and the
1496 destination filesystem already exists and it does not have any
1497 snapshots, and ``force`` is `False`.
1498 :raises DatasetNotFound: if the destination filesystem and its parent do
1499 not exist.
1500 :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1501 exist.
1502 :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1503 could not be rolled back to a matching snapshot because a newer
1504 snapshot is held and could not be destroyed.
1505 :raises DatasetBusy: if another receive operation is being performed on the
1506 destination filesystem.
1507 :raises EncryptionKeyNotLoaded: if corrective is set to true indicates the
1508 key must be loaded to do a non-raw corrective recv on an encrypted
1509 dataset.
1510 :raises BadStream: if corrective is set to true indicates that
1511 corrective recv was not able to reconstruct a corrupted block.
1512 :raises BadStream: if the stream is corrupt or it is not recognized or it
1513 is a compound stream or it is a clone stream, but ``origin`` is `None`.
1514 :raises BadStream: if a clone stream is received and the destination
1515 filesystem already exists.
1516 :raises StreamFeatureNotSupported: if corrective is set to true indicates
1517 stream is not compatible with the data in the pool.
1518 :raises StreamFeatureNotSupported: if the stream has a feature that is not
1519 supported on this side.
1520 :raises ReceivePropertyFailure: if one or more of the specified properties
1521 is invalid or has an invalid type or value.
1522 :raises NameInvalid: if the name of either snapshot is invalid.
1523 :raises NameTooLong: if the name of either snapshot is too long.
1524 '''
1525
1526 if origin is not None:
1527 c_origin = origin
1528 else:
1529 c_origin = _ffi.NULL
1530 if action_handle is not None:
1531 c_action_handle = _ffi.new("uint64_t *")
1532 else:
1533 c_action_handle = _ffi.NULL
1534 c_read_bytes = _ffi.new("uint64_t *")
1535 c_errflags = _ffi.new("uint64_t *")
1536 if props is None:
1537 props = {}
1538 if cmdprops is None:
1539 cmdprops = {}
1540 if key is None:
1541 key = b""
1542 else:
1543 key = bytes(key)
1544
1545 nvlist = nvlist_in(props)
1546 cmdnvlist = nvlist_in(cmdprops)
1547 properrs = {}
1548 with nvlist_out(properrs) as c_errors:
1549 ret = _lib.lzc_receive_with_heal(
1550 snapname, nvlist, cmdnvlist, key, len(key), c_origin,
1551 force, corrective, resumable, raw, fd, begin_record, cleanup_fd,
1552 c_read_bytes, c_errflags, c_action_handle, c_errors)
1553 errors.lzc_receive_translate_errors(
1554 ret, snapname, fd, force, raw, False, False, origin, properrs)
1555 return (int(c_read_bytes[0]), action_handle)
1556
1557
1558 @_uncommitted()
1559 def lzc_reopen(poolname, restart=True):
1560 '''
1561 Reopen a pool
1562
1563 :param bytes poolname: the name of the pool.
1564 :param bool restart: whether to restart an in-progress scrub operation.
1565
1566 :raises PoolNotFound: if the pool does not exist.
1567 '''
1568 ret = _lib.lzc_reopen(poolname, restart)
1569 errors.lzc_reopen_translate_error(ret, poolname)
1570
1571
1572 def lzc_send_resume(
1573 snapname, fromsnap, fd, flags=None, resumeobj=0, resumeoff=0
1574 ):
1575 '''
1576 Resume a previously interrupted send operation generating a zfs send stream
1577 for the specified snapshot and writing it to the specified file descriptor.
1578
1579 :param bytes snapname: the name of the snapshot to send.
1580 :param fromsnap: if not None the name of the starting snapshot
1581 for the incremental stream.
1582 :type fromsnap: bytes or None
1583 :param int fd: the file descriptor to write the send stream to.
1584 :param flags: the flags that control what enhanced features can be used in
1585 the stream.
1586 :type flags: list of bytes
1587 :param int resumeobj: the object number where this send stream should
1588 resume from.
1589 :param int resumeoff: the offset where this send stream should resume from.
1590
1591 :raises SnapshotNotFound: if either the starting snapshot is not `None` and
1592 does not exist, or if the ending snapshot does not exist.
1593 :raises NameInvalid: if the name of either snapshot is invalid.
1594 :raises NameTooLong: if the name of either snapshot is too long.
1595 :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
1596 ``snapname``.
1597 :raises PoolsDiffer: if the snapshots belong to different pools.
1598 :raises IOError: if an input / output error occurs while writing to ``fd``.
1599 :raises UnknownStreamFeature: if the ``flags`` contain an unknown flag
1600 name.
1601
1602 .. note::
1603 See :func:`lzc_send` for more information.
1604 '''
1605 if fromsnap is not None:
1606 c_fromsnap = fromsnap
1607 else:
1608 c_fromsnap = _ffi.NULL
1609 c_flags = 0
1610 if flags is None:
1611 flags = []
1612 for flag in flags:
1613 c_flag = {
1614 'embedded_data': _lib.LZC_SEND_FLAG_EMBED_DATA,
1615 'large_blocks': _lib.LZC_SEND_FLAG_LARGE_BLOCK,
1616 'compress': _lib.LZC_SEND_FLAG_COMPRESS,
1617 'raw': _lib.LZC_SEND_FLAG_RAW,
1618 }.get(flag)
1619 if c_flag is None:
1620 raise exceptions.UnknownStreamFeature(flag)
1621 c_flags |= c_flag
1622
1623 ret = _lib.lzc_send_resume(
1624 snapname, c_fromsnap, fd, c_flags, uint64_t(resumeobj),
1625 uint64_t(resumeoff))
1626 errors.lzc_send_translate_error(ret, snapname, fromsnap, fd, flags)
1627
1628
1629 @_uncommitted()
1630 def lzc_sync(poolname, force=False):
1631 '''
1632 Forces all in-core dirty data to be written to the primary pool storage
1633 and not the ZIL.
1634
1635 :param bytes poolname: the name of the pool.
1636 :param bool force: whether to force uberblock update even if there is no
1637 dirty data.
1638
1639 :raises PoolNotFound: if the pool does not exist.
1640
1641 .. note::
1642 This method signature is different from its C libzfs_core counterpart:
1643 `innvl` has been replaced by the `force` boolean and `outnvl` has been
1644 conveniently removed since it's not used.
1645 '''
1646 innvl = nvlist_in({b"force": force})
1647 with nvlist_out({}) as outnvl:
1648 ret = _lib.lzc_sync(poolname, innvl, outnvl)
1649 errors.lzc_sync_translate_error(ret, poolname)
1650
1651
1652 def is_supported(func):
1653 '''
1654 Check whether C *libzfs_core* provides implementation required
1655 for the given Python wrapper.
1656
1657 If `is_supported` returns ``False`` for the function, then
1658 calling the function would result in :exc:`NotImplementedError`.
1659
1660 :param function func: the function to check.
1661 :return bool: whether the function can be used.
1662 '''
1663 fname = func.__name__
1664 if fname not in globals():
1665 raise ValueError(fname + ' is not from libzfs_core')
1666 if not callable(func):
1667 raise ValueError(fname + ' is not a function')
1668 if not fname.startswith("lzc_"):
1669 raise ValueError(fname + ' is not a libzfs_core API function')
1670 check_func = getattr(func, "_check_func", None)
1671 if check_func is not None:
1672 return is_supported(check_func)
1673 return getattr(_lib, fname, None) is not None
1674
1675
1676 @_uncommitted()
1677 def lzc_promote(name):
1678 '''
1679 Promotes the ZFS dataset.
1680
1681 :param bytes name: the name of the dataset to promote.
1682 :raises NameInvalid: if the dataset name is invalid.
1683 :raises NameTooLong: if the dataset name is too long.
1684 :raises NameTooLong: if the dataset's origin has a snapshot that, if
1685 transferred to the dataset, would get a too long name.
1686 :raises NotClone: if the dataset is not a clone.
1687 :raises FilesystemNotFound: if the dataset does not exist.
1688 :raises SnapshotExists: if the dataset already has a snapshot with the same
1689 name as one of the origin's snapshots.
1690 '''
1691 ret = _lib.lzc_promote(name, _ffi.NULL, _ffi.NULL)
1692 errors.lzc_promote_translate_error(ret, name)
1693
1694
1695 @_uncommitted()
1696 def lzc_pool_checkpoint(name):
1697 '''
1698 Creates a checkpoint for the specified pool.
1699
1700 :param bytes name: the name of the pool to create a checkpoint for.
1701 :raises CheckpointExists: if the pool already has a checkpoint.
1702 :raises CheckpointDiscarding: if ZFS is in the middle of discarding a
1703 checkpoint for this pool.
1704 :raises DeviceRemovalRunning: if a vdev is currently being removed.
1705 :raises DeviceTooBig: if one or more top-level vdevs exceed the maximum
1706 vdev size.
1707 '''
1708 ret = _lib.lzc_pool_checkpoint(name)
1709 errors.lzc_pool_checkpoint_translate_error(ret, name)
1710
1711
1712 @_uncommitted()
1713 def lzc_pool_checkpoint_discard(name):
1714 '''
1715 Discard the checkpoint from the specified pool.
1716
1717 :param bytes name: the name of the pool to discard the checkpoint from.
1718 :raises CheckpointNotFound: if pool does not have a checkpoint.
1719 :raises CheckpointDiscarding: if ZFS is in the middle of discarding a
1720 checkpoint for this pool.
1721 '''
1722 ret = _lib.lzc_pool_checkpoint_discard(name)
1723 errors.lzc_pool_checkpoint_discard_translate_error(ret, name)
1724
1725
1726 def lzc_rename(source, target):
1727 '''
1728 Rename the ZFS dataset.
1729
1730 :param source name: the current name of the dataset to rename.
1731 :param target name: the new name of the dataset.
1732 :raises NameInvalid: if either the source or target name is invalid.
1733 :raises NameTooLong: if either the source or target name is too long.
1734 :raises NameTooLong: if a snapshot of the source would get a too long name
1735 after renaming.
1736 :raises FilesystemNotFound: if the source does not exist.
1737 :raises FilesystemNotFound: if the target's parent does not exist.
1738 :raises FilesystemExists: if the target already exists.
1739 :raises PoolsDiffer: if the source and target belong to different pools.
1740 :raises WrongParent: if the "new" parent dataset is not a filesystem
1741 (e.g. ZVOL)
1742 '''
1743 ret = _lib.lzc_rename(source, target)
1744 errors.lzc_rename_translate_error(ret, source, target)
1745
1746
1747 def lzc_destroy(name):
1748 '''
1749 Destroy the ZFS dataset.
1750
1751 :param bytes name: the name of the dataset to destroy.
1752 :raises NameInvalid: if the dataset name is invalid.
1753 :raises NameTooLong: if the dataset name is too long.
1754 :raises FilesystemNotFound: if the dataset does not exist.
1755 '''
1756 ret = _lib.lzc_destroy(name)
1757 errors.lzc_destroy_translate_error(ret, name)
1758
1759
1760 @_uncommitted()
1761 def lzc_inherit(name, prop):
1762 '''
1763 Inherit properties from a parent dataset of the given ZFS dataset.
1764
1765 :param bytes name: the name of the dataset.
1766 :param bytes prop: the name of the property to inherit.
1767 :raises NameInvalid: if the dataset name is invalid.
1768 :raises NameTooLong: if the dataset name is too long.
1769 :raises DatasetNotFound: if the dataset does not exist.
1770 :raises PropertyInvalid: if one or more of the specified properties is
1771 invalid or has an invalid type or value.
1772
1773 Inheriting a property actually resets it to its default value
1774 or removes it if it's a user property, so that the property could be
1775 inherited if it's inheritable. If the property is not inheritable
1776 then it would just have its default value.
1777
1778 This function can be used on snapshots to inherit user defined properties.
1779 '''
1780 ret = _lib.lzc_inherit(name, prop, _ffi.NULL)
1781 errors.lzc_inherit_prop_translate_error(ret, name, prop)
1782
1783
1784 # As the extended API is not committed yet, the names of the new interfaces
1785 # are not settled down yet.
1786 # lzc_inherit_prop makes it clearer what is to be inherited.
1787 lzc_inherit_prop = lzc_inherit
1788
1789
1790 @_uncommitted()
1791 def lzc_set_props(name, prop, val):
1792 '''
1793 Set properties of the ZFS dataset.
1794
1795 :param bytes name: the name of the dataset.
1796 :param bytes prop: the name of the property.
1797 :param Any val: the value of the property.
1798 :raises NameInvalid: if the dataset name is invalid.
1799 :raises NameTooLong: if the dataset name is too long.
1800 :raises DatasetNotFound: if the dataset does not exist.
1801 :raises NoSpace: if the property controls a quota and the values is too
1802 small for that quota.
1803 :raises PropertyInvalid: if one or more of the specified properties is
1804 invalid or has an invalid type or value.
1805
1806 This function can be used on snapshots to set user defined properties.
1807
1808 .. note::
1809 An attempt to set a readonly / statistic property is ignored
1810 without reporting any error.
1811 '''
1812 props = {prop: val}
1813 props_nv = nvlist_in(props)
1814 ret = _lib.lzc_set_props(name, props_nv, _ffi.NULL, _ffi.NULL)
1815 errors.lzc_set_prop_translate_error(ret, name, prop, val)
1816
1817
1818 # As the extended API is not committed yet, the names of the new interfaces
1819 # are not settled down yet.
1820 # It's not clear if atomically setting multiple properties is an achievable
1821 # goal and an interface acting on multiple entities must do so atomically
1822 # by convention.
1823 # Being able to set a single property at a time is sufficient for ClusterHQ.
1824 lzc_set_prop = lzc_set_props
1825
1826
1827 @_uncommitted()
1828 def lzc_list(name, options):
1829 '''
1830 List subordinate elements of the given dataset.
1831
1832 This function can be used to list child datasets and snapshots of the given
1833 dataset. The listed elements can be filtered by their type and by their
1834 depth relative to the starting dataset.
1835
1836 :param bytes name: the name of the dataset to be listed, could be a
1837 snapshot or a dataset.
1838 :param options: a `dict` of the options that control the listing behavior.
1839 :type options: dict of bytes:Any
1840 :return: a pair of file descriptors the first of which can be used to read
1841 the listing.
1842 :rtype: tuple of (int, int)
1843 :raises DatasetNotFound: if the dataset does not exist.
1844
1845 Two options are currently available:
1846
1847 recurse : integer or None
1848 specifies depth of the recursive listing. If ``None`` the depth is not
1849 limited.
1850 Absence of this option means that only the given dataset is listed.
1851
1852 type : dict of bytes:None
1853 specifies dataset types to include into the listing.
1854 Currently allowed keys are "filesystem", "volume", "snapshot".
1855 Absence of this option implies all types.
1856
1857 The first of the returned file descriptors can be used to
1858 read the listing in a binary encoded format. The data is
1859 a series of variable sized records each starting with a fixed
1860 size header, the header is followed by a serialized ``nvlist``.
1861 Each record describes a single element and contains the element's
1862 name as well as its properties.
1863 The file descriptor must be closed after reading from it.
1864
1865 The second file descriptor represents a pipe end to which the
1866 kernel driver is writing information. It should not be closed
1867 until all interesting information has been read and it must
1868 be explicitly closed afterwards.
1869 '''
1870 (rfd, wfd) = os.pipe()
1871 fcntl.fcntl(rfd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
1872 fcntl.fcntl(wfd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
1873 options = options.copy()
1874 options['fd'] = int32_t(wfd)
1875 opts_nv = nvlist_in(options)
1876 ret = _lib.lzc_list(name, opts_nv)
1877 if ret == errno.ESRCH:
1878 return (None, None)
1879 errors.lzc_list_translate_error(ret, name, options)
1880 return (rfd, wfd)
1881
1882
1883 # Description of the binary format used to pass data from the kernel.
1884 _PIPE_RECORD_FORMAT = 'IBBBB'
1885 _PIPE_RECORD_SIZE = struct.calcsize(_PIPE_RECORD_FORMAT)
1886
1887
1888 def _list(name, recurse=None, types=None):
1889 '''
1890 A wrapper for :func:`lzc_list` that hides details of working
1891 with the file descriptors and provides data in an easy to
1892 consume format.
1893
1894 :param bytes name: the name of the dataset to be listed, could be a
1895 snapshot, a volume or a filesystem.
1896 :param recurse: specifies depth of the recursive listing. If ``None`` the
1897 depth is not limited.
1898 :param types: specifies dataset types to include into the listing.
1899 Currently allowed keys are "filesystem", "volume", "snapshot". ``None``
1900 is equivalent to specifying the type of the dataset named by `name`.
1901 :type types: list of bytes or None
1902 :type recurse: integer or None
1903 :return: a list of dictionaries each describing a single listed element.
1904 :rtype: list of dict
1905 '''
1906 options = {}
1907
1908 # Convert types to a dict suitable for mapping to an nvlist.
1909 if types is not None:
1910 types = {x: None for x in types}
1911 options['type'] = types
1912 if recurse is None or recurse > 0:
1913 options['recurse'] = recurse
1914
1915 # Note that other_fd is used by the kernel side to write
1916 # the data, so we have to keep that descriptor open until
1917 # we are done.
1918 # Also, we have to explicitly close the descriptor as the
1919 # kernel doesn't do that.
1920 (fd, other_fd) = lzc_list(name, options)
1921 if fd is None:
1922 return
1923
1924 try:
1925 while True:
1926 record_bytes = os.read(fd, _PIPE_RECORD_SIZE)
1927 if not record_bytes:
1928 break
1929 (size, _, err, _, _) = struct.unpack(
1930 _PIPE_RECORD_FORMAT, record_bytes)
1931 if err == errno.ESRCH:
1932 break
1933 errors.lzc_list_translate_error(err, name, options)
1934 if size == 0:
1935 break
1936 data_bytes = os.read(fd, size)
1937 result = {}
1938 with nvlist_out(result) as nvp:
1939 ret = _lib.nvlist_unpack(data_bytes, size, nvp, 0)
1940 if ret != 0:
1941 raise exceptions.ZFSGenericError(
1942 ret, None, "Failed to unpack list data")
1943 yield result
1944 finally:
1945 os.close(other_fd)
1946 os.close(fd)
1947
1948
1949 @_uncommitted(lzc_list)
1950 def lzc_get_props(name):
1951 '''
1952 Get properties of the ZFS dataset.
1953
1954 :param bytes name: the name of the dataset.
1955 :raises DatasetNotFound: if the dataset does not exist.
1956 :raises NameInvalid: if the dataset name is invalid.
1957 :raises NameTooLong: if the dataset name is too long.
1958 :return: a dictionary mapping the property names to their values.
1959 :rtype: dict of bytes:Any
1960
1961 .. note::
1962 The value of ``clones`` property is a `list` of clone names as byte
1963 strings.
1964
1965 .. warning::
1966 The returned dictionary does not contain entries for properties
1967 with default values. One exception is the ``mountpoint`` property
1968 for which the default value is derived from the dataset name.
1969 '''
1970 result = next(_list(name, recurse=0))
1971 is_snapshot = result['dmu_objset_stats']['dds_is_snapshot']
1972 result = result['properties']
1973 # In most cases the source of the property is uninteresting and the
1974 # value alone is sufficient. One exception is the 'mountpoint'
1975 # property the final value of which is not the same as the inherited
1976 # value.
1977 mountpoint = result.get('mountpoint')
1978 if mountpoint is not None:
1979 mountpoint_src = mountpoint['source']
1980 mountpoint_val = mountpoint['value']
1981 # 'source' is the name of the dataset that has 'mountpoint' set
1982 # to a non-default value and from which the current dataset inherits
1983 # the property. 'source' can be the current dataset if its
1984 # 'mountpoint' is explicitly set.
1985 # 'source' can also be a special value like '$recvd', that case
1986 # is equivalent to the property being set on the current dataset.
1987 # Note that a normal mountpoint value should start with '/'
1988 # unlike the special values "none" and "legacy".
1989 if (mountpoint_val.startswith('/') and
1990 not mountpoint_src.startswith('$')):
1991 mountpoint_val = mountpoint_val + name[len(mountpoint_src):]
1992 elif not is_snapshot:
1993 mountpoint_val = '/' + name
1994 else:
1995 mountpoint_val = None
1996 result = {k: result[k]['value'] for k in result}
1997 if 'clones' in result:
1998 result['clones'] = list(result['clones'].keys())
1999 if mountpoint_val is not None:
2000 result['mountpoint'] = mountpoint_val
2001 return result
2002
2003
2004 @_uncommitted(lzc_list)
2005 def lzc_list_children(name):
2006 '''
2007 List the children of the ZFS dataset.
2008
2009 :param bytes name: the name of the dataset.
2010 :return: an iterator that produces the names of the children.
2011 :raises NameInvalid: if the dataset name is invalid.
2012 :raises NameTooLong: if the dataset name is too long.
2013 :raises DatasetNotFound: if the dataset does not exist.
2014
2015 .. warning::
2016 If the dataset does not exist, then the returned iterator would produce
2017 no results and no error is reported.
2018 That case is indistinguishable from the dataset having no children.
2019
2020 An attempt to list children of a snapshot is silently ignored as well.
2021 '''
2022 children = []
2023 for entry in _list(name, recurse=1, types=['filesystem', 'volume']):
2024 child = entry['name']
2025 if child != name:
2026 children.append(child)
2027
2028 return iter(children)
2029
2030
2031 @_uncommitted(lzc_list)
2032 def lzc_list_snaps(name):
2033 '''
2034 List the snapshots of the ZFS dataset.
2035
2036 :param bytes name: the name of the dataset.
2037 :return: an iterator that produces the names of the snapshots.
2038 :raises NameInvalid: if the dataset name is invalid.
2039 :raises NameTooLong: if the dataset name is too long.
2040 :raises DatasetNotFound: if the dataset does not exist.
2041
2042 .. warning::
2043 If the dataset does not exist, then the returned iterator would produce
2044 no results and no error is reported.
2045 That case is indistinguishable from the dataset having no snapshots.
2046
2047 An attempt to list snapshots of a snapshot is silently ignored as well.
2048 '''
2049 snaps = []
2050 for entry in _list(name, recurse=1, types=['snapshot']):
2051 snap = entry['name']
2052 if snap != name:
2053 snaps.append(snap)
2054
2055 return iter(snaps)
2056
2057
2058 # TODO: a better way to init and uninit the library
2059 def _initialize():
2060 class LazyInit(object):
2061
2062 def __init__(self, lib):
2063 self._lib = lib
2064 self._inited = False
2065 self._lock = threading.Lock()
2066
2067 def __getattr__(self, name):
2068 if not self._inited:
2069 with self._lock:
2070 if not self._inited:
2071 ret = self._lib.libzfs_core_init()
2072 if ret != 0:
2073 raise exceptions.ZFSInitializationFailed(ret)
2074 self._inited = True
2075 return getattr(self._lib, name)
2076
2077 return LazyInit(libzfs_core.lib)
2078
2079
2080 _ffi = libzfs_core.ffi
2081 _lib = _initialize()
2082
2083
2084 # vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4