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