LCOV - code coverage report
Current view: top level - core - helper.h (source / functions) Coverage Total Hit
Test: lcov.out Lines: 75.0 % 20 15
Test Date: 2025-08-19 17:27:08 Functions: 80.0 % 5 4

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

Generated by: LCOV version 2.0-1