• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 21230603853

21 Jan 2026 10:57PM UTC coverage: 72.798% (+0.3%) from 72.524%
21230603853

push

github

web-flow
os-release: add a new FANCY_NAME= field to /etc/os-release, similar to PRETTY_NAME, that may carry ansi sequences + more unicode chars (#40367)

It's sometimes useful include non-ascii unicode chars in an os name, and
give it some ansi coloring. Since we usualy don't want to show that,
introduce a new field for it, and show it at boot and in thostnamectl
only, with safe fallbacks if colors/emojis are not available.

77 of 113 new or added lines in 5 files covered. (68.14%)

2146 existing lines in 53 files now uncovered.

311199 of 427481 relevant lines covered (72.8%)

1155064.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.75
/src/shared/fdset.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <unistd.h>
5

6
#include "sd-daemon.h"
7

8
#include "alloc-util.h"
9
#include "async.h"
10
#include "dirent-util.h"
11
#include "errno-util.h"
12
#include "fd-util.h"
13
#include "fdset.h"
14
#include "log.h"
15
#include "parse-util.h"
16
#include "set.h"
17
#include "stat-util.h"
18
#include "string-util.h"
19

20
#define MAKE_SET(s) ((Set*) s)
21
#define MAKE_FDSET(s) ((FDSet*) s)
22

23
FDSet* fdset_new(void) {
15,920✔
24
        return MAKE_FDSET(set_new(NULL));
15,920✔
25
}
26

27
static void fdset_shallow_freep(FDSet **s) {
12,616✔
28
        /* Destroys the set, but does not free the fds inside, like fdset_free()! */
29
        set_free(MAKE_SET(*ASSERT_PTR(s)));
12,616✔
30
}
12,616✔
31

32
int fdset_new_array(FDSet **ret, const int fds[], size_t n_fds) {
1,819✔
33
        _cleanup_(fdset_shallow_freep) FDSet *s = NULL;
1,819✔
34
        int r;
1,819✔
35

36
        assert(ret);
1,819✔
37
        assert(fds || n_fds == 0);
1,819✔
38

39
        s = fdset_new();
1,819✔
40
        if (!s)
1,819✔
41
                return -ENOMEM;
42

43
        FOREACH_ARRAY(fd, fds, n_fds) {
3,642✔
44
                r = fdset_put(s, *fd);
1,823✔
45
                if (r < 0)
1,823✔
46
                        return r;
47
        }
48

49
        *ret = TAKE_PTR(s);
1,819✔
50
        return 0;
1,819✔
51
}
52

53
int fdset_steal_first(FDSet *fds) {
43,059✔
54
        void *p;
43,059✔
55

56
        p = set_steal_first(MAKE_SET(fds));
43,059✔
57
        if (!p)
43,059✔
58
                return -ENOENT;
59

60
        return PTR_TO_FD(p);
12,020✔
61
}
62

63
void fdset_close(FDSet *fds, bool async) {
29,135✔
64
        int fd;
29,135✔
65

66
        while ((fd = fdset_steal_first(fds)) >= 0) {
39,349✔
67
                /* Valgrind's fd might have ended up in this set here, due to fdset_new_fill(). We'll ignore
68
                 * all failures here, so that the EBADFD that valgrind will return us on close() doesn't
69
                 * influence us */
70

71
                /* When reloading duplicates of the private bus connection fds and suchlike are closed here,
72
                 * which has no effect at all, since they are only duplicates. So don't be surprised about
73
                 * these log messages. */
74

75
                if (DEBUG_LOGGING) {
10,214✔
76
                        _cleanup_free_ char *path = NULL;
9,114✔
77

78
                        (void) fd_get_path(fd, &path);
9,114✔
79
                        log_debug("Closing set fd %i (%s)", fd, strna(path));
9,118✔
80
                }
81

82
                if (async)
10,214✔
83
                        (void) asynchronous_close(fd);
14✔
84
                else
85
                        (void) close(fd);
10,200✔
86
        }
87
}
29,135✔
88

89
FDSet* fdset_free(FDSet *s) {
27,146✔
90
        fdset_close(s, /* async= */ false);
27,146✔
91
        set_free(MAKE_SET(s));
27,146✔
92
        return NULL;
27,146✔
93
}
94

95
FDSet* fdset_free_async(FDSet *s) {
1,818✔
96
        fdset_close(s, /* async= */ true);
1,818✔
97
        set_free(MAKE_SET(s));
1,818✔
98
        return NULL;
1,818✔
99
}
100

101
int fdset_put(FDSet *s, int fd) {
55,228✔
102
        assert(s);
55,228✔
103
        assert(fd >= 0);
55,228✔
104

105
        /* Avoid integer overflow in FD_TO_PTR() */
106
        if (fd == INT_MAX)
55,228✔
UNCOV
107
                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Refusing invalid fd: %d", fd);
×
108

109
        return set_put(MAKE_SET(s), FD_TO_PTR(fd));
55,228✔
110
}
111

112
int fdset_consume(FDSet *s, int fd) {
1,106✔
113
        int r;
1,106✔
114

115
        assert(s);
1,106✔
116
        assert(fd >= 0);
1,106✔
117

118
        r = fdset_put(s, fd);
1,106✔
119
        if (r < 0)
1,106✔
UNCOV
120
                safe_close(fd);
×
121

122
        return r;
1,106✔
123
}
124

125
int fdset_put_dup(FDSet *s, int fd) {
14,991✔
126
        _cleanup_close_ int copy = -EBADF;
14,991✔
127
        int r;
14,991✔
128

129
        assert(s);
14,991✔
130
        assert(fd >= 0);
14,991✔
131

132
        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
14,991✔
133
        if (copy < 0)
14,991✔
UNCOV
134
                return -errno;
×
135

136
        r = fdset_put(s, copy);
14,991✔
137
        if (r < 0)
14,991✔
UNCOV
138
                return r;
×
139

140
        return TAKE_FD(copy);
141
}
142

143
bool fdset_contains(FDSet *s, int fd) {
2,147✔
144
        assert(s);
2,147✔
145
        assert(fd >= 0);
2,147✔
146

147
        /* Avoid integer overflow in FD_TO_PTR() */
148
        if (fd == INT_MAX) {
2,147✔
149
                log_debug("Refusing invalid fd: %d", fd);
×
UNCOV
150
                return false;
×
151
        }
152

153
        return set_contains(MAKE_SET(s), FD_TO_PTR(fd));
2,147✔
154
}
155

156
int fdset_remove(FDSet *s, int fd) {
40,337✔
157
        assert(s);
40,337✔
158
        assert(fd >= 0);
40,337✔
159

160
        /* Avoid integer overflow in FD_TO_PTR() */
161
        if (fd == INT_MAX)
40,337✔
UNCOV
162
                return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Refusing invalid fd: %d", fd);
×
163

164
        return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
40,337✔
165
}
166

167
int fdset_new_fill(
10,367✔
168
                int filter_cloexec, /* if < 0 takes all fds, otherwise only those with O_CLOEXEC set (1) or unset (0) */
169
                FDSet **ret) {
170

UNCOV
171
        _cleanup_(fdset_shallow_freep) FDSet *s = NULL;
×
172
        _cleanup_closedir_ DIR *d = NULL;
10,367✔
173
        int r;
10,367✔
174

175
        assert(ret);
10,367✔
176

177
        /* Creates an fdset and fills in all currently open file descriptors. Also set all collected fds
178
         * to CLOEXEC. */
179

180
        d = opendir("/proc/self/fd");
10,367✔
181
        if (!d) {
10,367✔
UNCOV
182
                if (errno == ENOENT && proc_mounted() == 0)
×
UNCOV
183
                        return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS),
×
184
                                               "Failed to open /proc/self/fd/, /proc/ is not mounted.");
185

UNCOV
186
                return log_debug_errno(errno, "Failed to open /proc/self/fd/: %m");
×
187
        }
