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