LCOV - code coverage report
Current view: top level - lib - missing.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 36 56 64.3 %
Date: 2023-04-18 16:19:03 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /*
       2             :  * lwan - web server
       3             :  * Copyright (c) 2012 L. A. F. Pereira <l@tia.mat.br>
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU General Public License
       7             :  * as published by the Free Software Foundation; either version 2
       8             :  * of the License, or any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
      18             :  * USA.
      19             :  */
      20             : 
      21             : #include <errno.h>
      22             : #include <fcntl.h>
      23             : #include <libproc.h>
      24             : #include <limits.h>
      25             : #include <linux/capability.h>
      26             : #include <pthread.h>
      27             : #include <stdint.h>
      28             : #include <stdlib.h>
      29             : #include <string.h>
      30             : #include <sys/epoll.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/types.h>
      33             : #include <sys/vfs.h>
      34             : #include <unistd.h>
      35             : 
      36             : #include "lwan.h"
      37             : 
      38             : #ifndef LWAN_HAVE_MEMPCPY
      39             : void *mempcpy(void *dest, const void *src, size_t len)
      40             : {
      41             :     char *p = memcpy(dest, src, len);
      42             :     return p + len;
      43             : }
      44             : #endif
      45             : 
      46             : #ifndef LWAN_HAVE_MEMRCHR
      47             : void *memrchr(const void *s, int c, size_t n)
      48             : {
      49             :     const char *end = (const char *)s + n + 1;
      50             :     const char *prev = NULL;
      51             : 
      52             :     for (const char *cur = s; cur <= end; prev = cur++) {
      53             :         cur = (const char *)memchr(cur, c, (size_t)(end - cur));
      54             :         if (!cur)
      55             :             break;
      56             :     }
      57             : 
      58             :     return (void *)prev;
      59             : }
      60             : #endif
      61             : 
      62             : #ifndef LWAN_HAVE_PIPE2
      63             : int pipe2(int pipefd[2], int flags)
      64             : {
      65             :     int r;
      66             : 
      67             :     r = pipe(pipefd);
      68             :     if (r < 0)
      69             :         return r;
      70             : 
      71             :     if (fcntl(pipefd[0], F_SETFL, flags) < 0 ||
      72             :         fcntl(pipefd[1], F_SETFL, flags) < 0) {
      73             :         int saved_errno = errno;
      74             : 
      75             :         close(pipefd[0]);
      76             :         close(pipefd[1]);
      77             : 
      78             :         errno = saved_errno;
      79             :         return -1;
      80             :     }
      81             : 
      82             :     return 0;
      83             : }
      84             : #endif
      85             : 
      86             : #ifndef LWAN_HAVE_ACCEPT4
      87             : int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags)
      88             : {
      89             :     int fd = accept(sock, addr, addrlen);
      90             :     int newflags = 0;
      91             : 
      92             :     if (fd < 0)
      93             :         return fd;
      94             : 
      95             :     if (flags & SOCK_NONBLOCK) {
      96             :         newflags |= O_NONBLOCK;
      97             :         flags &= ~SOCK_NONBLOCK;
      98             :     }
      99             :     if (flags & SOCK_CLOEXEC) {
     100             :         newflags |= O_CLOEXEC;
     101             :         flags &= ~SOCK_CLOEXEC;
     102             :     }
     103             :     if (flags) {
     104             :         errno = -EINVAL;
     105             :         return -1;
     106             :     }
     107             : 
     108             :     if (fcntl(fd, F_SETFL, newflags) < 0) {
     109             :         int saved_errno = errno;
     110             : 
     111             :         close(fd);
     112             : 
     113             :         errno = saved_errno;
     114             :         return -1;
     115             :     }
     116             : 
     117             :     return fd;
     118             : }
     119             : #endif
     120             : 
     121             : #ifndef LWAN_HAVE_CLOCK_GETTIME
     122             : int clock_gettime(clockid_t clk_id, struct timespec *ts)
     123             : {
     124             :     switch (clk_id) {
     125             :     case CLOCK_MONOTONIC:
     126             :     case CLOCK_MONOTONIC_COARSE:
     127             :         /* FIXME: time() isn't monotonic */
     128             :         ts->tv_sec = time(NULL);
     129             :         ts->tv_nsec = 0;
     130             :         return 0;
     131             :     }
     132             : 
     133             :     errno = EINVAL;
     134             :     return -1;
     135             : }
     136             : #endif
     137             : 
     138             : #if !defined(LWAN_HAVE_EPOLL) && defined(LWAN_HAVE_KQUEUE)
     139             : #include <sys/event.h>
     140             : #include <sys/time.h>
     141             : #include <sys/types.h>
     142             : 
     143             : #include "hash.h"
     144             : 
     145             : int epoll_create1(int flags __attribute__((unused))) { return kqueue(); }
     146             : 
     147             : static int epoll_no_event_marker;
     148             : 
     149             : int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
     150             : {
     151             :     struct kevent ev;
     152             : 
     153             :     switch (op) {
     154             :     case EPOLL_CTL_ADD:
     155             :     case EPOLL_CTL_MOD: {
     156             :         int events = 0;
     157             :         void *udata = event->data.ptr;
     158             :         int flags = EV_ADD;
     159             : 
     160             :         if (event->events & EPOLLIN) {
     161             :             events = EVFILT_READ;
     162             :         } else if (event->events & EPOLLOUT) {
     163             :             events = EVFILT_WRITE;
     164             :         } else {
     165             :             events = EVFILT_WRITE;
     166             :             udata = &epoll_no_event_marker;
     167             :         }
     168             : 
     169             :         if (event->events & EPOLLONESHOT)
     170             :             flags |= EV_ONESHOT;
     171             :         if (event->events & EPOLLET)
     172             :             flags |= EV_CLEAR;
     173             : 
     174             :         flags |= EV_ERROR; /* EPOLLERR is always set. */
     175             :         flags |= EV_EOF;   /* EPOLLHUP is always set. */
     176             : 
     177             :         EV_SET(&ev, fd, events, flags, 0, 0, udata);
     178             :         break;
     179             :     }
     180             : 
     181             :     case EPOLL_CTL_DEL:
     182             :         EV_SET(&ev, fd, 0, EV_DELETE, 0, 0, 0);
     183             :         break;
     184             : 
     185             :     default:
     186             :         errno = EINVAL;
     187             :         return -1;
     188             :     }
     189             : 
     190             :     return kevent(epfd, &ev, 1, NULL, 0, NULL);
     191             : }
     192             : 
     193             : static struct timespec *to_timespec(struct timespec *t, int ms)
     194             : {
     195             :     if (ms < 0)
     196             :         return NULL;
     197             : 
     198             :     t->tv_sec = ms / 1000;
     199             :     t->tv_nsec = (ms % 1000) * 1000000;
     200             : 
     201             :     return t;
     202             : }
     203             : 
     204             : int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
     205             : {
     206             :     struct epoll_event *ev = events;
     207             :     struct kevent evs[maxevents];
     208             :     struct timespec tmspec;
     209             :     struct hash *coalesce;
     210             :     int i, r;
     211             : 
     212             :     coalesce = hash_int_new(NULL, NULL);
     213             :     if (UNLIKELY(!coalesce))
     214             :         return -1;
     215             : 
     216             :     r = kevent(epfd, NULL, 0, evs, maxevents, to_timespec(&tmspec, timeout));
     217             :     if (UNLIKELY(r < 0)) {
     218             :         hash_free(coalesce);
     219             :         return -1;
     220             :     }
     221             : 
     222             :     for (i = 0; i < r; i++) {
     223             :         struct kevent *kev = &evs[i];
     224             :         uint32_t mask = (uint32_t)(uintptr_t)hash_find(
     225             :             coalesce, (void *)(intptr_t)evs[i].ident);
     226             : 
     227             :         if (kev->flags & EV_ERROR)
     228             :             mask |= EPOLLERR;
     229             :         if (kev->flags & EV_EOF)
     230             :             mask |= EPOLLRDHUP;
     231             : 
     232             :         if (kev->filter == EVFILT_READ)
     233             :             mask |= EPOLLIN;
     234             :         else if (kev->filter == EVFILT_WRITE && evs[i].udata != &epoll_no_event_marker)
     235             :             mask |= EPOLLOUT;
     236             : 
     237             :         hash_add(coalesce, (void *)(intptr_t)evs[i].ident,
     238             :                  (void *)(uintptr_t)mask);
     239             :     }
     240             : 
     241             :     for (i = 0; i < r; i++) {
     242             :         void *maskptr;
     243             : 
     244             :         maskptr = hash_find(coalesce, (void *)(intptr_t)evs[i].ident);
     245             :         if (maskptr) {
     246             :             struct kevent *kev = &evs[i];
     247             : 
     248             :             if (kev->udata == &epoll_no_event_marker)
     249             :                 continue;
     250             : 
     251             :             ev->data.ptr = kev->udata;
     252             :             ev->events = (uint32_t)(uintptr_t)maskptr;
     253             :             ev++;
     254             :         }
     255             :     }
     256             : 
     257             :     hash_free(coalesce);
     258             :     return (int)(intptr_t)(ev - events);
     259             : }
     260             : #elif !defined(LWAN_HAVE_EPOLL)
     261             : #error epoll() not implemented for this platform
     262             : #endif
     263             : 
     264             : #if defined(__linux__) || defined(__CYGWIN__)
     265             : #if defined(LWAN_HAVE_GETAUXVAL)
     266             : #include <sys/auxv.h>
     267             : #endif
     268             : 
     269         460 : int proc_pidpath(pid_t pid, void *buffer, size_t buffersize)
     270             : {
     271             :     ssize_t path_len;
     272             : 
     273         460 :     if (getpid() != pid) {
     274           0 :         errno = EACCES;
     275             : 
     276           0 :         return -1;
     277             :     }
     278             : 
     279             : #if defined(LWAN_HAVE_GETAUXVAL)
     280         460 :     const char *execfn = (const char *)getauxval(AT_EXECFN);
     281             : 
     282         460 :     if (execfn) {
     283         460 :         size_t len = strlen(execfn);
     284             : 
     285         460 :         if (len + 1 < buffersize) {
     286         460 :             memcpy(buffer, execfn, len + 1);
     287             : 
     288         460 :             return 0;
     289             :         }
     290             :     }
     291             : #endif
     292             : 
     293           0 :     path_len = readlink("/proc/self/exe", buffer, buffersize);
     294           0 :     if (path_len < 0)
     295           0 :         return -1;
     296             : 
     297           0 :     if (path_len < (ssize_t)buffersize) {
     298           0 :         ((char *)buffer)[path_len] = '\0';
     299             : 
     300           0 :         return 0;
     301             :     }
     302             : 
     303           0 :     errno = EOVERFLOW;
     304           0 :     return -1;
     305             : }
     306             : 
     307             : #elif defined(__FreeBSD__)
     308             : #include <sys/sysctl.h>
     309             : 
     310             : int proc_pidpath(pid_t pid, void *buffer, size_t buffersize)
     311             : {
     312             :     int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
     313             :     size_t path_len = buffersize;
     314             : 
     315             :     if (getpid() != pid) {
     316             :         errno = EACCES;
     317             : 
     318             :         return -1;
     319             :     }
     320             : 
     321             :     if (sysctl(mib, N_ELEMENTS(mib), buffer, &path_len, NULL, 0) < 0)
     322             :         return -1;
     323             : 
     324             :     return 0;
     325             : }
     326             : #elif defined(LWAN_HAVE_DLADDR) && !defined(__APPLE__)
     327             : #include <dlfcn.h>
     328             : 
     329             : int proc_pidpath(pid_t pid, void *buffer, size_t buffersize)
     330             : {
     331             :     Dl_info info;
     332             : 
     333             :     if (getpid() != pid) {
     334             :         errno = EACCES;
     335             :         return -1;
     336             :     }
     337             : 
     338             :     extern int main();
     339             :     if (dladdr(main, &info)) {
     340             :         if (!info.dli_fname)
     341             :             goto fallback;
     342             : 
     343             :         if (buffersize < PATH_MAX - 1)
     344             :             goto fallback;
     345             : 
     346             :         if (realpath(info.dli_fname, buffer))
     347             :             return 0;
     348             :     }
     349             : 
     350             : fallback:
     351             :     if (strlcpy(buffer, "lwan", buffersize) >= buffersize) {
     352             :         errno = ENOMEM;
     353             :         return -1;
     354             :     }
     355             : 
     356             :     return 0;
     357             : }
     358             : #elif !defined(__APPLE__)
     359             : #error proc_pidpath() not implemented for this architecture
     360             : #endif
     361             : 
     362             : #if defined(__linux__)
     363             : 
     364             : #if !defined(LWAN_HAVE_GETTID)
     365             : #include <sys/syscall.h>
     366             : 
     367             : pid_t gettid(void) { return (pid_t)syscall(SYS_gettid); }
     368             : #endif
     369             : 
     370             : #elif defined(__FreeBSD__)
     371             : #include <sys/thr.h>
     372             : 
     373             : pid_t gettid(void)
     374             : {
     375             :     long ret;
     376             : 
     377             :     thr_self(&ret);
     378             : 
     379             :     return (pid_t)ret;
     380             : }
     381             : #elif defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
     382             : #include <sys/syscall.h>
     383             : 
     384             : pid_t gettid(void) { return syscall(SYS_thread_selfid); }
     385             : #else
     386             : pid_t gettid(void) { return (pid_t)pthread_self(); }
     387             : #endif
     388             : 
     389             : #if defined(__APPLE__)
     390             : /* NOTE: Although saved UID/GID cannot be set using sysctl(), for the use
     391             :  * case in Lwan, it's possible to obtain the value and check if they're the
     392             :  * ones expected -- and abort if it's not.  Should be good enough for a
     393             :  * wrapper like this.  */
     394             : 
     395             : #include <sys/sysctl.h>
     396             : 
     397             : static int get_current_proc_info(struct kinfo_proc *kp)
     398             : {
     399             :     int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
     400             :     size_t len = sizeof(*kp);
     401             : 
     402             :     return sysctl(mib, N_ELEMENTS(mib), kp, &len, NULL, 0);
     403             : }
     404             : 
     405             : int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
     406             : {
     407             :     struct kinfo_proc kp;
     408             : 
     409             :     if (!get_current_proc_info(&kp)) {
     410             :         *ruid = getuid();
     411             :         *euid = geteuid();
     412             :         *suid = kp.kp_eproc.e_pcred.p_svuid;
     413             : 
     414             :         return 0;
     415             :     }
     416             : 
     417             :     return -1;
     418             : }
     419             : 
     420             : int setresuid(uid_t ruid, uid_t euid, uid_t suid __attribute__((unused)))
     421             : {
     422             :     return setreuid(ruid, euid);
     423             : }
     424             : 
     425             : int setresgid(gid_t rgid, gid_t egid, gid_t sgid __attribute__((unused)))
     426             : {
     427             :     return setregid(rgid, egid);
     428             : }
     429             : 
     430             : int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
     431             : {
     432             :     struct kinfo_proc kp;
     433             : 
     434             :     if (!get_current_proc_info(&kp)) {
     435             :         *rgid = getgid();
     436             :         *egid = getegid();
     437             :         *sgid = kp.kp_eproc.e_pcred.p_svgid;
     438             : 
     439             :         return 0;
     440             :     }
     441             : 
     442             :     return -1;
     443             : }
     444             : #endif
     445             : 
     446             : #if !defined(LWAN_HAVE_MKOSTEMP)
     447             : int mkostemp(char *tmpl, int flags)
     448             : {
     449             :     int fd, fl;
     450             : 
     451             :     fd = mkstemp(tmpl);
     452             :     if (fd < 0)
     453             :         return -1;
     454             : 
     455             :     fl = fcntl(fd, F_GETFD);
     456             :     if (fl < 0)
     457             :         goto out;
     458             : 
     459             :     if (flags & O_CLOEXEC)
     460             :         fl |= FD_CLOEXEC;
     461             : 
     462             :     if (fcntl(fd, F_SETFD, fl) < 0)
     463             :         goto out;
     464             : 
     465             :     return fd;
     466             : 
     467             : out:
     468             :     close(fd);
     469             :     return -1;
     470             : }
     471             : #endif
     472             : 
     473             : #if !defined(LWAN_HAVE_REALLOCARRAY)
     474             : /*      $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $  */
     475             : /*
     476             :  * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
     477             :  *
     478             :  * Permission to use, copy, modify, and distribute this software for any
     479             :  * purpose with or without fee is hereby granted, provided that the above
     480             :  * copyright notice and this permission notice appear in all copies.
     481             :  *
     482             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     483             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     484             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     485             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     486             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     487             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     488             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     489             :  */
     490             : 
     491             : #include <errno.h>
     492             : #include <stdbool.h>
     493             : #include <stdint.h>
     494             : #include <stdlib.h>
     495             : #include <sys/types.h>
     496             : 
     497             : #if !defined(LWAN_HAVE_BUILTIN_MUL_OVERFLOW)
     498             : /*
     499             :  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
     500             :  * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
     501             :  */
     502             : #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
     503             : 
     504             : static inline bool umull_overflow(size_t a, size_t b, size_t *out)
     505             : {
     506             :     if ((a >= MUL_NO_OVERFLOW || b >= MUL_NO_OVERFLOW) && a > 0 &&
     507             :         SIZE_MAX / a < b)
     508             :         return true;
     509             :     *out = a * b;
     510             :     return false;
     511             : }
     512             : #else
     513             : #define umull_overflow __builtin_mul_overflow
     514             : #endif
     515             : 
     516             : void *reallocarray(void *optr, size_t nmemb, size_t size)
     517             : {
     518             :     size_t total_size;
     519             :     if (UNLIKELY(umull_overflow(nmemb, size, &total_size))) {
     520             :         errno = ENOMEM;
     521             :         return NULL;
     522             :     }
     523             :     if (UNLIKELY(total_size == 0)) {
     524             :         free(optr);
     525             :         return malloc(1);
     526             :     }
     527             :     return realloc(optr, total_size);
     528             : }
     529             : #endif /* LWAN_HAVE_REALLOCARRAY */
     530             : 
     531             : #if !defined(LWAN_HAVE_READAHEAD)
     532             : ssize_t readahead(int fd, off_t offset, size_t count)
     533             : {
     534             : #if defined(LWAN_HAVE_POSIX_FADVISE)
     535             :     return (ssize_t)posix_fadvise(fd, offset, (off_t)count,
     536             :                                   POSIX_FADV_WILLNEED);
     537             : #else
     538             :     (void)fd;
     539             :     (void)offset;
     540             :     (void)count;
     541             : 
     542             :     return 0;
     543             : #endif
     544             : }
     545             : #endif
     546             : 
     547             : #if !defined(LWAN_HAVE_GET_CURRENT_DIR_NAME)
     548             : #include <limits.h>
     549             : 
     550             : char *get_current_dir_name(void)
     551             : {
     552             :     char buffer[PATH_MAX];
     553             :     char *ret;
     554             : 
     555             :     ret = getcwd(buffer, sizeof(buffer));
     556             :     return strdup(ret ? ret : "/");
     557             : }
     558             : #endif
     559             : 
     560             : #ifndef __linux__
     561             : int capset(struct __user_cap_header_struct *header,
     562             :            struct __user_cap_data_struct *data)
     563             : {
     564             : #ifdef __OpenBSD__
     565             :     if (header->version != _LINUX_CAPABILITY_VERSION_1)
     566             :         return -EINVAL;
     567             :     if (header->pid != 0)
     568             :         return -EINVAL;
     569             :     if (data->effective == 0 && data->permitted == 0)
     570             :         return pledge("stdio rpath tmppath inet error", NULL);
     571             : #else
     572             :     (void)header;
     573             :     (void)data;
     574             : #endif
     575             : 
     576             :     return 0;
     577             : }
     578             : #endif
     579             : 
     580             : #if !defined(LWAN_HAVE_FWRITE_UNLOCKED)
     581             : size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *stream)
     582             : {
     583             :     size_t to_write = size * n;
     584             :     const size_t total_to_write = to_write;
     585             : 
     586             :     if (!to_write)
     587             :         return 0;
     588             : 
     589             :     fflush/* _unlocked? */(stream);
     590             : 
     591             :     while (to_write) {
     592             :         ssize_t r = write(fileno(stream), ptr, to_write);
     593             :         if (r < 0) {
     594             :             if (errno == EINTR)
     595             :                 continue;
     596             :             break;
     597             :         }
     598             : 
     599             :         to_write -= (size_t)r;
     600             :     }
     601             : 
     602             :     return (total_to_write - to_write) / size;
     603             : }
     604             : #endif
     605             : 
     606             : #if !defined(LWAN_HAVE_STATFS)
     607             : int statfs(const char *path, struct statfs *buf)
     608             : {
     609             :     (void)path;
     610             :     (void)buf;
     611             : 
     612             :     *errno = ENOSYS;
     613             :     return -1;
     614             : }
     615             : #endif
     616             : 
     617           0 : static int lwan_getentropy_fallback(void *buffer, size_t buffer_len)
     618             : {
     619             :     int fd;
     620             : 
     621           0 :     fd = open("/dev/urandom", O_CLOEXEC | O_RDONLY);
     622           0 :     if (fd < 0) {
     623           0 :         fd = open("/dev/random", O_CLOEXEC | O_RDONLY);
     624           0 :         if (fd < 0)
     625           0 :             return -1;
     626             :     }
     627           0 :     ssize_t total_read = read(fd, buffer, buffer_len);
     628           0 :     close(fd);
     629             : 
     630           0 :     return total_read == (ssize_t)buffer_len ? 0 : -1;
     631             : }
     632             : 
     633             : #if defined(SYS_getrandom)
     634         276 : long int lwan_getentropy(void *buffer, size_t buffer_len, int flags)
     635             : {
     636         276 :     long r = syscall(SYS_getrandom, buffer, buffer_len, flags);
     637             : 
     638         276 :     if (r < 0)
     639           0 :         return lwan_getentropy_fallback(buffer, buffer_len);
     640             : 
     641         276 :     return r;
     642             : }
     643             : #elif defined(LWAN_HAVE_GETENTROPY)
     644             : long int lwan_getentropy(void *buffer, size_t buffer_len, int flags)
     645             : {
     646             :     (void)flags;
     647             : 
     648             :     if (!getentropy(buffer, buffer_len))
     649             :         return buffer_len;
     650             : 
     651             :     return lwan_getentropy_fallback(buffer, buffer_len);
     652             : }
     653             : #else
     654             : long int lwan_getentropy(void *buffer, size_t buffer_len, int flags)
     655             : {
     656             :     (void)flags;
     657             :     return lwan_getentropy_fallback(buffer, buffer_len);
     658             : }
     659             : #endif
     660             : 
     661        2382 : static inline int isalpha_neutral(char c)
     662             : {
     663             :     /* Use this instead of isalpha() from ctype.h because they consider
     664             :      * the current locale.  This assumes CHAR_BIT == 8.  */
     665             :     static const unsigned char table[32] = {
     666             :         0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 7, 0, 0, 0, 0,
     667             :         0, 0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0, 0, 0, 0,
     668             :     };
     669        2382 :     unsigned char uc = (unsigned char)c;
     670        2382 :     return table[uc >> 3] & 1 << (uc & 7);
     671             : }
     672             : 
     673        1775 : bool strcaseequal_neutral(const char *a, const char *b)
     674             : {
     675        3754 :     for (;;) {
     676        5529 :         char ca = *a++;
     677        5529 :         char cb = *b++;
     678             : 
     679             :         /* See which bits are different in either character */
     680        5529 :         switch (ca ^ cb) {
     681        2099 :         case 0: /* ca and cb are the same: advance */
     682        2099 :             if (ca == '\0') {
     683             :                 /* If `ca` is 0 here, then cb must be 0 too, so we don't
     684             :                  * need to check both.  */
     685         364 :                 return true;
     686             :             }
     687        1735 :             continue;
     688        2019 :         case 32: /* Only 5th bit is set: advance if either are uppercase
     689             :                   * ASCII characters, but differ in case only */
     690             :             /* If either is an uppercase ASCII character, then move on */
     691        2019 :             if (isalpha_neutral(ca) || isalpha_neutral(cb))
     692        2019 :                 continue;
     693             :             /* Fallthrough */
     694             :         default:
     695        1411 :             return false;
     696             :         }
     697             :     }
     698             : }
     699             : 
     700             : #ifndef NDEBUG
     701          92 : __attribute__((constructor)) static void test_strcaseequal_neutral(void)
     702             : {
     703          92 :     assert(strcaseequal_neutral("LWAN", "lwan") == true);
     704          92 :     assert(strcaseequal_neutral("LwAn", "lWaN") == true);
     705          92 :     assert(strcaseequal_neutral("SomE-HeaDer", "some-header") == true);
     706             : 
     707          92 :     assert(strcaseequal_neutral("SomE-HeaDeP", "some-header") == false);
     708          92 :     assert(strcaseequal_neutral("LwAN", "lwam") == false);
     709          92 :     assert(strcaseequal_neutral("LwAn", "lWaM") == false);
     710             : 
     711             :     static_assert(CHAR_BIT == 8, "sane CHAR_BIT value");
     712             :     static_assert('*' == 42, "ASCII character set");
     713             :     static_assert('0' == 48, "ASCII character set");
     714             :     static_assert('a' == 97, "ASCII character set");
     715          92 : }
     716             : #endif
     717             : 
     718             : #ifndef LWAN_HAVE_STPCPY
     719             : char *stpncpy(char *restrict dst, const char *restrict src, size_t sz)
     720             : {
     721             :     /* Implementation from the Linux stpcpy(3) man page. */
     722             :     char *p = mempcpy(dst, src, sz);
     723             :     *p = 0;
     724             :     return p;
     725             : }
     726             : 
     727             : char *stpcpy(char *restrict dst, const char *restrict src)
     728             : {
     729             :     return stpncpy(dst, src, strlen(src));
     730             : }
     731             : #endif

Generated by: LCOV version 1.15-2-gb9d6727