188

189
        s = fdset_new();
10,367✔
190
        if (!s)
10,367✔
191
                return -ENOMEM;
192

193
        FOREACH_DIRENT(de, d, return -errno) {
130,143✔
194
                int fd;
99,042✔
195

196
                if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
99,042✔
UNCOV
197
                        continue;
×
198

199
                fd = parse_fd(de->d_name);
99,042✔
200
                if (fd < 0)
99,042✔
201
                        return fd;
202

203
                if (fd < 3)
99,042✔
204
                        continue;
31,101✔
205
                if (fd == dirfd(d))
67,941✔
206
                        continue;
10,367✔
207

208
                if (filter_cloexec >= 0) {
57,574✔
209
                        int fl;
57,573✔
210

211
                        /* If user asked for that filter by O_CLOEXEC. This is useful so that fds that have
212
                         * been passed in can be collected and fds which have been created locally can be
213
                         * ignored, under the assumption that only the latter have O_CLOEXEC set. */
214

215
                        fl = RET_NERRNO(fcntl(fd, F_GETFD));
57,573✔
UNCOV
216
                        if (fl < 0) {
×
UNCOV
217
                                if (DEBUG_LOGGING) {
×
UNCOV
218
                                        _cleanup_free_ char *path = NULL;
×
UNCOV
219
                                        (void) fd_get_path(fd, &path);
×
UNCOV
220
                                        log_debug_errno(fl, "Failed to get flags of fd=%d (%s): %m",
×
221
                                                        fd, strna(path));
222
                                }
223

UNCOV
224
                                return fl;
×
225
                        }
226

227
                        if (FLAGS_SET(fl, FD_CLOEXEC) != !!filter_cloexec)
57,573✔
228
                                continue;
20,367✔
229
                }
230

231
                /* We need to set CLOEXEC manually only if we're collecting non-CLOEXEC fds. */
232
                if (filter_cloexec <= 0) {
37,206✔
233
                        r = fd_cloexec(fd, true);
37,206✔
234
                        if (r < 0) {
37,206✔
UNCOV
235
                                if (DEBUG_LOGGING) {
×
UNCOV
236
                                        _cleanup_free_ char *path = NULL;
×
UNCOV
237
                                        (void) fd_get_path(fd, &path);
×
UNCOV
238
                                        log_debug_errno(r, "Failed to set CLOEXEC flag on fd=%d (%s): %m",
×
239
                                                        fd, strna(path));
240
                                }
241

UNCOV
242
                                return r;
×
243
                        }
244
                }
245

246
                r = fdset_put(s, fd);
37,207✔
247
                if (r < 0) {
37,207✔
UNCOV
248
                        if (DEBUG_LOGGING) {
×
UNCOV
249
                                _cleanup_free_ char *path = NULL;
×
UNCOV
250
                                (void) fd_get_path(fd, &path);
×
UNCOV
251
                                log_debug_errno(r, "Failed to put fd=%d (%s) into fdset: %m",
×
252
                                                fd, strna(path));
253
                        }
254

UNCOV
255
                        return r;
×
256
                }
257
        }
