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