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