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""" 19Helper routines for converting ``errno`` style error codes from C functions 20to Python exceptions defined by `libzfs_core` API. 21 22The conversion heavily depends on the context of the error: the attempted 23operation and the input parameters. For this reason, there is a conversion 24routine for each `libzfs_core` interface function. The conversion routines 25have the return code as a parameter as well as all the parameters of the 26corresponding interface functions. 27 28The parameters and exceptions are documented in the `libzfs_core` interfaces. 29""" 30from __future__ import absolute_import, division, print_function 31 32import errno 33import re 34import string 35from . import exceptions as lzc_exc 36from ._constants import ( 37 ECHRNG, 38 ECKSUM, 39 ETIME, 40 MAXNAMELEN, 41 ZFS_ERR_CHECKPOINT_EXISTS, 42 ZFS_ERR_DISCARDING_CHECKPOINT, 43 ZFS_ERR_NO_CHECKPOINT, 44 ZFS_ERR_DEVRM_IN_PROGRESS, 45 ZFS_ERR_VDEV_TOO_BIG, 46 ZFS_ERR_WRONG_PARENT, 47 ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS, 48 zfs_errno 49) 50 51 52def lzc_create_translate_error(ret, name, ds_type, props): 53 if ret == 0: 54 return 55 if ret == errno.EINVAL: 56 _validate_fs_name(name) 57 raise lzc_exc.PropertyInvalid(name) 58 if ret == errno.EEXIST: 59 raise lzc_exc.FilesystemExists(name) 60 if ret == errno.ENOENT: 61 raise lzc_exc.ParentNotFound(name) 62 if ret == ZFS_ERR_WRONG_PARENT: 63 raise lzc_exc.WrongParent(_fs_name(name)) 64 if ret == zfs_errno.ZFS_ERR_BADPROP: 65 raise lzc_exc.PropertyInvalid(name) 66 raise _generic_exception(ret, name, "Failed to create filesystem") 67 68 69def lzc_clone_translate_error(ret, name, origin, props): 70 if ret == 0: 71 return 72 if ret == errno.EINVAL: 73 _validate_fs_name(name) 74 _validate_snap_name(origin) 75 raise lzc_exc.PropertyInvalid(name) 76 if ret == errno.EXDEV: 77 raise lzc_exc.PoolsDiffer(name) 78 if ret == errno.EEXIST: 79 raise lzc_exc.FilesystemExists(name) 80 if ret == errno.ENOENT: 81 if not _is_valid_snap_name(origin): 82 raise lzc_exc.SnapshotNameInvalid(origin) 83 raise lzc_exc.DatasetNotFound(name) 84 raise _generic_exception(ret, name, "Failed to create clone") 85 86 87def lzc_rollback_translate_error(ret, name): 88 if ret == 0: 89 return 90 if ret == errno.ESRCH: 91 raise lzc_exc.SnapshotNotFound(name) 92 if ret == errno.EINVAL: 93 _validate_fs_name(name) 94 raise lzc_exc.NameInvalid(name) 95 if ret == errno.ENOENT: 96 if not _is_valid_fs_name(name): 97 raise lzc_exc.NameInvalid(name) 98 else: 99 raise lzc_exc.FilesystemNotFound(name) 100 raise _generic_exception(ret, name, "Failed to rollback") 101 102 103def lzc_rollback_to_translate_error(ret, name, snap): 104 if ret == errno.EEXIST: 105 raise lzc_exc.SnapshotNotLatest(snap) 106 else: 107 lzc_rollback_translate_error(ret, name) 108 109 110def lzc_snapshot_translate_errors(ret, errlist, snaps, props): 111 if ret == 0: 112 return 113 114 def _map(ret, name): 115 if ret == errno.EXDEV: 116 pool_names = iter(map(_pool_name, snaps)) 117 pool_name = next(pool_names, None) 118 same_pool = all(x == pool_name for x in pool_names) 119 if same_pool: 120 return lzc_exc.DuplicateSnapshots(name) 121 else: 122 return lzc_exc.PoolsDiffer(name) 123 elif ret == errno.EINVAL: 124 if any(not _is_valid_snap_name(s) for s in snaps): 125 return lzc_exc.NameInvalid(name) 126 elif any(len(s) > MAXNAMELEN for s in snaps): 127 return lzc_exc.NameTooLong(name) 128 else: 129 return lzc_exc.PropertyInvalid(name) 130 131 if ret == errno.EEXIST: 132 return lzc_exc.SnapshotExists(name) 133 if ret == errno.ENOENT: 134 return lzc_exc.FilesystemNotFound(name) 135 return _generic_exception(ret, name, "Failed to create snapshot") 136 137 _handle_err_list(ret, errlist, snaps, lzc_exc.SnapshotFailure, _map) 138 139 140def lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer): 141 if ret == 0: 142 return 143 144 def _map(ret, name): 145 if ret == errno.EEXIST: 146 return lzc_exc.SnapshotIsCloned(name) 147 if ret == errno.ENOENT: 148 return lzc_exc.PoolNotFound(name) 149 if ret == errno.EBUSY: 150 return lzc_exc.SnapshotIsHeld(name) 151 return _generic_exception(ret, name, "Failed to destroy snapshot") 152 153 _handle_err_list( 154 ret, errlist, snaps, lzc_exc.SnapshotDestructionFailure, _map) 155 156 157def lzc_bookmark_translate_errors(ret, errlist, bookmarks): 158 159 if ret == 0: 160 return 161 162 def _map(ret, name): 163 source = bookmarks[name] 164 if ret == errno.EINVAL: 165 if name: 166 pool_names = map(_pool_name, bookmarks.keys()) 167 168 # use _validate* functions for MAXNAMELEN check 169 try: 170 _validate_bmark_name(name) 171 except lzc_exc.ZFSError as e: 172 return e 173 174 try: 175 _validate_snap_name(source) 176 source_is_snap = True 177 except lzc_exc.ZFSError: 178 source_is_snap = False 179 try: 180 _validate_bmark_name(source) 181 source_is_bmark = True 182 except lzc_exc.ZFSError: 183 source_is_bmark = False 184 if not source_is_snap and not source_is_bmark: 185 return lzc_exc.BookmarkSourceInvalid(source) 186 187 if any(x != _pool_name(name) for x in pool_names): 188 return lzc_exc.PoolsDiffer(name) 189 else: 190 invalid_names = [ 191 b for b in bookmarks.keys() if not _is_valid_bmark_name(b)] 192 if invalid_names: 193 return lzc_exc.BookmarkNameInvalid(invalid_names[0]) 194 if ret == errno.EEXIST: 195 return lzc_exc.BookmarkExists(name) 196 if ret == errno.ENOENT: 197 return lzc_exc.SnapshotNotFound(name) 198 if ret == errno.ENOTSUP: 199 return lzc_exc.BookmarkNotSupported(name) 200 if ret == zfs_errno.ZFS_ERR_BOOKMARK_SOURCE_NOT_ANCESTOR: 201 return lzc_exc.BookmarkMismatch(source) 202 return _generic_exception(ret, name, "Failed to create bookmark") 203 204 _handle_err_list( 205 ret, errlist, bookmarks.keys(), lzc_exc.BookmarkFailure, _map) 206 207 208def lzc_get_bookmarks_translate_error(ret, fsname, props): 209 if ret == 0: 210 return 211 if ret == errno.ENOENT: 212 raise lzc_exc.FilesystemNotFound(fsname) 213 raise _generic_exception(ret, fsname, "Failed to list bookmarks") 214 215 216def lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks): 217 if ret == 0: 218 return 219 220 def _map(ret, name): 221 if ret == errno.EINVAL: 222 return lzc_exc.NameInvalid(name) 223 return _generic_exception(ret, name, "Failed to destroy bookmark") 224 225 _handle_err_list( 226 ret, errlist, bookmarks, lzc_exc.BookmarkDestructionFailure, _map) 227 228 229def lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap): 230 if ret == 0: 231 return 232 if ret == errno.EXDEV and firstsnap is not None: 233 if _pool_name(firstsnap) != _pool_name(lastsnap): 234 raise lzc_exc.PoolsDiffer(lastsnap) 235 else: 236 raise lzc_exc.SnapshotMismatch(lastsnap) 237 if ret == errno.EINVAL: 238 if not _is_valid_snap_name(firstsnap): 239 raise lzc_exc.NameInvalid(firstsnap) 240 elif not _is_valid_snap_name(lastsnap): 241 raise lzc_exc.NameInvalid(lastsnap) 242 elif len(firstsnap) > MAXNAMELEN: 243 raise lzc_exc.NameTooLong(firstsnap) 244 elif len(lastsnap) > MAXNAMELEN: 245 raise lzc_exc.NameTooLong(lastsnap) 246 elif _pool_name(firstsnap) != _pool_name(lastsnap): 247 raise lzc_exc.PoolsDiffer(lastsnap) 248 else: 249 raise lzc_exc.SnapshotMismatch(lastsnap) 250 if ret == errno.ENOENT: 251 raise lzc_exc.SnapshotNotFound(lastsnap) 252 raise _generic_exception( 253 ret, lastsnap, "Failed to calculate space used by range of snapshots") 254 255 256def lzc_hold_translate_errors(ret, errlist, holds, fd): 257 if ret == 0: 258 return 259 260 def _map(ret, name): 261 if ret == errno.EXDEV: 262 return lzc_exc.PoolsDiffer(name) 263 elif ret == errno.EINVAL: 264 if name: 265 pool_names = map(_pool_name, holds.keys()) 266 if not _is_valid_snap_name(name): 267 return lzc_exc.NameInvalid(name) 268 elif len(name) > MAXNAMELEN: 269 return lzc_exc.NameTooLong(name) 270 elif any(x != _pool_name(name) for x in pool_names): 271 return lzc_exc.PoolsDiffer(name) 272 else: 273 invalid_names = [ 274 b for b in holds.keys() if not _is_valid_snap_name(b)] 275 if invalid_names: 276 return lzc_exc.NameInvalid(invalid_names[0]) 277 fs_name = None 278 hold_name = None 279 pool_name = None 280 if name is not None: 281 fs_name = _fs_name(name) 282 pool_name = _pool_name(name) 283 hold_name = holds[name] 284 if ret == errno.ENOENT: 285 return lzc_exc.FilesystemNotFound(fs_name) 286 if ret == errno.EEXIST: 287 return lzc_exc.HoldExists(name) 288 if ret == errno.E2BIG: 289 return lzc_exc.NameTooLong(hold_name) 290 if ret == errno.ENOTSUP: 291 return lzc_exc.FeatureNotSupported(pool_name) 292 return _generic_exception(ret, name, "Failed to hold snapshot") 293 294 if ret == errno.EBADF: 295 raise lzc_exc.BadHoldCleanupFD() 296 _handle_err_list(ret, errlist, holds.keys(), lzc_exc.HoldFailure, _map) 297 298 299def lzc_release_translate_errors(ret, errlist, holds): 300 if ret == 0: 301 return 302 for snap in holds: 303 hold_list = holds[snap] 304 if not isinstance(hold_list, list): 305 raise lzc_exc.TypeError('holds must be in a list') 306 307 def _map(ret, name): 308 if ret == errno.EXDEV: 309 return lzc_exc.PoolsDiffer(name) 310 elif ret == errno.EINVAL: 311 if name: 312 pool_names = map(_pool_name, holds.keys()) 313 if not _is_valid_snap_name(name): 314 return lzc_exc.NameInvalid(name) 315 elif len(name) > MAXNAMELEN: 316 return lzc_exc.NameTooLong(name) 317 elif any(x != _pool_name(name) for x in pool_names): 318 return lzc_exc.PoolsDiffer(name) 319 else: 320 invalid_names = [ 321 b for b in holds.keys() if not _is_valid_snap_name(b)] 322 if invalid_names: 323 return lzc_exc.NameInvalid(invalid_names[0]) 324 elif ret == errno.ENOENT: 325 return lzc_exc.HoldNotFound(name) 326 elif ret == errno.E2BIG: 327 tag_list = holds[name] 328 too_long_tags = [t for t in tag_list if len(t) > MAXNAMELEN] 329 return lzc_exc.NameTooLong(too_long_tags[0]) 330 elif ret == errno.ENOTSUP: 331 pool_name = None 332 if name is not None: 333 pool_name = _pool_name(name) 334 return lzc_exc.FeatureNotSupported(pool_name) 335 else: 336 return _generic_exception( 337 ret, name, "Failed to release snapshot hold") 338 339 _handle_err_list( 340 ret, errlist, holds.keys(), lzc_exc.HoldReleaseFailure, _map) 341 342 343def lzc_get_holds_translate_error(ret, snapname): 344 if ret == 0: 345 return 346 if ret == errno.EINVAL: 347 _validate_snap_name(snapname) 348 if ret == errno.ENOENT: 349 raise lzc_exc.SnapshotNotFound(snapname) 350 if ret == errno.ENOTSUP: 351 raise lzc_exc.FeatureNotSupported(_pool_name(snapname)) 352 raise _generic_exception(ret, snapname, "Failed to get holds on snapshot") 353 354 355def lzc_send_translate_error(ret, snapname, fromsnap, fd, flags): 356 if ret == 0: 357 return 358 if ret == errno.EXDEV and fromsnap is not None: 359 if _pool_name(fromsnap) != _pool_name(snapname): 360 raise lzc_exc.PoolsDiffer(snapname) 361 else: 362 raise lzc_exc.SnapshotMismatch(snapname) 363 elif ret == errno.EINVAL: 364 if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and 365 not _is_valid_bmark_name(fromsnap)): 366 raise lzc_exc.NameInvalid(fromsnap) 367 elif (not _is_valid_snap_name(snapname) and 368 not _is_valid_fs_name(snapname)): 369 raise lzc_exc.NameInvalid(snapname) 370 elif fromsnap is not None and len(fromsnap) > MAXNAMELEN: 371 raise lzc_exc.NameTooLong(fromsnap) 372 elif len(snapname) > MAXNAMELEN: 373 raise lzc_exc.NameTooLong(snapname) 374 elif (fromsnap is not None and 375 _pool_name(fromsnap) != _pool_name(snapname)): 376 raise lzc_exc.PoolsDiffer(snapname) 377 elif ret == errno.ENOENT: 378 if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and 379 not _is_valid_bmark_name(fromsnap)): 380 raise lzc_exc.NameInvalid(fromsnap) 381 raise lzc_exc.SnapshotNotFound(snapname) 382 elif ret == errno.ENAMETOOLONG: 383 if fromsnap is not None and len(fromsnap) > MAXNAMELEN: 384 raise lzc_exc.NameTooLong(fromsnap) 385 else: 386 raise lzc_exc.NameTooLong(snapname) 387 raise lzc_exc.StreamIOError(ret) 388 389 390def lzc_send_space_translate_error(ret, snapname, fromsnap): 391 if ret == 0: 392 return 393 if ret == errno.EXDEV and fromsnap is not None: 394 if _pool_name(fromsnap) != _pool_name(snapname): 395 raise lzc_exc.PoolsDiffer(snapname) 396 else: 397 raise lzc_exc.SnapshotMismatch(snapname) 398 elif ret == errno.EINVAL: 399 if fromsnap is not None and not _is_valid_snap_name(fromsnap): 400 raise lzc_exc.NameInvalid(fromsnap) 401 elif not _is_valid_snap_name(snapname): 402 raise lzc_exc.NameInvalid(snapname) 403 elif fromsnap is not None and len(fromsnap) > MAXNAMELEN: 404 raise lzc_exc.NameTooLong(fromsnap) 405 elif len(snapname) > MAXNAMELEN: 406 raise lzc_exc.NameTooLong(snapname) 407 elif (fromsnap is not None and 408 _pool_name(fromsnap) != _pool_name(snapname)): 409 raise lzc_exc.PoolsDiffer(snapname) 410 elif ret == errno.ENOENT and fromsnap is not None: 411 if not _is_valid_snap_name(fromsnap): 412 raise lzc_exc.NameInvalid(fromsnap) 413 if ret == errno.ENOENT: 414 raise lzc_exc.SnapshotNotFound(snapname) 415 raise _generic_exception( 416 ret, snapname, "Failed to estimate backup stream size") 417 418 419def lzc_receive_translate_errors( 420 ret, snapname, fd, force, raw, resumable, embedded, origin, properrs 421): 422 if ret == 0: 423 if properrs is not None and len(properrs) > 0: 424 def _map(ret, name): 425 if ret == errno.EINVAL: 426 return lzc_exc.PropertyInvalid(name) 427 if ret == zfs_errno.ZFS_ERR_BADPROP: 428 return lzc_exc.PropertyInvalid(name) 429 return _generic_exception(ret, name, "Failed to set property") 430 _handle_err_list( 431 errno.EINVAL, properrs, [snapname], 432 lzc_exc.ReceivePropertyFailure, _map) 433 else: 434 return 435 if ret == errno.EINVAL: 436 if (not _is_valid_snap_name(snapname) and 437 not _is_valid_fs_name(snapname)): 438 raise lzc_exc.NameInvalid(snapname) 439 elif len(snapname) > MAXNAMELEN: 440 raise lzc_exc.NameTooLong(snapname) 441 elif origin is not None and not _is_valid_snap_name(origin): 442 raise lzc_exc.NameInvalid(origin) 443 elif resumable: 444 raise lzc_exc.StreamFeatureInvalid() 445 elif embedded and not raw: 446 raise lzc_exc.StreamFeatureIncompatible() 447 else: 448 raise lzc_exc.BadStream() 449 if ret == errno.ENOENT: 450 if not _is_valid_snap_name(snapname): 451 raise lzc_exc.NameInvalid(snapname) 452 else: 453 raise lzc_exc.DatasetNotFound(snapname) 454 if ret == errno.EEXIST: 455 raise lzc_exc.DatasetExists(snapname) 456 if ret == errno.ENOTSUP: 457 raise lzc_exc.StreamFeatureNotSupported() 458 if ret == errno.ENODEV: 459 raise lzc_exc.StreamMismatch(_fs_name(snapname)) 460 if ret == errno.ETXTBSY: 461 raise lzc_exc.DestinationModified(_fs_name(snapname)) 462 if ret == errno.EBUSY: 463 raise lzc_exc.DatasetBusy(_fs_name(snapname)) 464 if ret == errno.ENOSPC: 465 raise lzc_exc.NoSpace(_fs_name(snapname)) 466 if ret == errno.EDQUOT: 467 raise lzc_exc.QuotaExceeded(_fs_name(snapname)) 468 if ret == errno.ENAMETOOLONG: 469 raise lzc_exc.NameTooLong(snapname) 470 if ret == errno.EROFS: 471 raise lzc_exc.ReadOnlyPool(_pool_name(snapname)) 472 if ret == errno.EAGAIN: 473 raise lzc_exc.SuspendedPool(_pool_name(snapname)) 474 if ret == errno.EACCES: 475 raise lzc_exc.EncryptionKeyNotLoaded() 476 if ret == ECKSUM: 477 raise lzc_exc.BadStream() 478 if ret == ZFS_ERR_WRONG_PARENT: 479 raise lzc_exc.WrongParent(_fs_name(snapname)) 480 if ret == zfs_errno.ZFS_ERR_STREAM_TRUNCATED: 481 raise lzc_exc.StreamTruncated() 482 if ret == zfs_errno.ZFS_ERR_BADPROP: 483 raise lzc_exc.PropertyInvalid(snapname) 484 485 raise lzc_exc.StreamIOError(ret) 486 487 488def lzc_promote_translate_error(ret, name): 489 if ret == 0: 490 return 491 if ret == errno.EINVAL: 492 _validate_fs_name(name) 493 raise lzc_exc.NotClone(name) 494 if ret == errno.ENOTSOCK: 495 raise lzc_exc.NotClone(name) 496 if ret == errno.ENOENT: 497 raise lzc_exc.FilesystemNotFound(name) 498 if ret == errno.EEXIST: 499 raise lzc_exc.SnapshotExists(name) 500 raise _generic_exception(ret, name, "Failed to promote dataset") 501 502 503def lzc_change_key_translate_error(ret, name): 504 if ret == 0: 505 return 506 if ret == errno.EINVAL: 507 _validate_fs_name(name) 508 raise lzc_exc.PropertyInvalid(name) 509 if ret == errno.ENOENT: 510 raise lzc_exc.FilesystemNotFound(name) 511 if ret == errno.EACCES: 512 raise lzc_exc.EncryptionKeyNotLoaded() 513 raise _generic_exception(ret, name, "Failed to change encryption key") 514 515 516def lzc_load_key_translate_error(ret, name, noop): 517 if ret == 0: 518 return 519 if ret == errno.EINVAL: 520 _validate_fs_name(name) 521 raise lzc_exc.PropertyInvalid(name) 522 if ret == errno.ENOENT: 523 raise lzc_exc.FilesystemNotFound(name) 524 if ret == errno.EACCES: 525 raise lzc_exc.EncryptionKeyInvalid() 526 if ret == errno.EEXIST: 527 raise lzc_exc.EncryptionKeyAlreadyLoaded() 528 if noop: 529 raise _generic_exception(ret, name, "Failed to load encryption key") 530 else: 531 raise _generic_exception(ret, name, "Failed to verify encryption key") 532 533 534def lzc_unload_key_translate_error(ret, name): 535 if ret == 0: 536 return 537 if ret == errno.EINVAL: 538 _validate_fs_name(name) 539 raise lzc_exc.PropertyInvalid(name) 540 if ret == errno.ENOENT: 541 raise lzc_exc.FilesystemNotFound(name) 542 if ret == errno.EACCES: 543 raise lzc_exc.EncryptionKeyNotLoaded() 544 raise _generic_exception(ret, name, "Failed to unload encryption key") 545 546 547def lzc_sync_translate_error(ret, name): 548 if ret == 0: 549 return 550 if ret == errno.ENOENT: 551 raise lzc_exc.PoolNotFound(name) 552 raise _generic_exception(ret, name, "Failed to sync pool") 553 554 555def lzc_reopen_translate_error(ret, name): 556 if ret == 0: 557 return 558 if ret == errno.ENOENT: 559 raise lzc_exc.PoolNotFound(name) 560 raise _generic_exception(ret, name, "Failed to reopen pool") 561 562 563def lzc_channel_program_translate_error(ret, name, error): 564 if ret == 0: 565 return 566 if ret == errno.ENOENT: 567 raise lzc_exc.PoolNotFound(name) 568 if ret == ETIME: 569 raise lzc_exc.ZCPTimeout() 570 if ret == errno.ENOMEM: 571 raise lzc_exc.ZCPMemoryError() 572 if ret == errno.ENOSPC: 573 raise lzc_exc.ZCPSpaceError() 574 if ret == errno.EPERM: 575 raise lzc_exc.ZCPPermissionError() 576 if ret == ECHRNG: 577 raise lzc_exc.ZCPRuntimeError(error) 578 if ret == errno.EINVAL: 579 if error is None: 580 raise lzc_exc.ZCPLimitInvalid() 581 else: 582 raise lzc_exc.ZCPSyntaxError(error) 583 raise _generic_exception(ret, name, "Failed to execute channel program") 584 585 586def lzc_pool_checkpoint_translate_error(ret, name, discard=False): 587 if ret == 0: 588 return 589 if ret == errno.ENOENT: 590 raise lzc_exc.PoolNotFound(name) 591 if ret == ZFS_ERR_CHECKPOINT_EXISTS: 592 raise lzc_exc.CheckpointExists() 593 if ret == ZFS_ERR_NO_CHECKPOINT: 594 raise lzc_exc.CheckpointNotFound() 595 if ret == ZFS_ERR_DISCARDING_CHECKPOINT: 596 raise lzc_exc.CheckpointDiscarding() 597 if ret == ZFS_ERR_DEVRM_IN_PROGRESS: 598 raise lzc_exc.DeviceRemovalRunning() 599 if ret == ZFS_ERR_VDEV_TOO_BIG: 600 raise lzc_exc.DeviceTooBig() 601 if ret == ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS: 602 raise lzc_exc.RaidzExpansionRunning() 603 if discard: 604 raise _generic_exception( 605 ret, name, "Failed to discard pool checkpoint") 606 else: 607 raise _generic_exception(ret, name, "Failed to create pool checkpoint") 608 609 610def lzc_pool_checkpoint_discard_translate_error(ret, name): 611 lzc_pool_checkpoint_translate_error(ret, name, discard=True) 612 613 614def lzc_rename_translate_error(ret, source, target): 615 if ret == 0: 616 return 617 if ret == errno.EINVAL: 618 _validate_fs_name(source) 619 _validate_fs_name(target) 620 if _pool_name(source) != _pool_name(target): 621 raise lzc_exc.PoolsDiffer(source) 622 if ret == errno.EEXIST: 623 raise lzc_exc.FilesystemExists(target) 624 if ret == errno.ENOENT: 625 raise lzc_exc.FilesystemNotFound(source) 626 if ret == ZFS_ERR_WRONG_PARENT: 627 raise lzc_exc.WrongParent(target) 628 raise _generic_exception(ret, source, "Failed to rename dataset") 629 630 631def lzc_destroy_translate_error(ret, name): 632 if ret == 0: 633 return 634 if ret == errno.EINVAL: 635 _validate_fs_name(name) 636 if ret == errno.ENOENT: 637 raise lzc_exc.FilesystemNotFound(name) 638 raise _generic_exception(ret, name, "Failed to destroy dataset") 639 640 641def lzc_inherit_prop_translate_error(ret, name, prop): 642 if ret == 0: 643 return 644 if ret == errno.EINVAL: 645 _validate_fs_name(name) 646 raise lzc_exc.PropertyInvalid(prop) 647 if ret == errno.ENOENT: 648 raise lzc_exc.DatasetNotFound(name) 649 raise _generic_exception(ret, name, "Failed to inherit a property") 650 651 652def lzc_set_prop_translate_error(ret, name, prop, val): 653 if ret == 0: 654 return 655 if ret == errno.EINVAL: 656 _validate_fs_or_snap_name(name) 657 raise lzc_exc.PropertyInvalid(prop) 658 if ret == errno.ENOENT: 659 raise lzc_exc.DatasetNotFound(name) 660 raise _generic_exception(ret, name, "Failed to set a property") 661 662 663def lzc_get_props_translate_error(ret, name): 664 if ret == 0: 665 return 666 if ret == errno.EINVAL: 667 _validate_fs_or_snap_name(name) 668 if ret == errno.ENOENT: 669 raise lzc_exc.DatasetNotFound(name) 670 raise _generic_exception(ret, name, "Failed to get properties") 671 672 673def lzc_list_children_translate_error(ret, name): 674 if ret == 0: 675 return 676 if ret == errno.EINVAL: 677 _validate_fs_name(name) 678 raise _generic_exception(ret, name, "Error while iterating children") 679 680 681def lzc_list_snaps_translate_error(ret, name): 682 if ret == 0: 683 return 684 if ret == errno.EINVAL: 685 _validate_fs_name(name) 686 raise _generic_exception(ret, name, "Error while iterating snapshots") 687 688 689def lzc_list_translate_error(ret, name, opts): 690 if ret == 0: 691 return 692 if ret == errno.ENOENT: 693 raise lzc_exc.DatasetNotFound(name) 694 if ret == errno.EINVAL: 695 _validate_fs_or_snap_name(name) 696 raise _generic_exception(ret, name, "Error obtaining a list") 697 698 699def _handle_err_list(ret, errlist, names, exception, mapper): 700 ''' 701 Convert one or more errors from an operation into the requested exception. 702 703 :param int ret: the overall return code. 704 :param errlist: the dictionary that maps entity names to their specific 705 error codes. 706 :type errlist: dict of bytes:int 707 :param names: the list of all names of the entities on which the operation 708 was attempted. 709 :param type exception: the type of the exception to raise if an error 710 occurred. The exception should be a subclass of 711 ``MultipleOperationsFailure``. 712 :param function mapper: the function that maps an error code and a name to 713 a Python exception. 714 715 Unless ``ret`` is zero this function will raise the ``exception``. 716 If the ``errlist`` is not empty, then the compound exception will contain 717 a list of exceptions corresponding to each individual error code in the 718 ``errlist``. 719 Otherwise, the ``exception`` will contain a list with a single exception 720 corresponding to the ``ret`` value. If the ``names`` list contains only one 721 element, that is, the operation was attempted on a single entity, then the 722 name of that entity is passed to the ``mapper``. 723 If the operation was attempted on multiple entities, but the ``errlist`` 724 is empty, then we can not know which entity caused the error and, thus, 725 ``None`` is used as a name to signify that fact. 726 727 .. note:: 728 Note that the ``errlist`` can contain a special element with a key of 729 "N_MORE_ERRORS". 730 That element means that there were too many errors to place on the 731 ``errlist``. 732 Those errors are suppressed and only their count is provided as a 733 value of the special ``N_MORE_ERRORS`` element. 734 ''' 735 if ret == 0: 736 return 737 738 if len(errlist) == 0: 739 suppressed_count = 0 740 names = list(zip(names, range(2))) 741 if len(names) == 1: 742 name, _ = names[0] 743 else: 744 name = None 745 errors = [mapper(ret, name)] 746 else: 747 errors = [] 748 suppressed_count = errlist.pop('N_MORE_ERRORS', 0) 749 for name in errlist: 750 err = errlist[name] 751 errors.append(mapper(err, name)) 752 753 raise exception(errors, suppressed_count) 754 755 756def _pool_name(name): 757 ''' 758 Extract a pool name from the given dataset or bookmark name. 759 760 '/' separates dataset name components. 761 '@' separates a snapshot name from the rest of the dataset name. 762 '#' separates a bookmark name from the rest of the dataset name. 763 ''' 764 return re.split(b'[/@#]', name, 1)[0] 765 766 767def _fs_name(name): 768 ''' 769 Extract a dataset name from the given snapshot or bookmark name. 770 771 '@' separates a snapshot name from the rest of the dataset name. 772 '#' separates a bookmark name from the rest of the dataset name. 773 ''' 774 return re.split(b'[@#]', name, 1)[0] 775 776 777def _is_valid_name_component(component): 778 allowed = string.ascii_letters + string.digits + u'-_.: ' 779 return component and all(x in allowed.encode() for x in component) 780 781 782def _is_valid_fs_name(name): 783 return name and all(_is_valid_name_component(c) for c in name.split(b'/')) 784 785 786def _is_valid_snap_name(name): 787 parts = name.split(b'@') 788 return (len(parts) == 2 and _is_valid_fs_name(parts[0]) and 789 _is_valid_name_component(parts[1])) 790 791 792def _is_valid_bmark_name(name): 793 parts = name.split(b'#') 794 return (len(parts) == 2 and _is_valid_fs_name(parts[0]) and 795 _is_valid_name_component(parts[1])) 796 797 798def _validate_fs_name(name): 799 if not _is_valid_fs_name(name): 800 raise lzc_exc.FilesystemNameInvalid(name) 801 elif len(name) > MAXNAMELEN: 802 raise lzc_exc.NameTooLong(name) 803 804 805def _validate_snap_name(name): 806 if not _is_valid_snap_name(name): 807 raise lzc_exc.SnapshotNameInvalid(name) 808 elif len(name) > MAXNAMELEN: 809 raise lzc_exc.NameTooLong(name) 810 811 812def _validate_bmark_name(name): 813 if not _is_valid_bmark_name(name): 814 raise lzc_exc.BookmarkNameInvalid(name) 815 elif len(name) > MAXNAMELEN: 816 raise lzc_exc.NameTooLong(name) 817 818 819def _validate_fs_or_snap_name(name): 820 if not _is_valid_fs_name(name) and not _is_valid_snap_name(name): 821 raise lzc_exc.NameInvalid(name) 822 elif len(name) > MAXNAMELEN: 823 raise lzc_exc.NameTooLong(name) 824 825 826def _generic_exception(err, name, message): 827 if err in _error_to_exception: 828 return _error_to_exception[err](name) 829 else: 830 return lzc_exc.ZFSGenericError(err, message, name) 831 832 833_error_to_exception = {e.errno: e for e in [ 834 lzc_exc.ZIOError, 835 lzc_exc.NoSpace, 836 lzc_exc.QuotaExceeded, 837 lzc_exc.DatasetBusy, 838 lzc_exc.NameTooLong, 839 lzc_exc.ReadOnlyPool, 840 lzc_exc.SuspendedPool, 841 lzc_exc.PoolsDiffer, 842 lzc_exc.PropertyNotSupported, 843]} 844 845 846# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4 847