LCOV - code coverage report
Current view: top level - basic - fdset.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 87 123 70.7 %
Date: 2015-07-29 18:47:03 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <dirent.h>
      24             : #include <fcntl.h>
      25             : 
      26             : #include "set.h"
      27             : #include "util.h"
      28             : #include "macro.h"
      29             : #include "fdset.h"
      30             : #include "sd-daemon.h"
      31             : 
      32             : #define MAKE_SET(s) ((Set*) s)
      33             : #define MAKE_FDSET(s) ((FDSet*) s)
      34             : 
      35             : /* Make sure we can distinguish fd 0 and NULL */
      36             : #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
      37             : #define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
      38             : 
      39           9 : FDSet *fdset_new(void) {
      40           9 :         return MAKE_FDSET(set_new(NULL));
      41             : }
      42             : 
      43           1 : int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) {
      44             :         unsigned i;
      45             :         FDSet *s;
      46             :         int r;
      47             : 
      48           1 :         assert(ret);
      49             : 
      50           1 :         s = fdset_new();
      51           1 :         if (!s)
      52           0 :                 return -ENOMEM;
      53             : 
      54           5 :         for (i = 0; i < n_fds; i++) {
      55             : 
      56           4 :                 r = fdset_put(s, fds[i]);
      57           4 :                 if (r < 0) {
      58           0 :                         set_free(MAKE_SET(s));
      59           0 :                         return r;
      60             :                 }
      61             :         }
      62             : 
      63           1 :         *ret = s;
      64           1 :         return 0;
      65             : }
      66             : 
      67           9 : FDSet* fdset_free(FDSet *s) {
      68             :         void *p;
      69             : 
      70          29 :         while ((p = set_steal_first(MAKE_SET(s)))) {
      71             :                 /* Valgrind's fd might have ended up in this set here,
      72             :                  * due to fdset_new_fill(). We'll ignore all failures
      73             :                  * here, so that the EBADFD that valgrind will return
      74             :                  * us on close() doesn't influence us */
      75             : 
      76             :                 /* When reloading duplicates of the private bus
      77             :                  * connection fds and suchlike are closed here, which
      78             :                  * has no effect at all, since they are only
      79             :                  * duplicates. So don't be surprised about these log
      80             :                  * messages. */
      81             : 
      82          11 :                 log_debug("Closing left-over fd %i", PTR_TO_FD(p));
      83          11 :                 close_nointr(PTR_TO_FD(p));
      84             :         }
      85             : 
      86           9 :         set_free(MAKE_SET(s));
      87           9 :         return NULL;
      88             : }
      89             : 
      90          15 : int fdset_put(FDSet *s, int fd) {
      91          15 :         assert(s);
      92          15 :         assert(fd >= 0);
      93             : 
      94          15 :         return set_put(MAKE_SET(s), FD_TO_PTR(fd));
      95             : }
      96             : 
      97           0 : int fdset_consume(FDSet *s, int fd) {
      98             :         int r;
      99             : 
     100           0 :         assert(s);
     101           0 :         assert(fd >= 0);
     102             : 
     103           0 :         r = fdset_put(s, fd);
     104           0 :         if (r <= 0)
     105           0 :                 safe_close(fd);
     106             : 
     107           0 :         return r;
     108             : }
     109             : 
     110           2 : int fdset_put_dup(FDSet *s, int fd) {
     111             :         int copy, r;
     112             : 
     113           2 :         assert(s);
     114           2 :         assert(fd >= 0);
     115             : 
     116           2 :         copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
     117           2 :         if (copy < 0)
     118           0 :                 return -errno;
     119             : 
     120           2 :         r = fdset_put(s, copy);
     121           2 :         if (r < 0) {
     122           0 :                 safe_close(copy);
     123           0 :                 return r;
     124             :         }
     125             : 
     126           2 :         return copy;
     127             : }
     128             : 
     129           8 : bool fdset_contains(FDSet *s, int fd) {
     130           8 :         assert(s);
     131           8 :         assert(fd >= 0);
     132             : 
     133           8 :         return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
     134             : }
     135             : 
     136           1 : int fdset_remove(FDSet *s, int fd) {
     137           1 :         assert(s);
     138           1 :         assert(fd >= 0);
     139             : 
     140           1 :         return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
     141             : }
     142             : 
     143           1 : int fdset_new_fill(FDSet **_s) {
     144           2 :         _cleanup_closedir_ DIR *d = NULL;
     145             :         struct dirent *de;
     146           1 :         int r = 0;
     147             :         FDSet *s;
     148             : 
     149           1 :         assert(_s);
     150             : 
     151             :         /* Creates an fdset and fills in all currently open file
     152             :          * descriptors. */
     153             : 
     154           1 :         d = opendir("/proc/self/fd");
     155           1 :         if (!d)
     156           0 :                 return -errno;
     157             : 
     158           1 :         s = fdset_new();
     159           1 :         if (!s) {
     160           0 :                 r = -ENOMEM;
     161           0 :                 goto finish;
     162             :         }
     163             : 
     164           9 :         while ((de = readdir(d))) {
     165           7 :                 int fd = -1;
     166             : 
     167           7 :                 if (hidden_file(de->d_name))
     168           8 :                         continue;
     169             : 
     170           5 :                 r = safe_atoi(de->d_name, &fd);
     171           5 :                 if (r < 0)
     172           0 :                         goto finish;
     173             : 
     174           5 :                 if (fd < 3)
     175           3 :                         continue;
     176             : 
     177           2 :                 if (fd == dirfd(d))
     178           1 :                         continue;
     179             : 
     180           1 :                 r = fdset_put(s, fd);
     181           1 :                 if (r < 0)
     182           0 :                         goto finish;
     183             :         }
     184             : 
     185           1 :         r = 0;
     186           1 :         *_s = s;
     187           1 :         s = NULL;
     188             : 
     189             : finish:
     190             :         /* We won't close the fds here! */
     191           1 :         if (s)
     192           0 :                 set_free(MAKE_SET(s));
     193             : 
     194           1 :         return r;
     195             : }
     196             : 
     197           2 : int fdset_cloexec(FDSet *fds, bool b) {
     198             :         Iterator i;
     199             :         void *p;
     200             :         int r;
     201             : 
     202           2 :         assert(fds);
     203             : 
     204           6 :         SET_FOREACH(p, MAKE_SET(fds), i)
     205           2 :                 if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
     206           0 :                         return r;
     207             : 
     208           2 :         return 0;
     209             : }
     210             : 
     211           0 : int fdset_new_listen_fds(FDSet **_s, bool unset) {
     212             :         int n, fd, r;
     213             :         FDSet *s;
     214             : 
     215           0 :         assert(_s);
     216             : 
     217             :         /* Creates an fdset and fills in all passed file descriptors */
     218             : 
     219           0 :         s = fdset_new();
     220           0 :         if (!s) {
     221           0 :                 r = -ENOMEM;
     222           0 :                 goto fail;
     223             :         }
     224             : 
     225           0 :         n = sd_listen_fds(unset);
     226           0 :         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
     227           0 :                 r = fdset_put(s, fd);
     228           0 :                 if (r < 0)
     229           0 :                         goto fail;
     230             :         }
     231             : 
     232           0 :         *_s = s;
     233           0 :         return 0;
     234             : 
     235             : 
     236             : fail:
     237           0 :         if (s)
     238           0 :                 set_free(MAKE_SET(s));
     239             : 
     240           0 :         return r;
     241             : }
     242             : 
     243           1 : int fdset_close_others(FDSet *fds) {
     244             :         void *e;
     245             :         Iterator i;
     246             :         int *a;
     247             :         unsigned j, m;
     248             : 
     249           1 :         j = 0, m = fdset_size(fds);
     250           1 :         a = alloca(sizeof(int) * m);
     251           3 :         SET_FOREACH(e, MAKE_SET(fds), i)
     252           1 :                 a[j++] = PTR_TO_FD(e);
     253             : 
     254           1 :         assert(j == m);
     255             : 
     256           1 :         return close_all_fds(a, j);
     257             : }
     258             : 
     259          12 : unsigned fdset_size(FDSet *fds) {
     260          12 :         return set_size(MAKE_SET(fds));
     261             : }
     262             : 
     263           2 : bool fdset_isempty(FDSet *fds) {
     264           2 :         return set_isempty(MAKE_SET(fds));
     265             : }
     266             : 
     267           2 : int fdset_iterate(FDSet *s, Iterator *i) {
     268             :         void *p;
     269             : 
     270           2 :         if (!set_iterate(MAKE_SET(s), i, &p))
     271           1 :                 return -ENOENT;
     272             : 
     273           1 :         return PTR_TO_FD(p);
     274             : }
     275             : 
     276           3 : int fdset_steal_first(FDSet *fds) {
     277             :         void *p;
     278             : 
     279           3 :         p = set_steal_first(MAKE_SET(fds));
     280           3 :         if (!p)
     281           2 :                 return -ENOENT;
     282             : 
     283           1 :         return PTR_TO_FD(p);
     284             : }

Generated by: LCOV version 1.11