Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #pragma once
7 :
8 : #include <assert.h>
9 : #include <errno.h>
10 : #include <stdbool.h>
11 : #include <stddef.h>
12 : #include <stdlib.h>
13 : #include <string.h>
14 : #include <unistd.h>
15 :
16 : extern const char *strerrordesc_np(int errnum);
17 :
18 : #define bf_packed __attribute__((packed))
19 : #define bf_aligned(x) __attribute__((aligned(x)))
20 : #define bf_unused __attribute__((unused))
21 :
22 : #ifndef bf_assert
23 : #define bf_assert(x) assert(x)
24 : #endif
25 :
26 : #define BF_STR(s) _BF_STR(s)
27 : #define _BF_STR(s) #s
28 :
29 : /**
30 : * Mark a variable as unused, to prevent the compiler from emitting a warning.
31 : *
32 : * @param x The variable to mark as unused.
33 : */
34 : #define UNUSED(x) (void)(x)
35 :
36 : /**
37 : * Set @p ptr to NULL and return its previous value.
38 : *
39 : * Inspired from systemd's TAKE_PTR() macro, which is itself inspired from
40 : * Rust's Option::take() method:
41 : * https://doc.rust-lang.org/std/option/enum.Option.html#method.take
42 : *
43 : * @param var Variable to return the value of.
44 : * @param type Type of @p var.
45 : * @param nullvalue Value to set @p var to.
46 : * @return Value of @p var before it was set to @p nullvalue.
47 : */
48 : #define TAKE_GENERIC(var, type, nullvalue) \
49 : ({ \
50 : /* NOLINTBEGIN: do not enclose 'type' in parentheses */ \
51 : type *_pvar_ = &(var); \
52 : type _var_ = *_pvar_; \
53 : type _nullvalue_ = nullvalue; \
54 : /* NOLINTEND */ \
55 : *_pvar_ = _nullvalue_; \
56 : _var_; \
57 : })
58 :
59 : #define TAKE_PTR_TYPE(ptr, type) TAKE_GENERIC(ptr, type, NULL)
60 : #define TAKE_PTR(ptr) TAKE_PTR_TYPE(ptr, typeof(ptr))
61 : #define TAKE_STRUCT_TYPE(s, type) TAKE_GENERIC(s, type, {})
62 : #define TAKE_STRUCT(s) TAKE_STRUCT_TYPE(s, typeof(s))
63 : #define TAKE_FD(fd) TAKE_GENERIC(fd, int, -1)
64 :
65 : /**
66 : * Get the number of element in an array.
67 : *
68 : * @param x The array.
69 : * @return size_t The number of elements in the array.
70 : */
71 : #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
72 :
73 : #define _cleanup_free_ __attribute__((__cleanup__(freep)))
74 : #define _cleanup_close_ __attribute__((__cleanup__(closep)))
75 :
76 : /**
77 : * Return a string describing the given error code.
78 : *
79 : * This function must be used over strerror(), which is marked at mt-unsafe.
80 : *
81 : * @param v Error code, can be positive or negative.
82 : */
83 : #define bf_strerror(v) strerrordesc_np(abs(v))
84 :
85 : /**
86 : * Swap two values.
87 : *
88 : * @param a First value to swap.
89 : * @param b Second value to swap.
90 : */
91 : #define bf_swap(a, b) \
92 : do { \
93 : typeof(a) __a = (a); \
94 : (a) = (b); \
95 : (b) = __a; \
96 : } while (0)
97 :
98 : #define bf_min(a, b) \
99 : ({ \
100 : __typeof__(a) _a = (a); \
101 : __typeof__(b) _b = (b); \
102 : _a < _b ? _a : _b; \
103 : })
104 :
105 : /**
106 : * Free a pointer and set it to NULL.
107 : *
108 : * @param ptr Pointer to free.
109 : */
110 84 : static inline void freep(void *ptr)
111 : {
112 542 : free(*(void **)ptr);
113 452 : *(void **)ptr = NULL;
114 102 : }
115 :
116 : /**
117 : * Close a file descriptor and set it to -1.
118 : *
119 : * File descriptors are expected to be uninitialized to -1, so this function
120 : * can be used to close a file descriptor and set it to -1 in a single
121 : * operation. If the file descriptor is already -1, it is not closed.
122 : *
123 : * @param fd File descriptor to close.
124 : */
125 : static inline void closep(int *fd)
126 : {
127 36 : if (*fd >= 0)
128 15 : close(*fd);
129 26 : *fd = -1;
130 : }
131 :
132 : /**
133 : * Duplicate a memory region.
134 : *
135 : * Allocate a new buffer of size @p len and copy @p src into it. Requirements
136 : * applicable to @p src and @p len:
137 : * - If @p src is NULL, @p len must be 0. In this case, NULL is returned.
138 : * - If @p src is non-NULL, a new buffer of @p len bytes will be allocated to
139 : * store the first @p len bytes of @p src. This new buffer is then returned.
140 : *
141 : * Unless NULL is returned, the new buffer is owned by the caller.
142 : *
143 : * @param src Source buffer to copy to @p dst.
144 : * @param len Number of bytes to copy to @p dst.
145 : * @return Pointer to the new buffer, or NULL on failure.
146 : */
147 0 : static inline void *bf_memdup(const void *src, size_t len)
148 : {
149 : void *dst;
150 :
151 0 : if (!src)
152 : return NULL;
153 :
154 0 : dst = malloc(len);
155 0 : if (!dst)
156 : return NULL;
157 :
158 0 : return memcpy(dst, src, len);
159 : }
160 :
161 : /**
162 : * Copy @p len bytes from @p src to @p dst.
163 : *
164 : * Allow for @p src to be NULL and/or @p len to be zero:
165 : * - If @p src is NULL, @p len must be equal 0. @p dst is not modified.
166 : * - If @p src is not NULL, @p len can be equal to 0, in which case @p dst is
167 : * not modified.
168 : *
169 : * @param dst Destination buffer. Can't be NULL, and must be big enough to store
170 : * @p len bytes from @p src.
171 : * @param src Source buffer to copy to @p dst.
172 : * @param len Number of bytes to copy to @p dst.
173 : * @return Pointer to @p dst.
174 : */
175 173 : static inline void *bf_memcpy(void *dst, const void *src, size_t len)
176 : {
177 173 : bf_assert(dst);
178 173 : bf_assert(src ? 1 : len == 0);
179 :
180 173 : if (!src || !len)
181 : return dst;
182 :
183 125 : return memcpy(dst, src, len);
184 : }
185 :
186 : /**
187 : * Reallocate @p ptr into a new buffer of size @p size.
188 : *
189 : * Behaves similarly to realloc(), except that @p ptr is left unchanged if
190 : * allocation fails, and an error is returned.
191 : *
192 : * @param ptr Memory buffer to grow. Can't be NULL.
193 : * @param size New size of the memory buffer.
194 : * @return 0 on success, or a negative errno value on failure.
195 : */
196 4 : static inline int bf_realloc(void **ptr, size_t size)
197 : {
198 : _cleanup_free_ void *_ptr;
199 :
200 4 : bf_assert(ptr);
201 :
202 4 : _ptr = realloc(*ptr, size);
203 4 : if (!_ptr)
204 : return -ENOMEM;
205 :
206 4 : *ptr = TAKE_PTR(_ptr);
207 :
208 4 : return 0;
209 : }
210 :
211 : /**
212 : * Returns true if @p a is equal to @p b.
213 : *
214 : * @param lhs First string.
215 : * @param rhs Second string.
216 : * @return True if @p a == @p b, false otherwise.
217 : */
218 : static inline bool bf_streq(const char *lhs, const char *rhs) // NOLINT
219 : {
220 303 : return strcmp(lhs, rhs) == 0;
221 : }
222 :
223 : /**
224 : * Copy a string to a buffer.
225 : *
226 : * @p src is copied to @p dst . If @p src is too long, at most @p len bytes are
227 : * copied (including the termination character).
228 : *
229 : * @param dst Destination buffer. Can't be NULL.
230 : * @param len Length of the destination buffer. The function will not copy more
231 : * than @p len bytes to @p dst , including @c \0 . Can't be 0.
232 : * @param src Soucre buffer to copy from. Will only be copied up to the
233 : * termination character if it fits. Can't be NULL.
234 : * @return 0 on success, or @c -E2BIG if @p src can't fit in @p dst .
235 : */
236 : int bf_strncpy(char *dst, size_t len, const char *src);
237 :
238 : /**
239 : * Read the contents of a file into a buffer.
240 : *
241 : * @param path Path to the file to read. Can't be NULL.
242 : * @param buf Pointer to a pointer to a buffer. The buffer will be allocated
243 : * automatically. The caller is responsible to free it. If @ref bf_read_file
244 : * fails, @p buf is left unchanged.
245 : * @param len Length of the allocated buffer. Populated by the function.
246 : * @return 0 on success, negative errno value on error.
247 : */
248 : int bf_read_file(const char *path, void **buf, size_t *len);
249 :
250 : /**
251 : * Write the contents of a buffer into a file.
252 : *
253 : * @param path Path to the file to write. Can't be NULL.
254 : * @param buf Buffer to write.
255 : * @param len Number of bytes to write the to file.
256 : * @return 0 on success, negative errno value on error.
257 : */
258 : int bf_write_file(const char *path, const void *buf, size_t len);
|