LCOV - code coverage report
Current view: top level - lib - sd-daemon.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 171 0.0 %
Date: 2023-04-18 16:19:03 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is based on sd-daemon.c from systemd. Unused code has been
       5             :   removed.
       6             : 
       7             :   Copyright 2010 Lennart Poettering
       8             : 
       9             :   systemd is free software; you can redistribute it and/or modify it
      10             :   under the terms of the GNU Lesser General Public License as published by
      11             :   the Free Software Foundation; either version 2.1 of the License, or
      12             :   (at your option) any later version.
      13             : 
      14             :   systemd is distributed in the hope that it will be useful, but
      15             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      17             :   Lesser General Public License for more details.
      18             : 
      19             :   You should have received a copy of the GNU Lesser General Public License
      20             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      21             : ***/
      22             : 
      23             : #define _GNU_SOURCE
      24             : #include <assert.h>
      25             : #include <errno.h>
      26             : #include <fcntl.h>
      27             : #include <limits.h>
      28             : #include <netinet/in.h>
      29             : #include <stdlib.h>
      30             : #include <sys/resource.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/stat.h>
      33             : #include <sys/types.h>
      34             : #include <unistd.h>
      35             : 
      36             : #include "sd-daemon.h"
      37             : #include "lwan-config.h"
      38             : 
      39           0 : static void unsetenv_listen_vars(void) {
      40           0 :         unsetenv("LISTEN_PID");
      41           0 :         unsetenv("LISTEN_FDS");
      42           0 :         unsetenv("LISTEN_FDNAMES");
      43           0 : }
      44             : 
      45           0 : int sd_listen_fds(int unset_environment) {
      46             :         int n, l, r, fd;
      47             :         const char *e;
      48             : 
      49           0 :         e = getenv("LISTEN_PID");
      50           0 :         if (!e) {
      51           0 :                 r = 0;
      52           0 :                 goto finish;
      53             :         }
      54             : 
      55           0 :         l = parse_int(e, -1);
      56           0 :         if (l <= 0) {
      57           0 :                 r = -EINVAL;
      58           0 :                 goto finish;
      59             :         }
      60             : 
      61             :         /* Is this for us? */
      62           0 :         if (getpid() != (pid_t)l) {
      63           0 :                 r = 0;
      64           0 :                 goto finish;
      65             :         }
      66             : 
      67           0 :         e = getenv("LISTEN_FDS");
      68           0 :         if (!e) {
      69           0 :                 r = 0;
      70           0 :                 goto finish;
      71             :         }
      72             : 
      73           0 :         n = parse_int(e, -1);
      74           0 :         if (!n) {
      75           0 :                 r = 0;
      76           0 :                 goto finish;
      77             :         }
      78             : 
      79             :         static_assert(SD_LISTEN_FDS_START < INT_MAX, "");
      80           0 :         if (n < 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
      81           0 :                 r = -EINVAL;
      82           0 :                 goto finish;
      83             :         }
      84             : 
      85           0 :         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int)n; fd++) {
      86             :                 int flags;
      87             : 
      88           0 :                 flags = fcntl(fd, F_GETFD);
      89           0 :                 if (flags < 0) {
      90           0 :                         r = -errno;
      91           0 :                         goto finish;
      92             :                 }
      93             : 
      94           0 :                 if (flags & FD_CLOEXEC)
      95           0 :                         continue;
      96             : 
      97           0 :                 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
      98           0 :                         r = -errno;
      99           0 :                         goto finish;
     100             :                 }
     101             :         }
     102             : 
     103           0 :         r = n;
     104             : 
     105           0 : finish:
     106           0 :         if (unset_environment)
     107           0 :                 unsetenv_listen_vars();
     108             : 
     109           0 :         return r;
     110             : }
     111             : 
     112             : /* Both strv_extend_n() and strv_split() aren't simple copies of the
     113             :  * same functions from systemd.  These are simplified versions of those
     114             :  * functions, used only in the sd_listen_fds_with_names() ported from
     115             :  * newer versions of systemd.
     116             :  */
     117           0 : static int strv_extend_n(char ***p, const char *s, int n) {
     118           0 :         if (!p)
     119           0 :                 return -EINVAL;
     120           0 :         if (!s)
     121           0 :                 return -EINVAL;
     122             : 
     123           0 :         *p = calloc((size_t)n, sizeof(char *));
     124           0 :         if (!p)
     125           0 :                 return -ENOMEM;
     126             : 
     127           0 :         size_t s_size = strlen(s) + 1;
     128           0 :         char *copies = calloc((size_t)(n + 1), s_size);
     129           0 :         if (!copies) {
     130           0 :                 free(*p);
     131           0 :                 return -ENOMEM;
     132             :         }
     133           0 :         for (int i = 0; i < n; i++) {
     134           0 :                 char *copy = &copies[(size_t)i * s_size];
     135           0 :                 *p[i] = memcpy(copy, s, s_size);
     136             :         }        
     137             : 
     138           0 :         return 0;
     139             : }
     140             : 
     141           0 : static int strv_split(char ***p, const char *value, const char separator) {
     142           0 :         char *copy = strdup(value);
     143           0 :         int n_split = 0;
     144             : 
     145           0 :         if (!copy)
     146           0 :                 return -ENOMEM;
     147             : 
     148           0 :         for (char *c = copy; *c; ) {
     149           0 :                 char *sep_pos = strchr(c, separator);
     150           0 :                 if (!sep_pos)
     151           0 :                         break;
     152             : 
     153           0 :                 n_split++;
     154           0 :                 c = sep_pos + 1;
     155             :         }        
     156             : 
     157           0 :         if (!n_split)
     158           0 :                 return 0;
     159             : 
     160           0 :         *p = calloc((size_t)(n_split + 1), sizeof(char *));
     161           0 :         if (!*p) {
     162           0 :                 free(copy);
     163           0 :                 return -ENOMEM;
     164             :         }
     165             : 
     166           0 :         int i = 0;
     167           0 :         for (char *c = copy; *c; ) {
     168           0 :                 char *sep_pos = strchr(c, separator);
     169           0 :                 if (!sep_pos)
     170           0 :                         break;
     171             : 
     172           0 :                 *sep_pos = '\0';
     173           0 :                 *p[i++] = c;
     174           0 :                 c = sep_pos + 1;
     175             :         }        
     176             : 
     177           0 :         return n_split;
     178             : }
     179             : 
     180           0 : int sd_listen_fds_with_names(int unset_environment, char ***names) {
     181           0 :         char **l = NULL;
     182             :         bool have_names;
     183           0 :         int n_names = 0, n_fds;
     184             :         const char *e;
     185             :         int r;
     186             : 
     187           0 :         if (!names)
     188           0 :                 return sd_listen_fds(unset_environment);
     189             : 
     190           0 :         e = getenv("LISTEN_FDNAMES");
     191           0 :         if (e) {
     192           0 :                 n_names = strv_split(&l, e, ':');
     193           0 :                 if (n_names < 0) {
     194           0 :                         if (unset_environment)
     195           0 :                                 unsetenv_listen_vars();
     196           0 :                         return n_names;
     197             :                 }
     198             : 
     199           0 :                 have_names = true;
     200             :         } else {
     201           0 :                 have_names = false;
     202             :         }
     203             : 
     204           0 :         n_fds = sd_listen_fds(unset_environment);
     205           0 :         if (n_fds <= 0) {
     206           0 :                 r = n_fds;
     207           0 :                 goto fail;
     208             :         }
     209             : 
     210           0 :         if (have_names) {
     211           0 :                 if (n_names != n_fds) {
     212           0 :                         r = -EINVAL;
     213           0 :                         goto fail;
     214             :                 }
     215             :         } else {
     216           0 :                 r = strv_extend_n(&l, "unknown", n_fds);
     217           0 :                 if (r < 0)
     218           0 :                         goto fail;
     219             :         }
     220             : 
     221           0 :         *names = l;
     222             : 
     223           0 :         return n_fds;
     224             : 
     225           0 : fail:
     226           0 :         free(l);
     227           0 :         return r;
     228             : }
     229             : 
     230           0 : static int sd_is_socket_internal(int fd, int type, int listening) {
     231             :         struct stat st_fd;
     232             : 
     233           0 :         if (fd < 0)
     234           0 :                 return -EBADF;
     235             : 
     236           0 :         if (type < 0)
     237           0 :                 return -EINVAL;
     238             : 
     239           0 :         if (fstat(fd, &st_fd) < 0)
     240           0 :                 return -errno;
     241             : 
     242           0 :         if (!S_ISSOCK(st_fd.st_mode))
     243           0 :                 return 0;
     244             : 
     245           0 :         if (type != 0) {
     246           0 :                 int other_type = 0;
     247           0 :                 socklen_t l = sizeof(other_type);
     248             : 
     249           0 :                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
     250           0 :                         return -errno;
     251             : 
     252           0 :                 if (l != sizeof(other_type))
     253           0 :                         return -EINVAL;
     254             : 
     255           0 :                 if (other_type != type)
     256           0 :                         return 0;
     257             :         }
     258             : 
     259           0 :         if (listening >= 0) {
     260           0 :                 int accepting = 0;
     261           0 :                 socklen_t l = sizeof(accepting);
     262             : 
     263           0 :                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
     264           0 :                         return -errno;
     265             : 
     266           0 :                 if (l != sizeof(accepting))
     267           0 :                         return -EINVAL;
     268             : 
     269           0 :                 if (!accepting != !listening)
     270           0 :                         return 0;
     271             :         }
     272             : 
     273           0 :         return 1;
     274             : }
     275             : 
     276             : union sockaddr_union {
     277             :         struct sockaddr sa;
     278             :         struct sockaddr_in in4;
     279             :         struct sockaddr_in6 in6;
     280             : };
     281             : 
     282           0 : int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
     283           0 :         union sockaddr_union sockaddr = {};
     284           0 :         socklen_t l = sizeof(sockaddr);
     285             :         int r;
     286             : 
     287           0 :         if (family != 0 && family != AF_INET && family != AF_INET6)
     288           0 :                 return -EINVAL;
     289             : 
     290           0 :         r = sd_is_socket_internal(fd, type, listening);
     291           0 :         if (r <= 0)
     292           0 :                 return r;
     293             : 
     294           0 :         if (getsockname(fd, &sockaddr.sa, &l) < 0)
     295           0 :                 return -errno;
     296             : 
     297           0 :         if (l < sizeof(sa_family_t))
     298           0 :                 return -EINVAL;
     299             : 
     300           0 :         if (sockaddr.sa.sa_family != AF_INET &&
     301           0 :             sockaddr.sa.sa_family != AF_INET6)
     302           0 :                 return 0;
     303             : 
     304           0 :         if (family > 0)
     305           0 :                 if (sockaddr.sa.sa_family != family)
     306           0 :                         return 0;
     307             : 
     308           0 :         if (port > 0) {
     309           0 :                 if (sockaddr.sa.sa_family == AF_INET) {
     310           0 :                         if (l < sizeof(struct sockaddr_in))
     311           0 :                                 return -EINVAL;
     312             : 
     313           0 :                         return htons(port) == sockaddr.in4.sin_port;
     314             :                 } else {
     315           0 :                         if (l < sizeof(struct sockaddr_in6))
     316           0 :                                 return -EINVAL;
     317             : 
     318           0 :                         return htons(port) == sockaddr.in6.sin6_port;
     319             :                 }
     320             :         }
     321             : 
     322           0 :         return 1;
     323             : }

Generated by: LCOV version 1.15-2-gb9d6727