1 | /* |
2 | * Copyright 2013-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <errno.h> |
20 | |
21 | #include <cstdio> |
22 | #include <stdexcept> |
23 | #include <system_error> |
24 | |
25 | #include <folly/Conv.h> |
26 | #include <folly/FBString.h> |
27 | #include <folly/Likely.h> |
28 | #include <folly/Portability.h> |
29 | |
30 | namespace folly { |
31 | |
32 | // Various helpers to throw appropriate std::system_error exceptions from C |
33 | // library errors (returned in errno, as positive return values (many POSIX |
34 | // functions), or as negative return values (Linux syscalls)) |
35 | // |
36 | // The *Explicit functions take an explicit value for errno. |
37 | |
38 | inline std::system_error makeSystemErrorExplicit(int err, const char* msg) { |
39 | // TODO: The C++ standard indicates that std::generic_category() should be |
40 | // used for POSIX errno codes. |
41 | // |
42 | // We should ideally change this to use std::generic_category() instead of |
43 | // std::system_category(). However, undertaking this change will require |
44 | // updating existing call sites that currently catch exceptions thrown by |
45 | // this code and currently expect std::system_category. |
46 | return std::system_error(err, std::system_category(), msg); |
47 | } |
48 | |
49 | template <class... Args> |
50 | std::system_error makeSystemErrorExplicit(int err, Args&&... args) { |
51 | return makeSystemErrorExplicit( |
52 | err, to<fbstring>(std::forward<Args>(args)...).c_str()); |
53 | } |
54 | |
55 | inline std::system_error makeSystemError(const char* msg) { |
56 | return makeSystemErrorExplicit(errno, msg); |
57 | } |
58 | |
59 | template <class... Args> |
60 | std::system_error makeSystemError(Args&&... args) { |
61 | return makeSystemErrorExplicit(errno, std::forward<Args>(args)...); |
62 | } |
63 | |
64 | // Helper to throw std::system_error |
65 | [[noreturn]] inline void throwSystemErrorExplicit(int err, const char* msg) { |
66 | throw_exception(makeSystemErrorExplicit(err, msg)); |
67 | } |
68 | |
69 | template <class... Args> |
70 | [[noreturn]] void throwSystemErrorExplicit(int err, Args&&... args) { |
71 | throw_exception(makeSystemErrorExplicit(err, std::forward<Args>(args)...)); |
72 | } |
73 | |
74 | // Helper to throw std::system_error from errno and components of a string |
75 | template <class... Args> |
76 | [[noreturn]] void throwSystemError(Args&&... args) { |
77 | throwSystemErrorExplicit(errno, std::forward<Args>(args)...); |
78 | } |
79 | |
80 | // Check a Posix return code (0 on success, error number on error), throw |
81 | // on error. |
82 | template <class... Args> |
83 | void checkPosixError(int err, Args&&... args) { |
84 | if (UNLIKELY(err != 0)) { |
85 | throwSystemErrorExplicit(err, std::forward<Args>(args)...); |
86 | } |
87 | } |
88 | |
89 | // Check a Linux kernel-style return code (>= 0 on success, negative error |
90 | // number on error), throw on error. |
91 | template <class... Args> |
92 | void checkKernelError(ssize_t ret, Args&&... args) { |
93 | if (UNLIKELY(ret < 0)) { |
94 | throwSystemErrorExplicit(int(-ret), std::forward<Args>(args)...); |
95 | } |
96 | } |
97 | |
98 | // Check a traditional Unix return code (-1 and sets errno on error), throw |
99 | // on error. |
100 | template <class... Args> |
101 | void checkUnixError(ssize_t ret, Args&&... args) { |
102 | if (UNLIKELY(ret == -1)) { |
103 | throwSystemError(std::forward<Args>(args)...); |
104 | } |
105 | } |
106 | |
107 | template <class... Args> |
108 | void checkUnixErrorExplicit(ssize_t ret, int savedErrno, Args&&... args) { |
109 | if (UNLIKELY(ret == -1)) { |
110 | throwSystemErrorExplicit(savedErrno, std::forward<Args>(args)...); |
111 | } |
112 | } |
113 | |
114 | // Check the return code from a fopen-style function (returns a non-nullptr |
115 | // FILE* on success, nullptr on error, sets errno). Works with fopen, fdopen, |
116 | // freopen, tmpfile, etc. |
117 | template <class... Args> |
118 | void checkFopenError(FILE* fp, Args&&... args) { |
119 | if (UNLIKELY(!fp)) { |
120 | throwSystemError(std::forward<Args>(args)...); |
121 | } |
122 | } |
123 | |
124 | template <class... Args> |
125 | void checkFopenErrorExplicit(FILE* fp, int savedErrno, Args&&... args) { |
126 | if (UNLIKELY(!fp)) { |
127 | throwSystemErrorExplicit(savedErrno, std::forward<Args>(args)...); |
128 | } |
129 | } |
130 | |
131 | /** |
132 | * If cond is not true, raise an exception of type E. E must have a ctor that |
133 | * works with const char* (a description of the failure). |
134 | */ |
135 | #define CHECK_THROW(cond, E) \ |
136 | do { \ |
137 | if (!(cond)) { \ |
138 | folly::throw_exception<E>("Check failed: " #cond); \ |
139 | } \ |
140 | } while (0) |
141 | |
142 | } // namespace folly |
143 | |