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""" 19Exceptions that can be raised by libzfs_core operations. 20""" 21from __future__ import absolute_import, division, print_function 22 23import errno 24from ._constants import ( 25 ECHRNG, 26 ECKSUM, 27 ETIME, 28 ZFS_ERR_CHECKPOINT_EXISTS, 29 ZFS_ERR_DISCARDING_CHECKPOINT, 30 ZFS_ERR_NO_CHECKPOINT, 31 ZFS_ERR_DEVRM_IN_PROGRESS, 32 ZFS_ERR_VDEV_TOO_BIG, 33 ZFS_ERR_WRONG_PARENT, 34 ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS, 35 zfs_errno 36) 37 38 39class ZFSError(Exception): 40 errno = None 41 message = None 42 name = None 43 44 def __str__(self): 45 if self.name is not None: 46 return "[Errno %d] %s: '%s'" % ( 47 self.errno, self.message, self.name) 48 else: 49 return "[Errno %d] %s" % (self.errno, self.message) 50 51 def __repr__(self): 52 return "%s(%r, %r)" % ( 53 self.__class__.__name__, self.errno, self.message) 54 55 56class ZFSGenericError(ZFSError): 57 58 def __init__(self, errno, name, message): 59 self.errno = errno 60 self.message = message 61 self.name = name 62 63 64class ZFSInitializationFailed(ZFSError): 65 message = "Failed to initialize libzfs_core" 66 67 def __init__(self, errno): 68 self.errno = errno 69 70 71class MultipleOperationsFailure(ZFSError): 72 73 def __init__(self, errors, suppressed_count): 74 # Use first of the individual error codes 75 # as an overall error code. This is more consistent. 76 self.errno = errors[0].errno 77 self.errors = errors 78 # this many errors were encountered but not placed on the `errors` list 79 self.suppressed_count = suppressed_count 80 81 def __str__(self): 82 return "%s, %d errors included, %d suppressed" % ( 83 ZFSError.__str__(self), len(self.errors), self.suppressed_count) 84 85 def __repr__(self): 86 return "%s(%r, %r, errors=%r, suppressed=%r)" % ( 87 self.__class__.__name__, self.errno, self.message, self.errors, 88 self.suppressed_count) 89 90 91class DatasetNotFound(ZFSError): 92 93 """ 94 This exception is raised when an operation failure can be caused by a 95 missing snapshot or a missing filesystem and it is impossible to 96 distinguish between the causes. 97 """ 98 errno = errno.ENOENT 99 message = "Dataset not found" 100 101 def __init__(self, name): 102 self.name = name 103 104 105class DatasetExists(ZFSError): 106 107 """ 108 This exception is raised when an operation failure can be caused by an 109 existing snapshot or filesystem and it is impossible to distinguish between 110 the causes. 111 """ 112 errno = errno.EEXIST 113 message = "Dataset already exists" 114 115 def __init__(self, name): 116 self.name = name 117 118 119class NotClone(ZFSError): 120 errno = errno.EINVAL 121 message = "Filesystem is not a clone, can not promote" 122 123 def __init__(self, name): 124 self.name = name 125 126 127class FilesystemExists(DatasetExists): 128 message = "Filesystem already exists" 129 130 def __init__(self, name): 131 self.name = name 132 133 134class FilesystemNotFound(DatasetNotFound): 135 message = "Filesystem not found" 136 137 def __init__(self, name): 138 self.name = name 139 140 141class ParentNotFound(ZFSError): 142 errno = errno.ENOENT 143 message = "Parent not found" 144 145 def __init__(self, name): 146 self.name = name 147 148 149class WrongParent(ZFSError): 150 errno = ZFS_ERR_WRONG_PARENT 151 message = "Parent dataset is not a filesystem" 152 153 def __init__(self, name): 154 self.name = name 155 156 157class SnapshotExists(DatasetExists): 158 message = "Snapshot already exists" 159 160 def __init__(self, name): 161 self.name = name 162 163 164class SnapshotNotFound(DatasetNotFound): 165 message = "Snapshot not found" 166 167 def __init__(self, name): 168 self.name = name 169 170 171class SnapshotNotLatest(ZFSError): 172 errno = errno.EEXIST 173 message = "Snapshot is not the latest" 174 175 def __init__(self, name): 176 self.name = name 177 178 179class SnapshotIsCloned(ZFSError): 180 errno = errno.EEXIST 181 message = "Snapshot is cloned" 182 183 def __init__(self, name): 184 self.name = name 185 186 187class SnapshotIsHeld(ZFSError): 188 errno = errno.EBUSY 189 message = "Snapshot is held" 190 191 def __init__(self, name): 192 self.name = name 193 194 195class DuplicateSnapshots(ZFSError): 196 errno = errno.EXDEV 197 message = "Requested multiple snapshots of the same filesystem" 198 199 def __init__(self, name): 200 self.name = name 201 202 203class SnapshotFailure(MultipleOperationsFailure): 204 message = "Creation of snapshot(s) failed for one or more reasons" 205 206 def __init__(self, errors, suppressed_count): 207 super(SnapshotFailure, self).__init__(errors, suppressed_count) 208 209 210class SnapshotDestructionFailure(MultipleOperationsFailure): 211 message = "Destruction of snapshot(s) failed for one or more reasons" 212 213 def __init__(self, errors, suppressed_count): 214 super(SnapshotDestructionFailure, self).__init__( 215 errors, suppressed_count) 216 217 218class BookmarkExists(ZFSError): 219 errno = errno.EEXIST 220 message = "Bookmark already exists" 221 222 def __init__(self, name): 223 self.name = name 224 225 226class BookmarkNotFound(ZFSError): 227 errno = errno.ENOENT 228 message = "Bookmark not found" 229 230 def __init__(self, name): 231 self.name = name 232 233 234class BookmarkMismatch(ZFSError): 235 errno = errno.EINVAL 236 message = "source is not an ancestor of the new bookmark's dataset" 237 238 def __init__(self, name): 239 self.name = name 240 241 242class BookmarkSourceInvalid(ZFSError): 243 errno = errno.EINVAL 244 message = "Bookmark source is not a valid snapshot or existing bookmark" 245 246 def __init__(self, name): 247 self.name = name 248 249 250class BookmarkNotSupported(ZFSError): 251 errno = errno.ENOTSUP 252 message = "Bookmark feature is not supported" 253 254 def __init__(self, name): 255 self.name = name 256 257 258class BookmarkFailure(MultipleOperationsFailure): 259 message = "Creation of bookmark(s) failed for one or more reasons" 260 261 def __init__(self, errors, suppressed_count): 262 super(BookmarkFailure, self).__init__(errors, suppressed_count) 263 264 265class BookmarkDestructionFailure(MultipleOperationsFailure): 266 message = "Destruction of bookmark(s) failed for one or more reasons" 267 268 def __init__(self, errors, suppressed_count): 269 super(BookmarkDestructionFailure, self).__init__( 270 errors, suppressed_count) 271 272 273class BadHoldCleanupFD(ZFSError): 274 errno = errno.EBADF 275 message = "Bad file descriptor as cleanup file descriptor" 276 277 278class HoldExists(ZFSError): 279 errno = errno.EEXIST 280 message = "Hold with a given tag already exists on snapshot" 281 282 def __init__(self, name): 283 self.name = name 284 285 286class HoldNotFound(ZFSError): 287 errno = errno.ENOENT 288 message = "Hold with a given tag does not exist on snapshot" 289 290 def __init__(self, name): 291 self.name = name 292 293 294class HoldFailure(MultipleOperationsFailure): 295 message = "Placement of hold(s) failed for one or more reasons" 296 297 def __init__(self, errors, suppressed_count): 298 super(HoldFailure, self).__init__(errors, suppressed_count) 299 300 301class HoldReleaseFailure(MultipleOperationsFailure): 302 message = "Release of hold(s) failed for one or more reasons" 303 304 def __init__(self, errors, suppressed_count): 305 super(HoldReleaseFailure, self).__init__(errors, suppressed_count) 306 307 308class SnapshotMismatch(ZFSError): 309 errno = errno.ENODEV 310 message = "Snapshot is not descendant of source snapshot" 311 312 def __init__(self, name): 313 self.name = name 314 315 316class StreamMismatch(ZFSError): 317 errno = errno.ENODEV 318 message = "Stream is not applicable to destination dataset" 319 320 def __init__(self, name): 321 self.name = name 322 323 324class DestinationModified(ZFSError): 325 errno = errno.ETXTBSY 326 message = "Destination dataset has modifications that can not be undone" 327 328 def __init__(self, name): 329 self.name = name 330 331 332class BadStream(ZFSError): 333 errno = ECKSUM 334 message = "Bad backup stream" 335 336 337class StreamFeatureNotSupported(ZFSError): 338 errno = errno.ENOTSUP 339 message = "Stream contains unsupported feature" 340 341 342class UnknownStreamFeature(ZFSError): 343 errno = errno.ENOTSUP 344 message = "Unknown feature requested for stream" 345 346 347class StreamFeatureInvalid(ZFSError): 348 errno = errno.EINVAL 349 message = "Kernel modules must be upgraded to receive this stream" 350 351 352class StreamFeatureIncompatible(ZFSError): 353 errno = errno.EINVAL 354 message = "Incompatible embedded feature with encrypted receive" 355 356 357class StreamTruncated(ZFSError): 358 errno = zfs_errno.ZFS_ERR_STREAM_TRUNCATED 359 message = "incomplete stream" 360 361 362class ReceivePropertyFailure(MultipleOperationsFailure): 363 message = "Receiving of properties failed for one or more reasons" 364 365 def __init__(self, errors, suppressed_count): 366 super(ReceivePropertyFailure, self).__init__(errors, suppressed_count) 367 368 369class StreamIOError(ZFSError): 370 message = "I/O error while writing or reading stream" 371 372 def __init__(self, errno): 373 self.errno = errno 374 375 376class ZIOError(ZFSError): 377 errno = errno.EIO 378 message = "I/O error" 379 380 def __init__(self, name): 381 self.name = name 382 383 384class NoSpace(ZFSError): 385 errno = errno.ENOSPC 386 message = "No space left" 387 388 def __init__(self, name): 389 self.name = name 390 391 392class QuotaExceeded(ZFSError): 393 errno = errno.EDQUOT 394 message = "Quota exceeded" 395 396 def __init__(self, name): 397 self.name = name 398 399 400class DatasetBusy(ZFSError): 401 errno = errno.EBUSY 402 message = "Dataset is busy" 403 404 def __init__(self, name): 405 self.name = name 406 407 408class NameTooLong(ZFSError): 409 errno = errno.ENAMETOOLONG 410 message = "Dataset name is too long" 411 412 def __init__(self, name): 413 self.name = name 414 415 416class NameInvalid(ZFSError): 417 errno = errno.EINVAL 418 message = "Invalid name" 419 420 def __init__(self, name): 421 self.name = name 422 423 424class SnapshotNameInvalid(NameInvalid): 425 message = "Invalid name for snapshot" 426 427 def __init__(self, name): 428 self.name = name 429 430 431class FilesystemNameInvalid(NameInvalid): 432 message = "Invalid name for filesystem or volume" 433 434 def __init__(self, name): 435 self.name = name 436 437 438class BookmarkNameInvalid(NameInvalid): 439 message = "Invalid name for bookmark" 440 441 def __init__(self, name): 442 self.name = name 443 444 445class ReadOnlyPool(ZFSError): 446 errno = errno.EROFS 447 message = "Pool is read-only" 448 449 def __init__(self, name): 450 self.name = name 451 452 453class SuspendedPool(ZFSError): 454 errno = errno.EAGAIN 455 message = "Pool is suspended" 456 457 def __init__(self, name): 458 self.name = name 459 460 461class PoolNotFound(ZFSError): 462 errno = errno.EXDEV 463 message = "No such pool" 464 465 def __init__(self, name): 466 self.name = name 467 468 469class PoolsDiffer(ZFSError): 470 errno = errno.EXDEV 471 message = "Source and target belong to different pools" 472 473 def __init__(self, name): 474 self.name = name 475 476 477class FeatureNotSupported(ZFSError): 478 errno = errno.ENOTSUP 479 message = "Feature is not supported in this version" 480 481 def __init__(self, name): 482 self.name = name 483 484 485class PropertyNotSupported(ZFSError): 486 errno = errno.ENOTSUP 487 message = "Property is not supported in this version" 488 489 def __init__(self, name): 490 self.name = name 491 492 493class PropertyInvalid(ZFSError): 494 errno = errno.EINVAL 495 message = "Invalid property or property value" 496 497 def __init__(self, name): 498 self.name = name 499 500 501class DatasetTypeInvalid(ZFSError): 502 errno = errno.EINVAL 503 message = "Specified dataset type is unknown" 504 505 def __init__(self, name): 506 self.name = name 507 508 509class UnknownCryptCommand(ZFSError): 510 errno = errno.EINVAL 511 message = "Specified crypt command is invalid" 512 513 def __init__(self, name): 514 self.name = name 515 516 517class EncryptionKeyNotLoaded(ZFSError): 518 errno = errno.EACCES 519 message = "Encryption key is not currently loaded" 520 521 522class EncryptionKeyAlreadyLoaded(ZFSError): 523 errno = errno.EEXIST 524 message = "Encryption key is already loaded" 525 526 527class EncryptionKeyInvalid(ZFSError): 528 errno = errno.EACCES 529 message = "Incorrect encryption key provided" 530 531 532class ZCPError(ZFSError): 533 errno = None 534 message = None 535 536 537class ZCPSyntaxError(ZCPError): 538 errno = errno.EINVAL 539 message = "Channel program contains syntax errors" 540 541 def __init__(self, details): 542 self.details = details 543 544 545class ZCPRuntimeError(ZCPError): 546 errno = ECHRNG 547 message = "Channel programs encountered a runtime error" 548 549 def __init__(self, details): 550 self.details = details 551 552 553class ZCPLimitInvalid(ZCPError): 554 errno = errno.EINVAL 555 message = "Channel program called with invalid limits" 556 557 558class ZCPTimeout(ZCPError): 559 errno = ETIME 560 message = "Channel program timed out" 561 562 563class ZCPSpaceError(ZCPError): 564 errno = errno.ENOSPC 565 message = "Channel program exhausted the memory limit" 566 567 568class ZCPMemoryError(ZCPError): 569 errno = errno.ENOMEM 570 message = "Channel program return value too large" 571 572 573class ZCPPermissionError(ZCPError): 574 errno = errno.EPERM 575 message = "Channel programs must be run as root" 576 577 578class CheckpointExists(ZFSError): 579 errno = ZFS_ERR_CHECKPOINT_EXISTS 580 message = "Pool already has a checkpoint" 581 582 583class CheckpointNotFound(ZFSError): 584 errno = ZFS_ERR_NO_CHECKPOINT 585 message = "Pool does not have a checkpoint" 586 587 588class CheckpointDiscarding(ZFSError): 589 errno = ZFS_ERR_DISCARDING_CHECKPOINT 590 message = "Pool checkpoint is being discarded" 591 592 593class DeviceRemovalRunning(ZFSError): 594 errno = ZFS_ERR_DEVRM_IN_PROGRESS 595 message = "A vdev is currently being removed" 596 597 598class DeviceTooBig(ZFSError): 599 errno = ZFS_ERR_VDEV_TOO_BIG 600 message = "One or more top-level vdevs exceed the maximum vdev size" 601 602 603class RaidzExpansionRunning(ZFSError): 604 errno = ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS 605 message = "A raidz device is currently expanding" 606 607 608# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4 609