258

259
        *ret = TAKE_PTR(s);
10,367✔
260
        return 0;
10,367✔
261
}
262

263
int fdset_cloexec(FDSet *fds, bool b) {
2,553✔
264
        int r;
2,553✔
265

266
        assert(fds);
2,553✔
267

268
        int fd;
2,553✔
269
        FDSET_FOREACH(fd, fds) {
14,228✔
270
                r = fd_cloexec(fd, b);
11,675✔
271
                if (r < 0)
11,675✔
272
                        return r;
×
273
        }
274

275
        return 0;
2,553✔
276
}
277

278
int fdset_new_listen_fds(FDSet **ret, bool unset) {
430✔
279
        _cleanup_(fdset_shallow_freep) FDSet *s = NULL;
430✔
280
        int n, r;
430✔
281

282
        assert(ret);
430✔
283

284
        /* Creates an fdset and fills in all passed file descriptors */
285

286
        n = sd_listen_fds(unset);
430✔
287
        if (n < 0)
430✔
288
                return n;
289
        if (n == 0) {
430✔
290
                *ret = NULL;
430✔
291
                return 0;
430✔
292
        }
293

UNCOV
294
        s = fdset_new();
×
UNCOV
295
        if (!s)
×
296
                return -ENOMEM;
297

UNCOV
298
        for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
×
UNCOV
299
                r = fdset_put(s, fd);
×
UNCOV
300
                if (r < 0)
×
301
                        return r;
302
        }
303

UNCOV
304
        *ret = TAKE_PTR(s);
×
UNCOV
305
        return n;
×
306
}
307

308
int fdset_to_array(FDSet *fds, int **ret) {
124✔
309
        unsigned j = 0, m;
124✔
310
        int *a;
124✔
311

312
        assert(ret);
124✔
313

314
        m = fdset_size(fds);
124✔
315
        if (m > INT_MAX) /* We want to be able to return an "int" */
124✔
316
                return -ENOMEM;
124✔
317
        if (m == 0) {
124✔
318
                *ret = NULL; /* suppress array allocation if empty */
119✔
319
                return 0;
119✔
320
        }
321

322
        a = new(int, m);
5✔
323
        if (!a)
5✔
324
                return -ENOMEM;
325

326
        int fd;
5✔
327
        FDSET_FOREACH(fd, fds)
10✔
328
                a[j++] = fd;
5✔
329

330
        assert(j == m);
5✔
331

332
        *ret = TAKE_PTR(a);
5✔
333
        return (int) m;
5✔
334
}
335

336
int fdset_close_others(FDSet *fds) {
120✔
337
        _cleanup_free_ int *a = NULL;
120✔
338
        int n;
120✔
339

340
        n = fdset_to_array(fds, &a);
120✔
341
        if (n < 0)
120✔
342
                return n;
343

344
        return close_all_fds(a, n);
120✔
345
}
346

347
unsigned fdset_size(FDSet *fds) {
235✔
348
        return set_size(MAKE_SET(fds));
235✔
349
}
350

351
bool fdset_isempty(FDSet *fds) {
12,174✔
352
        return set_isempty(MAKE_SET(fds));
12,174✔
353
}
354

355
int fdset_iterate(FDSet *s, Iterator *i) {
20,488✔
356
        void *p;
20,488✔
357

358
        if (!set_iterate(MAKE_SET(s), i, &p))
20,488✔
359
                return -ENOENT;
20,488✔
360

361
        return PTR_TO_FD(p);
17,532✔
362
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc