1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "absl/status/status.h"
15
16 #include <errno.h>
17
18 #include <atomic>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23 #include <ostream>
24 #include <string>
25
26 #include "absl/base/attributes.h"
27 #include "absl/base/config.h"
28 #include "absl/base/internal/raw_logging.h"
29 #include "absl/base/internal/strerror.h"
30 #include "absl/base/macros.h"
31 #include "absl/base/no_destructor.h"
32 #include "absl/debugging/stacktrace.h"
33 #include "absl/debugging/symbolize.h"
34 #include "absl/status/internal/status_internal.h"
35 #include "absl/strings/str_cat.h"
36 #include "absl/strings/str_format.h"
37 #include "absl/strings/str_split.h"
38 #include "absl/strings/string_view.h"
39 #include "absl/types/optional.h"
40
41 namespace absl {
42 ABSL_NAMESPACE_BEGIN
43
44 static_assert(
45 alignof(status_internal::StatusRep) >= 4,
46 "absl::Status assumes it can use the bottom 2 bits of a StatusRep*.");
47
StatusCodeToString(StatusCode code)48 std::string StatusCodeToString(StatusCode code) {
49 switch (code) {
50 case StatusCode::kOk:
51 return "OK";
52 case StatusCode::kCancelled:
53 return "CANCELLED";
54 case StatusCode::kUnknown:
55 return "UNKNOWN";
56 case StatusCode::kInvalidArgument:
57 return "INVALID_ARGUMENT";
58 case StatusCode::kDeadlineExceeded:
59 return "DEADLINE_EXCEEDED";
60 case StatusCode::kNotFound:
61 return "NOT_FOUND";
62 case StatusCode::kAlreadyExists:
63 return "ALREADY_EXISTS";
64 case StatusCode::kPermissionDenied:
65 return "PERMISSION_DENIED";
66 case StatusCode::kUnauthenticated:
67 return "UNAUTHENTICATED";
68 case StatusCode::kResourceExhausted:
69 return "RESOURCE_EXHAUSTED";
70 case StatusCode::kFailedPrecondition:
71 return "FAILED_PRECONDITION";
72 case StatusCode::kAborted:
73 return "ABORTED";
74 case StatusCode::kOutOfRange:
75 return "OUT_OF_RANGE";
76 case StatusCode::kUnimplemented:
77 return "UNIMPLEMENTED";
78 case StatusCode::kInternal:
79 return "INTERNAL";
80 case StatusCode::kUnavailable:
81 return "UNAVAILABLE";
82 case StatusCode::kDataLoss:
83 return "DATA_LOSS";
84 default:
85 return "";
86 }
87 }
88
operator <<(std::ostream & os,StatusCode code)89 std::ostream& operator<<(std::ostream& os, StatusCode code) {
90 return os << StatusCodeToString(code);
91 }
92
EmptyString()93 const std::string* Status::EmptyString() {
94 static const absl::NoDestructor<std::string> kEmpty;
95 return kEmpty.get();
96 }
97
98 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
99 constexpr const char Status::kMovedFromString[];
100 #endif
101
MovedFromString()102 const std::string* Status::MovedFromString() {
103 static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString);
104 return kMovedFrom.get();
105 }
106
Status(absl::StatusCode code,absl::string_view msg)107 Status::Status(absl::StatusCode code, absl::string_view msg)
108 : rep_(CodeToInlinedRep(code)) {
109 if (code != absl::StatusCode::kOk && !msg.empty()) {
110 rep_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr));
111 }
112 }
113
PrepareToModify(uintptr_t rep)114 status_internal::StatusRep* Status::PrepareToModify(uintptr_t rep) {
115 if (IsInlined(rep)) {
116 return new status_internal::StatusRep(InlinedRepToCode(rep),
117 absl::string_view(), nullptr);
118 }
119 return RepToPointer(rep)->CloneAndUnref();
120 }
121
ToStringSlow(uintptr_t rep,StatusToStringMode mode)122 std::string Status::ToStringSlow(uintptr_t rep, StatusToStringMode mode) {
123 if (IsInlined(rep)) {
124 return absl::StrCat(absl::StatusCodeToString(InlinedRepToCode(rep)), ": ");
125 }
126 return RepToPointer(rep)->ToString(mode);
127 }
128
operator <<(std::ostream & os,const Status & x)129 std::ostream& operator<<(std::ostream& os, const Status& x) {
130 os << x.ToString(StatusToStringMode::kWithEverything);
131 return os;
132 }
133
AbortedError(absl::string_view message)134 Status AbortedError(absl::string_view message) {
135 return Status(absl::StatusCode::kAborted, message);
136 }
137
AlreadyExistsError(absl::string_view message)138 Status AlreadyExistsError(absl::string_view message) {
139 return Status(absl::StatusCode::kAlreadyExists, message);
140 }
141
CancelledError(absl::string_view message)142 Status CancelledError(absl::string_view message) {
143 return Status(absl::StatusCode::kCancelled, message);
144 }
145
DataLossError(absl::string_view message)146 Status DataLossError(absl::string_view message) {
147 return Status(absl::StatusCode::kDataLoss, message);
148 }
149
DeadlineExceededError(absl::string_view message)150 Status DeadlineExceededError(absl::string_view message) {
151 return Status(absl::StatusCode::kDeadlineExceeded, message);
152 }
153
FailedPreconditionError(absl::string_view message)154 Status FailedPreconditionError(absl::string_view message) {
155 return Status(absl::StatusCode::kFailedPrecondition, message);
156 }
157
InternalError(absl::string_view message)158 Status InternalError(absl::string_view message) {
159 return Status(absl::StatusCode::kInternal, message);
160 }
161
InvalidArgumentError(absl::string_view message)162 Status InvalidArgumentError(absl::string_view message) {
163 return Status(absl::StatusCode::kInvalidArgument, message);
164 }
165
NotFoundError(absl::string_view message)166 Status NotFoundError(absl::string_view message) {
167 return Status(absl::StatusCode::kNotFound, message);
168 }
169
OutOfRangeError(absl::string_view message)170 Status OutOfRangeError(absl::string_view message) {
171 return Status(absl::StatusCode::kOutOfRange, message);
172 }
173
PermissionDeniedError(absl::string_view message)174 Status PermissionDeniedError(absl::string_view message) {
175 return Status(absl::StatusCode::kPermissionDenied, message);
176 }
177
ResourceExhaustedError(absl::string_view message)178 Status ResourceExhaustedError(absl::string_view message) {
179 return Status(absl::StatusCode::kResourceExhausted, message);
180 }
181
UnauthenticatedError(absl::string_view message)182 Status UnauthenticatedError(absl::string_view message) {
183 return Status(absl::StatusCode::kUnauthenticated, message);
184 }
185
UnavailableError(absl::string_view message)186 Status UnavailableError(absl::string_view message) {
187 return Status(absl::StatusCode::kUnavailable, message);
188 }
189
UnimplementedError(absl::string_view message)190 Status UnimplementedError(absl::string_view message) {
191 return Status(absl::StatusCode::kUnimplemented, message);
192 }
193
UnknownError(absl::string_view message)194 Status UnknownError(absl::string_view message) {
195 return Status(absl::StatusCode::kUnknown, message);
196 }
197
IsAborted(const Status & status)198 bool IsAborted(const Status& status) {
199 return status.code() == absl::StatusCode::kAborted;
200 }
201
IsAlreadyExists(const Status & status)202 bool IsAlreadyExists(const Status& status) {
203 return status.code() == absl::StatusCode::kAlreadyExists;
204 }
205
IsCancelled(const Status & status)206 bool IsCancelled(const Status& status) {
207 return status.code() == absl::StatusCode::kCancelled;
208 }
209
IsDataLoss(const Status & status)210 bool IsDataLoss(const Status& status) {
211 return status.code() == absl::StatusCode::kDataLoss;
212 }
213
IsDeadlineExceeded(const Status & status)214 bool IsDeadlineExceeded(const Status& status) {
215 return status.code() == absl::StatusCode::kDeadlineExceeded;
216 }
217
IsFailedPrecondition(const Status & status)218 bool IsFailedPrecondition(const Status& status) {
219 return status.code() == absl::StatusCode::kFailedPrecondition;
220 }
221
IsInternal(const Status & status)222 bool IsInternal(const Status& status) {
223 return status.code() == absl::StatusCode::kInternal;
224 }
225
IsInvalidArgument(const Status & status)226 bool IsInvalidArgument(const Status& status) {
227 return status.code() == absl::StatusCode::kInvalidArgument;
228 }
229
IsNotFound(const Status & status)230 bool IsNotFound(const Status& status) {
231 return status.code() == absl::StatusCode::kNotFound;
232 }
233
IsOutOfRange(const Status & status)234 bool IsOutOfRange(const Status& status) {
235 return status.code() == absl::StatusCode::kOutOfRange;
236 }
237
IsPermissionDenied(const Status & status)238 bool IsPermissionDenied(const Status& status) {
239 return status.code() == absl::StatusCode::kPermissionDenied;
240 }
241
IsResourceExhausted(const Status & status)242 bool IsResourceExhausted(const Status& status) {
243 return status.code() == absl::StatusCode::kResourceExhausted;
244 }
245
IsUnauthenticated(const Status & status)246 bool IsUnauthenticated(const Status& status) {
247 return status.code() == absl::StatusCode::kUnauthenticated;
248 }
249
IsUnavailable(const Status & status)250 bool IsUnavailable(const Status& status) {
251 return status.code() == absl::StatusCode::kUnavailable;
252 }
253
IsUnimplemented(const Status & status)254 bool IsUnimplemented(const Status& status) {
255 return status.code() == absl::StatusCode::kUnimplemented;
256 }
257
IsUnknown(const Status & status)258 bool IsUnknown(const Status& status) {
259 return status.code() == absl::StatusCode::kUnknown;
260 }
261
ErrnoToStatusCode(int error_number)262 StatusCode ErrnoToStatusCode(int error_number) {
263 switch (error_number) {
264 case 0:
265 return StatusCode::kOk;
266 case EINVAL: // Invalid argument
267 case ENAMETOOLONG: // Filename too long
268 case E2BIG: // Argument list too long
269 case EDESTADDRREQ: // Destination address required
270 case EDOM: // Mathematics argument out of domain of function
271 case EFAULT: // Bad address
272 case EILSEQ: // Illegal byte sequence
273 case ENOPROTOOPT: // Protocol not available
274 case ENOSTR: // Not a STREAM
275 case ENOTSOCK: // Not a socket
276 case ENOTTY: // Inappropriate I/O control operation
277 case EPROTOTYPE: // Protocol wrong type for socket
278 case ESPIPE: // Invalid seek
279 return StatusCode::kInvalidArgument;
280 case ETIMEDOUT: // Connection timed out
281 case ETIME: // Timer expired
282 return StatusCode::kDeadlineExceeded;
283 case ENODEV: // No such device
284 case ENOENT: // No such file or directory
285 #ifdef ENOMEDIUM
286 case ENOMEDIUM: // No medium found
287 #endif
288 case ENXIO: // No such device or address
289 case ESRCH: // No such process
290 return StatusCode::kNotFound;
291 case EEXIST: // File exists
292 case EADDRNOTAVAIL: // Address not available
293 case EALREADY: // Connection already in progress
294 #ifdef ENOTUNIQ
295 case ENOTUNIQ: // Name not unique on network
296 #endif
297 return StatusCode::kAlreadyExists;
298 case EPERM: // Operation not permitted
299 case EACCES: // Permission denied
300 #ifdef ENOKEY
301 case ENOKEY: // Required key not available
302 #endif
303 case EROFS: // Read only file system
304 return StatusCode::kPermissionDenied;
305 case ENOTEMPTY: // Directory not empty
306 case EISDIR: // Is a directory
307 case ENOTDIR: // Not a directory
308 case EADDRINUSE: // Address already in use
309 case EBADF: // Invalid file descriptor
310 #ifdef EBADFD
311 case EBADFD: // File descriptor in bad state
312 #endif
313 case EBUSY: // Device or resource busy
314 case ECHILD: // No child processes
315 case EISCONN: // Socket is connected
316 #ifdef EISNAM
317 case EISNAM: // Is a named type file
318 #endif
319 #ifdef ENOTBLK
320 case ENOTBLK: // Block device required
321 #endif
322 case ENOTCONN: // The socket is not connected
323 case EPIPE: // Broken pipe
324 #ifdef ESHUTDOWN
325 case ESHUTDOWN: // Cannot send after transport endpoint shutdown
326 #endif
327 case ETXTBSY: // Text file busy
328 #ifdef EUNATCH
329 case EUNATCH: // Protocol driver not attached
330 #endif
331 return StatusCode::kFailedPrecondition;
332 case ENOSPC: // No space left on device
333 #ifdef EDQUOT
334 case EDQUOT: // Disk quota exceeded
335 #endif
336 case EMFILE: // Too many open files
337 case EMLINK: // Too many links
338 case ENFILE: // Too many open files in system
339 case ENOBUFS: // No buffer space available
340 case ENODATA: // No message is available on the STREAM read queue
341 case ENOMEM: // Not enough space
342 case ENOSR: // No STREAM resources
343 #ifdef EUSERS
344 case EUSERS: // Too many users
345 #endif
346 return StatusCode::kResourceExhausted;
347 #ifdef ECHRNG
348 case ECHRNG: // Channel number out of range
349 #endif
350 case EFBIG: // File too large
351 case EOVERFLOW: // Value too large to be stored in data type
352 case ERANGE: // Result too large
353 return StatusCode::kOutOfRange;
354 #ifdef ENOPKG
355 case ENOPKG: // Package not installed
356 #endif
357 case ENOSYS: // Function not implemented
358 case ENOTSUP: // Operation not supported
359 case EAFNOSUPPORT: // Address family not supported
360 #ifdef EPFNOSUPPORT
361 case EPFNOSUPPORT: // Protocol family not supported
362 #endif
363 case EPROTONOSUPPORT: // Protocol not supported
364 #ifdef ESOCKTNOSUPPORT
365 case ESOCKTNOSUPPORT: // Socket type not supported
366 #endif
367 case EXDEV: // Improper link
368 return StatusCode::kUnimplemented;
369 case EAGAIN: // Resource temporarily unavailable
370 #ifdef ECOMM
371 case ECOMM: // Communication error on send
372 #endif
373 case ECONNREFUSED: // Connection refused
374 case ECONNABORTED: // Connection aborted
375 case ECONNRESET: // Connection reset
376 case EINTR: // Interrupted function call
377 #ifdef EHOSTDOWN
378 case EHOSTDOWN: // Host is down
379 #endif
380 case EHOSTUNREACH: // Host is unreachable
381 case ENETDOWN: // Network is down
382 case ENETRESET: // Connection aborted by network
383 case ENETUNREACH: // Network unreachable
384 case ENOLCK: // No locks available
385 case ENOLINK: // Link has been severed
386 #ifdef ENONET
387 case ENONET: // Machine is not on the network
388 #endif
389 return StatusCode::kUnavailable;
390 case EDEADLK: // Resource deadlock avoided
391 #ifdef ESTALE
392 case ESTALE: // Stale file handle
393 #endif
394 return StatusCode::kAborted;
395 case ECANCELED: // Operation cancelled
396 return StatusCode::kCancelled;
397 default:
398 return StatusCode::kUnknown;
399 }
400 }
401
402 namespace {
MessageForErrnoToStatus(int error_number,absl::string_view message)403 std::string MessageForErrnoToStatus(int error_number,
404 absl::string_view message) {
405 return absl::StrCat(message, ": ",
406 absl::base_internal::StrError(error_number));
407 }
408 } // namespace
409
ErrnoToStatus(int error_number,absl::string_view message)410 Status ErrnoToStatus(int error_number, absl::string_view message) {
411 return Status(ErrnoToStatusCode(error_number),
412 MessageForErrnoToStatus(error_number, message));
413 }
414
StatusMessageAsCStr(const Status & status)415 const char* StatusMessageAsCStr(const Status& status) {
416 // As an internal implementation detail, we guarantee that if status.message()
417 // is non-empty, then the resulting string_view is null terminated.
418 auto sv_message = status.message();
419 return sv_message.empty() ? "" : sv_message.data();
420 }
421
422 ABSL_NAMESPACE_END
423 } // namespace absl
424