LCOV - code coverage report
Current view: top level - lib - system.h (source / functions) Coverage Total Hit
Test: elfutils-0.195 Lines: 65.7 % 70 46
Test Date: 2026-06-18 23:14:11 Functions: 88.9 % 9 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 36.5 % 74 27

             Branch data     Line data    Source code
       1                 :             : /* Declarations for common convenience functions.
       2                 :             :    Copyright (C) 2006-2011 Red Hat, Inc.
       3                 :             :    Copyright (C) 2022, 2026 Mark J. Wielaard <mark@klomp.org>
       4                 :             :    Copyright (C) 2023 Khem Raj.
       5                 :             :    This file is part of elfutils.
       6                 :             : 
       7                 :             :    This file is free software; you can redistribute it and/or modify
       8                 :             :    it under the terms of either
       9                 :             : 
      10                 :             :      * the GNU Lesser General Public License as published by the Free
      11                 :             :        Software Foundation; either version 3 of the License, or (at
      12                 :             :        your option) any later version
      13                 :             : 
      14                 :             :    or
      15                 :             : 
      16                 :             :      * the GNU General Public License as published by the Free
      17                 :             :        Software Foundation; either version 2 of the License, or (at
      18                 :             :        your option) any later version
      19                 :             : 
      20                 :             :    or both in parallel, as here.
      21                 :             : 
      22                 :             :    elfutils is distributed in the hope that it will be useful, but
      23                 :             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      24                 :             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      25                 :             :    General Public License for more details.
      26                 :             : 
      27                 :             :    You should have received copies of the GNU General Public License and
      28                 :             :    the GNU Lesser General Public License along with this program.  If
      29                 :             :    not, see <http://www.gnu.org/licenses/>.  */
      30                 :             : 
      31                 :             : #ifndef LIB_SYSTEM_H
      32                 :             : #define LIB_SYSTEM_H    1
      33                 :             : 
      34                 :             : /* Prevent double inclusion of config.h, config.h includes eu-config.h.  */
      35                 :             : #ifdef HAVE_CONFIG_H
      36                 :             : #ifndef EU_CONFIG_H
      37                 :             : # include <config.h>
      38                 :             : #endif
      39                 :             : #endif
      40                 :             : 
      41                 :             : #include <errno.h>
      42                 :             : #include <fcntl.h>
      43                 :             : #include <stdbool.h>
      44                 :             : #include <stddef.h>
      45                 :             : #include <stdint.h>
      46                 :             : #include <string.h>
      47                 :             : #include <stdarg.h>
      48                 :             : #include <stdlib.h>
      49                 :             : 
      50                 :             : /* System dependent headers */
      51                 :             : #include <byteswap.h>
      52                 :             : #include <endian.h>
      53                 :             : #include <sys/mman.h>
      54                 :             : #include <sys/param.h>
      55                 :             : #include <unistd.h>
      56                 :             : 
      57                 :             : #if defined(HAVE_SYS_RANDOM_H)
      58                 :             : #include <sys/random.h>
      59                 :             : #endif
      60                 :             : 
      61                 :             : #if defined(HAVE_ERROR_H)
      62                 :             : #include <error.h>
      63                 :             : #elif defined(HAVE_ERR_H)
      64                 :             : extern int error_message_count;
      65                 :             : void error(int status, int errnum, const char *format, ...);
      66                 :             : #else
      67                 :             : #error "err.h or error.h must be available"
      68                 :             : #endif
      69                 :             : 
      70                 :             : /* error (EXIT_FAILURE, ...) should be noreturn but on some systems it
      71                 :             :    isn't.  This may cause warnings about code that should not be reachable.
      72                 :             :    So have an explicit error_exit wrapper that is noreturn (because it
      73                 :             :    calls exit explicitly).  */
      74                 :             : #define error_exit(errnum,...) do { \
      75                 :             :     error (EXIT_FAILURE,errnum,__VA_ARGS__); \
      76                 :             :     exit (EXIT_FAILURE); \
      77                 :             :   } while (0)
      78                 :             : 
      79                 :             : #if BYTE_ORDER == LITTLE_ENDIAN
      80                 :             : # define LE32(n)        (n)
      81                 :             : # define LE64(n)        (n)
      82                 :             : # define BE32(n)        bswap_32 (n)
      83                 :             : # define BE64(n)        bswap_64 (n)
      84                 :             : #elif BYTE_ORDER == BIG_ENDIAN
      85                 :             : # define BE32(n)        (n)
      86                 :             : # define BE64(n)        (n)
      87                 :             : # define LE32(n)        bswap_32 (n)
      88                 :             : # define LE64(n)        bswap_64 (n)
      89                 :             : #else
      90                 :             : # error "Unknown byte order"
      91                 :             : #endif
      92                 :             : 
      93                 :             : #ifndef MAX
      94                 :             : #define MAX(m, n) ((m) < (n) ? (n) : (m))
      95                 :             : #endif
      96                 :             : 
      97                 :             : #ifndef MIN
      98                 :             : #define MIN(m, n) ((m) < (n) ? (m) : (n))
      99                 :             : #endif
     100                 :             : 
     101                 :             : #if !HAVE_DECL_POWEROF2
     102                 :             : #define powerof2(x) (((x) & ((x) - 1)) == 0)
     103                 :             : #endif
     104                 :             : 
     105                 :             : #if !HAVE_DECL_MEMPCPY
     106                 :             : #define mempcpy(dest, src, n) \
     107                 :             :     ((void *) ((char *) memcpy (dest, src, n) + (size_t) n))
     108                 :             : #endif
     109                 :             : 
     110                 :             : #if !HAVE_DECL_REALLOCARRAY
     111                 :             : static inline void *
     112                 :             : reallocarray (void *ptr, size_t nmemb, size_t size)
     113                 :             : {
     114                 :             :   if (size > 0 && nmemb > SIZE_MAX / size)
     115                 :             :     {
     116                 :             :       errno = ENOMEM;
     117                 :             :       return NULL;
     118                 :             :     }
     119                 :             :   return realloc (ptr, nmemb * size);
     120                 :             : }
     121                 :             : #endif
     122                 :             : 
     123                 :             : /* Return TRUE if the start of STR matches PREFIX, FALSE otherwise.  */
     124                 :             : 
     125                 :             : static inline int
     126                 :    13933225 : startswith (const char *str, const char *prefix)
     127                 :             : {
     128                 :    13933225 :   return strncmp (str, prefix, strlen (prefix)) == 0;
     129                 :             : }
     130                 :             : 
     131                 :             : /* Return TRUE if STR[FROM] is a valid string with a zero terminator
     132                 :             :    at or before STR[TO - 1].  Note FROM is an index into the STR
     133                 :             :    array, while TO is the maximum size of the STR array.  This
     134                 :             :    function returns FALSE when TO is zero or FROM >= TO.  */
     135                 :             : static inline bool
     136                 :    12113960 : validate_str (const char *str, size_t from, size_t to)
     137                 :             : {
     138                 :             : #if HAVE_DECL_MEMRCHR
     139                 :             :   // Check end first, which is likely a zero terminator,
     140                 :             :   // to prevent function call
     141                 :    12113960 :   return (to > 0
     142   [ +  -  -  + ]:    12113960 :           && (str[to - 1] == '\0'
     143         [ #  # ]:           0 :               || (to > from
     144         [ #  # ]:           0 :                   && memrchr (&str[from], '\0', to - from - 1) != NULL)));
     145                 :             : #else
     146                 :             :   do {
     147                 :             :     if (to <= from)
     148                 :             :       return false;
     149                 :             : 
     150                 :             :     to--;
     151                 :             :   } while (str[to]);
     152                 :             : 
     153                 :             :   return true;
     154                 :             : #endif
     155                 :             : }
     156                 :             : 
     157                 :             : /* A special gettext function we use if the strings are too short.  */
     158                 :             : #define sgettext(Str) \
     159                 :             :   ({ const char *__res = strrchr (_(Str), '|');                       \
     160                 :             :      __res ? __res + 1 : Str; })
     161                 :             : 
     162                 :             : #define gettext_noop(Str) Str
     163                 :             : 
     164                 :             : #ifndef TEMP_FAILURE_RETRY
     165                 :             : #define TEMP_FAILURE_RETRY(expression) \
     166                 :             :   ({ ssize_t __res; \
     167                 :             :      do \
     168                 :             :        __res = expression; \
     169                 :             :      while (__res == -1 && errno == EINTR); \
     170                 :             :      __res; })
     171                 :             : #endif
     172                 :             : 
     173                 :             : #ifndef ACCESSPERMS
     174                 :             : #define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) /* 0777 */
     175                 :             : #endif
     176                 :             : 
     177                 :             : #ifndef ALLPERMS
     178                 :             : #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) /* 07777 */
     179                 :             : #endif
     180                 :             : 
     181                 :             : #ifndef DEFFILEMODE
     182                 :             : #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)/* 0666 */
     183                 :             : #endif
     184                 :             : 
     185                 :             : static inline ssize_t __attribute__ ((unused))
     186                 :     2126402 : pwrite_retry (int fd, const void *buf, size_t len, off_t off)
     187                 :             : {
     188                 :     2126402 :   ssize_t recvd = 0;
     189                 :             : 
     190                 :     2126402 :   do
     191                 :             :     {
     192   [ -  +  -  - ]:     2126402 :       ssize_t ret = TEMP_FAILURE_RETRY (pwrite (fd, ((char *)buf) + recvd, len - recvd,
     193                 :             :                                                 off + recvd));
     194         [ +  + ]:     2126402 :       if (ret <= 0)
     195         [ +  - ]:         506 :         return ret < 0 ? ret : recvd;
     196                 :             : 
     197                 :     2125896 :       recvd += ret;
     198                 :             :     }
     199         [ -  + ]:     2125896 :   while ((size_t) recvd < len);
     200                 :             : 
     201                 :             :   return recvd;
     202                 :             : }
     203                 :             : 
     204                 :             : static inline ssize_t __attribute__ ((unused))
     205                 :         310 : write_retry (int fd, const void *buf, size_t len)
     206                 :             : {
     207                 :         310 :   ssize_t recvd = 0;
     208                 :             : 
     209                 :         310 :   do
     210                 :             :     {
     211   [ -  +  -  - ]:         310 :       ssize_t ret = TEMP_FAILURE_RETRY (write (fd, ((char *)buf) + recvd, len - recvd));
     212         [ -  + ]:         310 :       if (ret <= 0)
     213         [ #  # ]:           0 :         return ret < 0 ? ret : recvd;
     214                 :             : 
     215                 :         310 :       recvd += ret;
     216                 :             :     }
     217         [ -  + ]:         310 :   while ((size_t) recvd < len);
     218                 :             : 
     219                 :             :   return recvd;
     220                 :             : }
     221                 :             : 
     222                 :             : static inline ssize_t __attribute__ ((unused))
     223                 :     1644472 : pread_retry (int fd, void *buf, size_t len, off_t off)
     224                 :             : {
     225                 :     1644472 :   ssize_t recvd = 0;
     226                 :             : 
     227                 :     1654498 :   do
     228                 :             :     {
     229   [ +  +  -  +  :     3308996 :       ssize_t ret = TEMP_FAILURE_RETRY (pread (fd, ((char *)buf) + recvd, len - recvd,
                   -  - ]
     230                 :             :                                                off + recvd));
     231         [ +  + ]:     1654498 :       if (ret <= 0)
     232         [ +  - ]:       10068 :         return ret < 0 ? ret : recvd;
     233                 :             : 
     234                 :     1644430 :       recvd += ret;
     235                 :             :     }
     236         [ +  + ]:     1644430 :   while ((size_t) recvd < len);
     237                 :             : 
     238                 :             :   return recvd;
     239                 :             : }
     240                 :             : 
     241                 :             : static inline ssize_t __attribute__ ((unused))
     242                 :           0 : read_retry (int fd, void *buf, size_t len)
     243                 :             : {
     244                 :           0 :   ssize_t recvd = 0;
     245                 :             : 
     246                 :           0 :   do
     247                 :             :     {
     248   [ #  #  #  #  :           0 :       ssize_t ret = TEMP_FAILURE_RETRY (read (fd, ((char *)buf) + recvd,
                   #  # ]
     249                 :             :                                               len - recvd));
     250         [ #  # ]:           0 :       if (ret <= 0)
     251         [ #  # ]:           0 :         return ret < 0 ? ret : recvd;
     252                 :             : 
     253                 :           0 :       recvd += ret;
     254                 :             :     }
     255         [ #  # ]:           0 :   while ((size_t) recvd < len);
     256                 :             : 
     257                 :             :   return recvd;
     258                 :             : }
     259                 :             : 
     260                 :             : /* The demangler from libstdc++.  */
     261                 :             : extern char *__cxa_demangle (const char *mangled_name, char *output_buffer,
     262                 :             :                              size_t *length, int *status);
     263                 :             : 
     264                 :             : /* A static assertion.  This will cause a compile-time error if EXPR,
     265                 :             :    which must be a compile-time constant, is false.  */
     266                 :             : 
     267                 :             : #define eu_static_assert(expr)                                          \
     268                 :             :   extern int never_defined_just_used_for_checking[(expr) ? 1 : -1]      \
     269                 :             :     __attribute__ ((unused))
     270                 :             : 
     271                 :             : /* We really want a basename implementation that doesn't modify the
     272                 :             :    input argument.  Normally you get that from string.h with _GNU_SOURCE
     273                 :             :    define.  But some libc implementations don't define it and other
     274                 :             :    define it, but provide an implementation that still modifies the
     275                 :             :    argument.  So define our own and poison a bare basename symbol.  */
     276                 :             : static inline const char *
     277                 :       21586 : xbasename(const char *s)
     278                 :             : {
     279                 :       21586 :   const char *p = strrchr(s, '/');
     280         [ +  + ]:       21586 :   return p ? p+1 : s;
     281                 :             : }
     282                 :             : #pragma GCC poison basename
     283                 :             : 
     284                 :             : /* Get a random uint64_t.  Returns zero on success, minus one on failure.  */
     285                 :             : static inline int
     286                 :          92 : xrandom64 (uint64_t *r)
     287                 :             : {
     288                 :             :   /* Prefer getentropy if it is available, fallback to getrandom, if
     289                 :             :      both are missing, or if they fail try reading from /dev/urandom.  */
     290                 :             : #if HAVE_DECL_GETENTROPY
     291         [ +  - ]:          92 :   if (getentropy (r, sizeof (*r)) == 0)
     292                 :             :     return 0;
     293                 :             : #elif HAVE_DECL_GETRANDOM
     294                 :             :   if (TEMP_FAILURE_RETRY (getrandom (r, sizeof (*r), 0)) == sizeof (*r))
     295                 :             :     return 0;
     296                 :             : #endif
     297                 :           0 :   int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
     298         [ #  # ]:           0 :   if (fd < 0)
     299                 :             :     return -1;
     300         [ #  # ]:           0 :   if (read_retry (fd, r, sizeof (uint64_t)) == sizeof (uint64_t))
     301                 :             :     {
     302                 :           0 :       close (fd);
     303                 :           0 :       return 0;
     304                 :             :     }
     305                 :           0 :   int save_errno = errno;
     306                 :           0 :   close (fd);
     307                 :           0 :   errno = save_errno;
     308                 :             :   /* We could try some pseudo-random thing with getpid and
     309                 :             :      clock_gettime.  But if even getting something from /dev/urandom
     310                 :             :      fails it seems we tried hard enough already.  */
     311                 :           0 :   return -1;
     312                 :             : }
     313                 :             : 
     314                 :             : /* There is no mkstempat needed for creating a temp file in a specific
     315                 :             :    directory. Needed e.g. in combination with renameat to atomicly
     316                 :             :    replace a file. So define one ourselves. Like mkstemp the template
     317                 :             :    must end in "XXXXXX", which are replaced by an unique filename
     318                 :             :    suffix. The file is created with user read/write permissions only
     319                 :             :    in the given dirfd using openat.
     320                 :             :    https://sourceware.org/bugzilla/show_bug.cgi?id=19866 */
     321                 :             : static inline int
     322                 :          92 : xmkstempat (int dirfd, char *templ)
     323                 :             : {
     324                 :             :   /* Only use these 64 chars.  */
     325                 :          92 :   const char chars[] =
     326                 :             :     "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
     327                 :             : 
     328                 :             :   /* Must end in 6X.  */
     329                 :          92 :   size_t l = strlen (templ);
     330   [ +  -  -  + ]:          92 :   if (l < 6 || memcmp (templ + l - 6, "XXXXXX", 6) != 0)
     331                 :             :     {
     332                 :           0 :       errno = EINVAL;
     333                 :           0 :       return -1;
     334                 :             :     }
     335                 :             : 
     336                 :             :   int tries = 128; /* Just fail with EEXIST if 128 tries wasn't enough.  */
     337                 :          92 :   do
     338                 :             :     {
     339                 :          92 :       uint64_t r; /* We need at least 64^6 == 2^36  */
     340         [ +  - ]:          92 :       if (xrandom64 (&r) != 0)
     341                 :          92 :         return -1;
     342                 :             : 
     343                 :             :       /* Random chars for the template.  */
     344         [ +  + ]:         644 :       for (int i = 0; i < 6; i++)
     345                 :             :         {
     346                 :         552 :           templ[l - 6 + i] = chars[r % 64];
     347                 :         552 :           r /= 64;
     348                 :             :         }
     349                 :             : 
     350                 :             :       /* Must be able to open exclusively.  */
     351                 :          92 :       int fd = openat (dirfd, templ,
     352                 :             :                        O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC,
     353                 :             :                        S_IRUSR | S_IWUSR);
     354         [ -  + ]:          92 :       if (fd >= 0)
     355                 :             :         return fd;
     356                 :             : 
     357                 :           0 :       tries--;
     358                 :             :     }
     359   [ #  #  #  # ]:           0 :   while (tries > 0 && errno == EEXIST);
     360                 :             : 
     361                 :             :   return -1;
     362                 :             : }
     363                 :             : 
     364                 :             : #endif /* system.h */
        

Generated by: LCOV version 2.0-1