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