Branch data 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 <stdint.h>
13 : : #include <stdlib.h>
14 : : #include <string.h>
15 : : #include <strings.h>
16 : :
17 : : extern const char *strerrordesc_np(int errnum);
18 : :
19 : : #define _BF_APPLY0(t, s, dummy)
20 : : #define _BF_APPLY1(t, s, a) t(a)
21 : : #define _BF_APPLY2(t, s, a, ...) t(a) s _BF_APPLY1(t, s, __VA_ARGS__)
22 : : #define _BF_APPLY3(t, s, a, ...) t(a) s _BF_APPLY2(t, s, __VA_ARGS__)
23 : : #define _BF_APPLY4(t, s, a, ...) t(a) s _BF_APPLY3(t, s, __VA_ARGS__)
24 : : #define _BF_APPLY5(t, s, a, ...) t(a) s _BF_APPLY4(t, s, __VA_ARGS__)
25 : : #define _BF_APPLY6(t, s, a, ...) t(a) s _BF_APPLY5(t, s, __VA_ARGS__)
26 : : #define _BF_APPLY7(t, s, a, ...) t(a) s _BF_APPLY6(t, s, __VA_ARGS__)
27 : : #define _BF_APPLY8(t, s, a, ...) t(a) s _BF_APPLY7(t, s, __VA_ARGS__)
28 : : #define _BF_APPLY9(t, s, a, ...) t(a) s _BF_APPLY8(t, s, __VA_ARGS__)
29 : : #define _BF_APPLY10(t, s, a, ...) t(a) s _BF_APPLY9(t, s, __VA_ARGS__)
30 : : #define _BF_APPLY11(t, s, a, ...) t(a) s _BF_APPLY10(t, s, __VA_ARGS__)
31 : : #define _BF_APPLY12(t, s, a, ...) t(a) s _BF_APPLY11(t, s, __VA_ARGS__)
32 : : #define _BF_APPLY13(t, s, a, ...) t(a) s _BF_APPLY12(t, s, __VA_ARGS__)
33 : : #define _BF_APPLY14(t, s, a, ...) t(a) s _BF_APPLY13(t, s, __VA_ARGS__)
34 : : #define _BF_APPLY15(t, s, a, ...) t(a) s _BF_APPLY14(t, s, __VA_ARGS__)
35 : : #define _BF_APPLY16(t, s, a, ...) t(a) s _BF_APPLY15(t, s, __VA_ARGS__)
36 : :
37 : : #define __BF_NUM_ARGS1(dummy, x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, \
38 : : x6, x5, x4, x3, x2, x1, x0, ...) \
39 : : x0
40 : : #define _BF_NUM_ARGS(...) \
41 : : __BF_NUM_ARGS1(dummy, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, \
42 : : 6, 5, 4, 3, 2, 1, 0)
43 : :
44 : : #define ___BF_APPLY_ALL(t, s, n, ...) _BF_APPLY##n(t, s, __VA_ARGS__)
45 : : #define __BF_APPLY_ALL(t, s, n, ...) ___BF_APPLY_ALL(t, s, n, __VA_ARGS__)
46 : : #define _BF_APPLY_ALL(t, s, ...) \
47 : : __BF_APPLY_ALL(t, s, _BF_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
48 : :
49 : : #define BF_BASE_10 10
50 : : #define BF_BASE_16 16
51 : :
52 : : #define _BF_ALIGNED(addr, mask) (((addr) & (mask)) == 0)
53 : : #define BF_ALIGNED_64(addr) _BF_ALIGNED(addr, 0x07)
54 : : #define BF_ALIGNED_32(addr) _BF_ALIGNED(addr, 0x03)
55 : : #define BF_ALIGNED_16(addr) _BF_ALIGNED(addr, 0x01)
56 : :
57 : : /**
58 : : * @brief Generate a bitflag from multiple values.
59 : : *
60 : : * Enumeration are used extensively to define related values. Thanks to
61 : : * enumeration's continuous values, they are used as array indexes to convert
62 : : * them into strings.
63 : : *
64 : : * However, they can sometimes be combined, leading to very wordy code, e.g.
65 : : * `1 << ENUM_VAL_1 | 1 << ENUM_VAL_5`.
66 : : *
67 : : * `BF_FLAGS` can be used to replace the wordy code with a simpler macro call,
68 : : * e.g. `BF_FLAGS(ENUL_VAL_1, ENUM_VAL_5)`. It will automatically create an
69 : : * integer with the enumeration values as a set bit index in the bitflag.
70 : : *
71 : : * @return Bitflag for variadic values.
72 : : */
73 : : #define BF_FLAGS(...) _BF_APPLY_ALL(BF_FLAG, |, __VA_ARGS__)
74 : :
75 : : /**
76 : : * @brief Shift 1 by `n` to create a flag.
77 : : *
78 : : * @see `BF_FLAGS`
79 : : *
80 : : * @return `1ULL << n` to be used as a flag.
81 : : */
82 : : #define BF_FLAG(n) (1ULL << (n))
83 : :
84 : : /**
85 : : * @brief Generate a bitmask covering all valid flags below `max_value`.
86 : : *
87 : : * @return Mask with bits 0 through max_value-1 set.
88 : : */
89 : : #define BF_FLAGS_MASK(max_value) ((1ULL << (max_value)) - 1)
90 : :
91 : : #define bf_packed __attribute__((packed))
92 : : #define bf_aligned(x) __attribute__((aligned(x)))
93 : : #define bf_unused __attribute__((unused))
94 : :
95 : : #define BF_STR(s) _BF_STR(s)
96 : : #define _BF_STR(s) #s
97 : :
98 : : /**
99 : : * @brief Generate a build error if an enumeration to string mapping array
100 : : * contains fewer entries than members in the enumeration.
101 : : *
102 : : * @param array Array containing the mapping between the enumeration values and
103 : : * ther string representation.
104 : : * @param n_values Number of values in the enumeration, usually the
105 : : * `_BF_$NAME_MAX` enumeration value.
106 : : */
107 : : #define static_assert_enum_mapping(array, n_values) \
108 : : static_assert(ARRAY_SIZE(array) == (n_values), \
109 : : "missing entries in " BF_STR(array) " array");
110 : :
111 : : /**
112 : : * Set @p ptr to NULL and return its previous value.
113 : : *
114 : : * Inspired from systemd's TAKE_PTR() macro, which is itself inspired from
115 : : * Rust's Option::take() method:
116 : : * https://doc.rust-lang.org/std/option/enum.Option.html#method.take
117 : : *
118 : : * @param var Variable to return the value of.
119 : : * @param type Type of @p var.
120 : : * @param nullvalue Value to set @p var to.
121 : : * @return Value of @p var before it was set to @p nullvalue.
122 : : */
123 : : #define TAKE_GENERIC(var, type, nullvalue) \
124 : : ({ \
125 : : /* NOLINTBEGIN: do not enclose 'type' in parentheses */ \
126 : : type *_pvar_ = &(var); \
127 : : type _var_ = *_pvar_; \
128 : : type _nullvalue_ = nullvalue; \
129 : : /* NOLINTEND */ \
130 : : *_pvar_ = _nullvalue_; \
131 : : _var_; \
132 : : })
133 : :
134 : : #define TAKE_PTR_TYPE(ptr, type) TAKE_GENERIC(ptr, type, NULL)
135 : : #define TAKE_PTR(ptr) TAKE_PTR_TYPE(ptr, typeof(ptr))
136 : : #define TAKE_STRUCT_TYPE(s, type) TAKE_GENERIC(s, type, {})
137 : : #define TAKE_STRUCT(s) TAKE_STRUCT_TYPE(s, typeof(s))
138 : : #define TAKE_FD(fd) TAKE_GENERIC(fd, int, -1)
139 : :
140 : : /**
141 : : * Get the number of element in an array.
142 : : *
143 : : * @param x The array.
144 : : * @return size_t The number of elements in the array.
145 : : */
146 : : #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
147 : :
148 : : #define _cleanup_free_ __attribute__((__cleanup__(freep)))
149 : : #define _cleanup_close_ __attribute__((__cleanup__(closep)))
150 : :
151 : : /**
152 : : * Return a string describing the given error code.
153 : : *
154 : : * This function must be used over strerror(), which is marked at mt-unsafe.
155 : : *
156 : : * @param v Error code, can be positive or negative.
157 : : */
158 : : #define bf_strerror(v) strerrordesc_np(abs(v))
159 : :
160 : : /**
161 : : * Swap two values.
162 : : *
163 : : * @param a First value to swap.
164 : : * @param b Second value to swap.
165 : : */
166 : : #define bf_swap(a, b) \
167 : : do { \
168 : : typeof(a) __a = (a); \
169 : : (a) = (b); \
170 : : (b) = __a; \
171 : : } while (0)
172 : :
173 : : #define bf_min(a, b) \
174 : : ({ \
175 : : __typeof__(a) _a = (a); \
176 : : __typeof__(b) _b = (b); \
177 : : _a < _b ? _a : _b; \
178 : : })
179 : :
180 : : #define bf_max(a, b) \
181 : : ({ \
182 : : __typeof__(a) _a = (a); \
183 : : __typeof__(b) _b = (b); \
184 : : _a > _b ? _a : _b; \
185 : : })
186 : :
187 : : /**
188 : : * @brief Strip whitespace from the beginning of a string.
189 : : *
190 : : * @param str String to trim. Can't be NULL.
191 : : * @return Trimmed version of `str`, as a pointer to a character of `str`.
192 : : */
193 : : char *bf_ltrim(char *str);
194 : :
195 : : /**
196 : : * @brief Strip whitespace from the end of a string.
197 : : *
198 : : * `str` will be modified to insert `\0` after the last non-whitespace
199 : : * character.
200 : : * @param str String to trim. Can't be NULL.
201 : : * @return Trimmed version of `str`, as a pointer to a character of `str`.
202 : : */
203 : : char *bf_rtrim(char *str);
204 : :
205 : : /**
206 : : * @brief Strip whitespace from the beginning and the end of a string.
207 : : *
208 : : * `str` will be modified to insert `\0` after the last non-whitespace
209 : : * character.
210 : : *
211 : : * @param str String to trim. Can't be NULL.
212 : : * @return Trimmed version of `str`, as a pointer to a character of `str`.
213 : : */
214 : : char *bf_trim(char *str);
215 : :
216 : : /**
217 : : * Free a pointer and set it to NULL.
218 : : *
219 : : * @param ptr Pointer to free.
220 : : */
221 : 3 : static inline void freep(void *ptr)
222 : : {
223 [ + + ]: 209785 : free(*(void **)ptr);
224 : 135988 : *(void **)ptr = NULL;
225 : 66825 : }
226 : :
227 : : /**
228 : : * @brief Close a file descriptor and set it to -1.
229 : : *
230 : : * `bpfilter` uses `-1` as neutral value for file descriptor, meaning it
231 : : * doesn't represent an open file yet. Once closed, a file descriptor should
232 : : * be reset to `-1`.
233 : : *
234 : : * `closep` is used to close a file descriptor. File descriptors with negative
235 : : * values are ignored (-1 is used for "unset", but will also ignore file
236 : : * descriptors containing negative errno values). Once closed, `*fd` is set
237 : : * to `-1`.
238 : : *
239 : : * If the call to `close` fails, a warning is printed, and the file descriptor
240 : : * is assumed to be already closed.
241 : : *
242 : : * @todo Ensure file descriptors are always initialized to -1, and closed using
243 : : * ``closep``.
244 : : *
245 : : * @param fd File descriptor to close. Can't be NULL.
246 : : */
247 : : void closep(int *fd);
248 : :
249 : : /**
250 : : * Duplicate a memory region.
251 : : *
252 : : * Allocate a new buffer of size @p len and copy @p src into it. Requirements
253 : : * applicable to @p src and @p len:
254 : : * - If @p src is NULL, @p len must be 0. In this case, NULL is returned.
255 : : * - If @p src is non-NULL, a new buffer of @p len bytes will be allocated to
256 : : * store the first @p len bytes of @p src. This new buffer is then returned.
257 : : *
258 : : * Unless NULL is returned, the new buffer is owned by the caller.
259 : : *
260 : : * @param src Source buffer to copy to @p dst.
261 : : * @param len Number of bytes to copy to @p dst.
262 : : * @return Pointer to the new buffer, or NULL on failure.
263 : : */
264 : 162 : static inline void *bf_memdup(const void *src, size_t len)
265 : : {
266 : : void *dst;
267 : :
268 [ - + ]: 162 : if (!src)
269 : : return NULL;
270 : :
271 : 162 : dst = malloc(len);
272 [ - + ]: 162 : if (!dst)
273 : : return NULL;
274 : :
275 : 162 : return memcpy(dst, src, len);
276 : : }
277 : :
278 : : /**
279 : : * Copy @p len bytes from @p src to @p dst.
280 : : *
281 : : * Allow for @p src to be NULL and/or @p len to be zero:
282 : : * - If @p src is NULL, @p len must be equal 0. @p dst is not modified.
283 : : * - If @p src is not NULL, @p len can be equal to 0, in which case @p dst is
284 : : * not modified.
285 : : *
286 : : * @param dst Destination buffer. Can't be NULL, and must be big enough to store
287 : : * @p len bytes from @p src.
288 : : * @param src Source buffer to copy to @p dst.
289 : : * @param len Number of bytes to copy to @p dst.
290 : : * @return Pointer to @p dst.
291 : : */
292 : 9562 : static inline void *bf_memcpy(void *dst, const void *src, size_t len)
293 : : {
294 : : assert(dst);
295 : : assert(src ? 1 : len == 0);
296 : :
297 [ + - ]: 9562 : if (!src || !len)
298 : : return dst;
299 : :
300 : 9562 : return memcpy(dst, src, len);
301 : : }
302 : :
303 : : /**
304 : : * Reallocate @p ptr into a new buffer of size @p size.
305 : : *
306 : : * Behaves similarly to realloc(), except that @p ptr is left unchanged if
307 : : * allocation fails, and an error is returned.
308 : : *
309 : : * @param ptr Memory buffer to grow. Can't be NULL.
310 : : * @param size New size of the memory buffer.
311 : : * @return 0 on success, or a negative errno value on failure.
312 : : */
313 : : int bf_realloc(void **ptr, size_t size);
314 : :
315 : : /**
316 : : * @brief Check if strings are equal.
317 : : *
318 : : * If any of `lhs`, `rhs` is NULL, the strings are considered inequal.
319 : : *
320 : : * @param lhs First string.
321 : : * @param rhs Second string.
322 : : * @return True if both strings are equal.
323 : : */
324 : 186132 : static inline bool bf_streq(const char *lhs, const char *rhs)
325 : : {
326 [ + + ]: 186132 : if (!lhs || !rhs)
327 : : return false;
328 : :
329 : 186111 : return strcmp(lhs, rhs) == 0;
330 : : }
331 : :
332 : : /**
333 : : * @brief Similar to `bf_streq`, except it compares only the first `n`
334 : : * characters.
335 : : *
336 : : * If any of `lhs`, `rhs` is NULL, the strings are considered inequal.
337 : : *
338 : : * @param lhs First string.
339 : : * @param rhs Second string.
340 : : * @param n Number of characters to compare.
341 : : * @return True if both strings are equal.
342 : : */
343 : 1668 : static inline bool bf_strneq(const char *lhs, const char *rhs, size_t n)
344 : : {
345 [ + - ]: 1668 : if (!lhs || !rhs)
346 : : return false;
347 : :
348 : 1668 : return strncmp(lhs, rhs, n) == 0;
349 : : }
350 : :
351 : : /**
352 : : * @brief Case insensitive alternative to `bf_streq`.
353 : : */
354 : 68621 : static inline bool bf_streq_i(const char *lhs, const char *rhs)
355 : : {
356 [ + + ]: 68621 : if (!lhs || !rhs)
357 : : return false;
358 : :
359 : 8117 : return strcasecmp(lhs, rhs) == 0;
360 : : }
361 : :
362 : : /**
363 : : * Copy a string to a buffer.
364 : : *
365 : : * @p src is copied to @p dst . If @p src is too long, at most @p len bytes are
366 : : * copied (including the termination character).
367 : : *
368 : : * @param dst Destination buffer. Can't be NULL.
369 : : * @param len Length of the destination buffer. The function will not copy more
370 : : * than @p len bytes to @p dst , including @c \0 . Can't be 0.
371 : : * @param src Soucre buffer to copy from. Will only be copied up to the
372 : : * termination character if it fits. Can't be NULL.
373 : : * @return 0 on success, or @c -E2BIG if @p src can't fit in @p dst .
374 : : */
375 : : int bf_strncpy(char *dst, size_t len, const char *src);
376 : :
377 : : /**
378 : : * Read the contents of a file into a buffer.
379 : : *
380 : : * @param path Path to the file to read. Can't be NULL.
381 : : * @param buf Pointer to a pointer to a buffer. The buffer will be allocated
382 : : * automatically. The caller is responsible to free it. If @ref
383 : : * bf_read_file fails, @p buf is left unchanged.
384 : : * @param len Length of the allocated buffer. Populated by the function.
385 : : * @return 0 on success, negative errno value on error.
386 : : */
387 : : int bf_read_file(const char *path, void **buf, size_t *len);
388 : :
389 : : /**
390 : : * Write the contents of a buffer into a file.
391 : : *
392 : : * @param path Path to the file to write. Can't be NULL.
393 : : * @param buf Buffer to write.
394 : : * @param len Number of bytes to write the to file.
395 : : * @return 0 on success, negative errno value on error.
396 : : */
397 : : int bf_write_file(const char *path, const void *buf, size_t len);
398 : :
399 : : /**
400 : : * @brief FNV-1a 64-bit offset basis (the initial hash value).
401 : : *
402 : : * @see https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function
403 : : * @return The initial hash value to pass to `bf_fnv1a()`.
404 : : */
405 : : uint64_t bf_fnv1a_init(void);
406 : :
407 : : /**
408 : : * @brief Compute a FNV-1a 64-bit hash.
409 : : *
410 : : * Pass `bf_fnv1a_init()` as `hash` for the initial call. To hash
411 : : * multiple fields, chain calls by passing the previous return value.
412 : : *
413 : : * @param data Data to hash. Can't be NULL.
414 : : * @param len Number of bytes to hash.
415 : : * @param hash Initial or chained hash value.
416 : : * @return Updated hash value.
417 : : */
418 : : uint64_t bf_fnv1a(const void *data, size_t len, uint64_t hash);
|