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