LCOV - code coverage report
Current view: top level - shared - fdset.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 92 122 75.4 %
Date: 2019-08-22 15:41:25 Functions: 15 16 93.8 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <alloca.h>
       4             : #include <errno.h>
       5             : #include <fcntl.h>
       6             : #include <stddef.h>
       7             : 
       8             : #include "sd-daemon.h"
       9             : 
      10             : #include "alloc-util.h"
      11             : #include "dirent-util.h"
      12             : #include "fd-util.h"
      13             : #include "fdset.h"
      14             : #include "log.h"
      15             : #include "macro.h"
      16             : #include "parse-util.h"
      17             : #include "path-util.h"
      18             : #include "set.h"
      19             : 
      20             : #define MAKE_SET(s) ((Set*) s)
      21             : #define MAKE_FDSET(s) ((FDSet*) s)
      22             : 
      23           9 : FDSet *fdset_new(void) {
      24           9 :         return MAKE_FDSET(set_new(NULL));
      25             : }
      26             : 
      27           1 : int fdset_new_array(FDSet **ret, const int *fds, size_t n_fds) {
      28             :         size_t i;
      29             :         FDSet *s;
      30             :         int r;
      31             : 
      32           1 :         assert(ret);
      33             : 
      34           1 :         s = fdset_new();
      35           1 :         if (!s)
      36           0 :                 return -ENOMEM;
      37             : 
      38           5 :         for (i = 0; i < n_fds; i++) {
      39             : 
      40           4 :                 r = fdset_put(s, fds[i]);
      41           4 :                 if (r < 0) {
      42           0 :                         set_free(MAKE_SET(s));
      43           0 :                         return r;
      44             :                 }
      45             :         }
      46             : 
      47           1 :         *ret = s;
      48           1 :         return 0;
      49             : }
      50             : 
      51           9 : void fdset_close(FDSet *s) {
      52             :         void *p;
      53             : 
      54          20 :         while ((p = set_steal_first(MAKE_SET(s)))) {
      55             :                 /* Valgrind's fd might have ended up in this set here, due to fdset_new_fill(). We'll ignore
      56             :                  * all failures here, so that the EBADFD that valgrind will return us on close() doesn't
      57             :                  * influence us */
      58             : 
      59             :                 /* When reloading duplicates of the private bus connection fds and suchlike are closed here,
      60             :                  * which has no effect at all, since they are only duplicates. So don't be surprised about
      61             :                  * these log messages. */
      62             : 
      63          11 :                 log_debug("Closing set fd %i", PTR_TO_FD(p));
      64          11 :                 (void) close_nointr(PTR_TO_FD(p));
      65             :         }
      66           9 : }
      67             : 
      68           9 : FDSet* fdset_free(FDSet *s) {
      69           9 :         fdset_close(s);
      70           9 :         set_free(MAKE_SET(s));
      71           9 :         return NULL;
      72             : }
      73             : 
      74          15 : int fdset_put(FDSet *s, int fd) {
      75          15 :         assert(s);
      76          15 :         assert(fd >= 0);
      77             : 
      78          15 :         return set_put(MAKE_SET(s), FD_TO_PTR(fd));
      79             : }
      80             : 
      81           2 : int fdset_put_dup(FDSet *s, int fd) {
      82             :         int copy, r;
      83             : 
      84           2 :         assert(s);
      85           2 :         assert(fd >= 0);
      86             : 
      87           2 :         copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
      88           2 :         if (copy < 0)
      89           0 :                 return -errno;
      90             : 
      91           2 :         r = fdset_put(s, copy);
      92           2 :         if (r < 0) {
      93           0 :                 safe_close(copy);
      94           0 :                 return r;
      95             :         }
      96             : 
      97           2 :         return copy;
      98             : }
      99             : 
     100           8 : bool fdset_contains(FDSet *s, int fd) {
     101           8 :         assert(s);
     102           8 :         assert(fd >= 0);
     103             : 
     104           8 :         return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
     105             : }
     106             : 
     107           1 : int fdset_remove(FDSet *s, int fd) {
     108           1 :         assert(s);
     109           1 :         assert(fd >= 0);
     110             : 
     111           1 :         return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
     112             : }
     113             : 
     114           1 : int fdset_new_fill(FDSet **_s) {
     115           1 :         _cleanup_closedir_ DIR *d = NULL;
     116             :         struct dirent *de;
     117           1 :         int r = 0;
     118             :         FDSet *s;
     119             : 
     120           1 :         assert(_s);
     121             : 
     122             :         /* Creates an fdset and fills in all currently open file
     123             :          * descriptors. */
     124             : 
     125           1 :         d = opendir("/proc/self/fd");
     126           1 :         if (!d)
     127           0 :                 return -errno;
     128             : 
     129           1 :         s = fdset_new();
     130           1 :         if (!s) {
     131           0 :                 r = -ENOMEM;
     132           0 :                 goto finish;
     133             :         }
     134             : 
     135           8 :         FOREACH_DIRENT(de, d, return -errno) {
     136           5 :                 int fd = -1;
     137             : 
     138           5 :                 r = safe_atoi(de->d_name, &fd);
     139           5 :                 if (r < 0)
     140           0 :                         goto finish;
     141             : 
     142           5 :                 if (fd < 3)
     143           4 :                         continue;
     144             : 
     145           2 :                 if (fd == dirfd(d))
     146           1 :                         continue;
     147             : 
     148           1 :                 r = fdset_put(s, fd);
     149           1 :                 if (r < 0)
     150           0 :                         goto finish;
     151             :         }
     152             : 
     153           1 :         r = 0;
     154           1 :         *_s = TAKE_PTR(s);
     155             : 
     156           1 : finish:
     157             :         /* We won't close the fds here! */
     158           1 :         if (s)
     159           0 :                 set_free(MAKE_SET(s));
     160             : 
     161           1 :         return r;
     162             : }
     163             : 
     164           2 : int fdset_cloexec(FDSet *fds, bool b) {
     165             :         Iterator i;
     166             :         void *p;
     167             :         int r;
     168             : 
     169           2 :         assert(fds);
     170             : 
     171           4 :         SET_FOREACH(p, MAKE_SET(fds), i) {
     172           2 :                 r = fd_cloexec(PTR_TO_FD(p), b);
     173           2 :                 if (r < 0)
     174           0 :                         return r;
     175             :         }
     176             : 
     177           2 :         return 0;
     178             : }
     179             : 
     180           0 : int fdset_new_listen_fds(FDSet **_s, bool unset) {
     181             :         int n, fd, r;
     182             :         FDSet *s;
     183             : 
     184           0 :         assert(_s);
     185             : 
     186             :         /* Creates an fdset and fills in all passed file descriptors */
     187             : 
     188           0 :         s = fdset_new();
     189           0 :         if (!s) {
     190           0 :                 r = -ENOMEM;
     191           0 :                 goto fail;
     192             :         }
     193             : 
     194           0 :         n = sd_listen_fds(unset);
     195           0 :         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
     196           0 :                 r = fdset_put(s, fd);
     197           0 :                 if (r < 0)
     198           0 :                         goto fail;
     199             :         }
     200             : 
     201           0 :         *_s = s;
     202           0 :         return 0;
     203             : 
     204           0 : fail:
     205           0 :         if (s)
     206           0 :                 set_free(MAKE_SET(s));
     207             : 
     208           0 :         return r;
     209             : }
     210             : 
     211           1 : int fdset_close_others(FDSet *fds) {
     212             :         void *e;
     213             :         Iterator i;
     214           1 :         int *a = NULL;
     215           1 :         size_t j = 0, m;
     216             : 
     217           1 :         m = fdset_size(fds);
     218             : 
     219           1 :         if (m > 0) {
     220           1 :                 a = newa(int, m);
     221           2 :                 SET_FOREACH(e, MAKE_SET(fds), i)
     222           1 :                         a[j++] = PTR_TO_FD(e);
     223             :         }
     224             : 
     225           1 :         assert(j == m);
     226             : 
     227           1 :         return close_all_fds(a, j);
     228             : }
     229             : 
     230          13 : unsigned fdset_size(FDSet *fds) {
     231          13 :         return set_size(MAKE_SET(fds));
     232             : }
     233             : 
     234           2 : bool fdset_isempty(FDSet *fds) {
     235           2 :         return set_isempty(MAKE_SET(fds));
     236             : }
     237             : 
     238           2 : int fdset_iterate(FDSet *s, Iterator *i) {
     239             :         void *p;
     240             : 
     241           2 :         if (!set_iterate(MAKE_SET(s), i, &p))
     242           1 :                 return -ENOENT;
     243             : 
     244           1 :         return PTR_TO_FD(p);
     245             : }
     246             : 
     247           3 : int fdset_steal_first(FDSet *fds) {
     248             :         void *p;
     249             : 
     250           3 :         p = set_steal_first(MAKE_SET(fds));
     251           3 :         if (!p)
     252           2 :                 return -ENOENT;
     253             : 
     254           1 :         return PTR_TO_FD(p);
     255             : }

Generated by: LCOV version 1.14