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

systemd / systemd / 14048528658

24 Mar 2025 08:06PM UTC coverage: 71.927% (-0.04%) from 71.966%
14048528658

push

github

web-flow
Ratelimit attempts to open watchdog, increase logging (#35708)

29 of 69 new or added lines in 4 files covered. (42.03%)

1083 existing lines in 38 files now uncovered.

296538 of 412279 relevant lines covered (71.93%)

716588.24 hits per line

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

76.03
/src/basic/io-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <limits.h>
5
#include <stdio.h>
6
#include <unistd.h>
7

8
#include "errno-util.h"
9
#include "io-util.h"
10
#include "iovec-util.h"
11
#include "string-util.h"
12
#include "time-util.h"
13

14
int flush_fd(int fd) {
4,833✔
15
        int count = 0;
4,833✔
16

17
        /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
18
         * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
19
         * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
20
         * was set to non-blocking too. */
21

22
        for (;;) {
10,958✔
23
                char buf[LINE_MAX];
10,958✔
24
                ssize_t l;
10,958✔
25
                int r;
10,958✔
26

27
                r = fd_wait_for_event(fd, POLLIN, 0);
10,958✔
28
                if (r < 0) {
10,958✔
29
                        if (r == -EINTR)
×
30
                                continue;
×
31

32
                        return r;
4,833✔
33
                }
34
                if (r == 0)
10,958✔
35
                        return count;
36

37
                l = read(fd, buf, sizeof(buf));
6,125✔
38
                if (l < 0) {
6,125✔
39
                        if (errno == EINTR)
×
40
                                continue;
×
41

42
                        if (errno == EAGAIN)
×
43
                                return count;
44

45
                        return -errno;
×
46
                } else if (l == 0)
6,125✔
47
                        return count;
48

49
                count += (int) l;
6,125✔
50
        }
51
}
52

53
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
13,406✔
54
        uint8_t *p = ASSERT_PTR(buf);
13,406✔
55
        ssize_t n = 0;
13,406✔
56

57
        assert(fd >= 0);
13,406✔
58

59
        /* If called with nbytes == 0, let's call read() at least once, to validate the operation */
60

61
        if (nbytes > (size_t) SSIZE_MAX)
13,406✔
62
                return -EINVAL;
63

64
        do {
24,945✔
65
                ssize_t k;
24,945✔
66

67
                k = read(fd, p, nbytes);
24,945✔
68
                if (k < 0) {
24,945✔
69
                        if (errno == EINTR)
×
70
                                continue;
×
71

72
                        if (errno == EAGAIN && do_poll) {
×
73

74
                                /* We knowingly ignore any return value here,
75
                                 * and expect that any error/EOF is reported
76
                                 * via read() */
77

78
                                (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
×
79
                                continue;
×
80
                        }
81

82
                        return n > 0 ? n : -errno;
×
83
                }
84

85
                if (k == 0)
24,945✔
86
                        return n;
87

88
                assert((size_t) k <= nbytes);
13,307✔
89
                assert(k <= SSIZE_MAX - n);
13,307✔
90

91
                p += k;
13,307✔
92
                nbytes -= k;
13,307✔
93
                n += k;
13,307✔
94
        } while (nbytes > 0);
13,307✔
95

96
        return n;
97
}
98

99
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
1,450✔
100
        ssize_t n;
1,450✔
101

102
        n = loop_read(fd, buf, nbytes, do_poll);
1,450✔
103
        if (n < 0)
1,450✔
104
                return (int) n;
×
105
        if ((size_t) n != nbytes)
1,450✔
106
                return -EIO;
×
107

108
        return 0;
109
}
110

111
int loop_write_full(int fd, const void *buf, size_t nbytes, usec_t timeout) {
182,341✔
112
        const uint8_t *p;
182,341✔
113
        usec_t end;
182,341✔
114
        int r;
182,341✔
115

116
        assert(fd >= 0);
182,341✔
117
        assert(buf || nbytes == 0);
182,341✔
118

119
        if (nbytes == 0) {
182,341✔
120
                static const dummy_t dummy[0];
121
                assert_cc(sizeof(dummy) == 0);
122
                p = (const void*) dummy; /* Some valid pointer, in case NULL was specified */
123
        } else {
124
                if (nbytes == SIZE_MAX)
182,312✔
125
                        nbytes = strlen(buf);
349✔
126
                else if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
181,963✔
127
                        return -EINVAL;
128

129
                p = buf;
130
        }
131

132
        /* When timeout is 0 or USEC_INFINITY this is not used. But we initialize it to a sensible value. */
133
        end = timestamp_is_set(timeout) ? usec_add(now(CLOCK_MONOTONIC), timeout) : USEC_INFINITY;
182,431✔
134

135
        do {
182,341✔
136
                ssize_t k;
182,341✔
137

138
                k = write(fd, p, nbytes);
182,341✔
139
                if (k < 0) {
182,341✔
140
                        if (errno == EINTR)
2✔
141
                                continue;
×
142

143
                        if (errno != EAGAIN || timeout == 0)
2✔
144
                                return -errno;
2✔
145

146
                        usec_t wait_for;
×
147

148
                        if (timeout == USEC_INFINITY)
×
149
                                wait_for = USEC_INFINITY;
150
                        else {
151
                                usec_t t = now(CLOCK_MONOTONIC);
×
152
                                if (t >= end)
×
153
                                        return -ETIME;
154

155
                                wait_for = usec_sub_unsigned(end, t);
×
156
                        }
157

158
                        r = fd_wait_for_event(fd, POLLOUT, wait_for);
×
159
                        if (timeout == USEC_INFINITY || ERRNO_IS_NEG_TRANSIENT(r))
×
160
                                /* If timeout == USEC_INFINITY we knowingly ignore any return value
161
                                 * here, and expect that any error/EOF is reported via write() */
162
                                continue;
×
163
                        if (r < 0)
×
164
                                return r;
165
                        if (r == 0)
×
166
                                return -ETIME;
167
                        continue;
×
168
                }
169

170
                if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
182,339✔
171
                        return -EIO;
172

173
                assert((size_t) k <= nbytes);
182,339✔
174

175
                p += k;
182,339✔
176
                nbytes -= k;
182,339✔
177
        } while (nbytes > 0);
182,339✔
178

179
        return 0;
180
}
181

182
int pipe_eof(int fd) {
×
183
        int r;
×
184

185
        r = fd_wait_for_event(fd, POLLIN, 0);
×
186
        if (r <= 0)
×
187
                return r;
188

189
        return !!(r & POLLHUP);
×
190
}
191

192
int ppoll_usec_full(struct pollfd *fds, size_t nfds, usec_t timeout, const sigset_t *ss) {
354,228✔
193
        int r;
354,228✔
194

195
        assert(fds || nfds == 0);
354,228✔
196

197
        /* This is a wrapper around ppoll() that does primarily two things:
198
         *
199
         *  ✅ Takes a usec_t instead of a struct timespec
200
         *
201
         *  ✅ Guarantees that if an invalid fd is specified we return EBADF (i.e. converts POLLNVAL to
202
         *     EBADF). This is done because EBADF is a programming error usually, and hence should bubble up
203
         *     as error, and not be eaten up as non-error POLLNVAL event.
204
         *
205
         *  ⚠️ ⚠️ ⚠️ Note that this function does not add any special handling for EINTR. Don't forget
206
         *  poll()/ppoll() will return with EINTR on any received signal always, there is no automatic
207
         *  restarting via SA_RESTART available. Thus, typically you want to handle EINTR not as an error,
208
         *  but just as reason to restart things, under the assumption you use a more appropriate mechanism
209
         *  to handle signals, such as signalfd() or signal handlers. ⚠️ ⚠️ ⚠️
210
         */
211

212
        if (nfds == 0 && timeout == 0)
354,228✔
213
                return 0;
354,228✔
214

215
        r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : TIMESPEC_STORE(timeout), ss);
354,228✔
216
        if (r < 0)
354,228✔
UNCOV
217
                return -errno;
×
218
        if (r == 0)
354,228✔
219
                return 0;
220

221
        for (size_t i = 0, n = r; i < nfds && n > 0; i++) {
631,590✔
222
                if (fds[i].revents == 0)
316,439✔
223
                        continue;
1,226✔
224
                if (fds[i].revents & POLLNVAL)
315,213✔
225
                        return -EBADF;
226
                n--;
315,213✔
227
        }
228

229
        return r;
230
}
231

232
int fd_wait_for_event(int fd, int event, usec_t timeout) {
58,502✔
233
        struct pollfd pollfd = {
58,502✔
234
                .fd = fd,
235
                .events = event,
236
        };
237
        int r;
58,502✔
238

239
        /* ⚠️ ⚠️ ⚠️ Keep in mind you almost certainly want to handle -EINTR gracefully in the caller, see
240
         * ppoll_usec() above! ⚠️ ⚠️ ⚠️ */
241

242
        r = ppoll_usec(&pollfd, 1, timeout);
58,502✔
243
        if (r <= 0)
58,502✔
244
                return r;
58,502✔
245

246
        return pollfd.revents;
19,427✔
247
}
248

249
static size_t nul_length(const uint8_t *p, size_t sz) {
312,524,583✔
250
        size_t n = 0;
312,524,583✔
251

252
        while (sz > 0) {
569,870,216✔
253
                if (*p != 0)
569,852,894✔
254
                        break;
255

256
                n++;
257,345,633✔
257
                p++;
257,345,633✔
258
                sz--;
257,345,633✔
259
        }
260

261
        return n;
312,524,583✔
262
}
263

264
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
33,132✔
265
        const uint8_t *q, *w, *e;
33,132✔
266
        ssize_t l;
33,132✔
267

268
        q = w = p;
33,132✔
269
        e = q + sz;
33,132✔
270
        while (q < e) {
312,557,715✔
271
                size_t n;
312,524,583✔
272

273
                n = nul_length(q, e - q);
312,524,583✔
274

275
                /* If there are more than the specified run length of
276
                 * NUL bytes, or if this is the beginning or the end
277
                 * of the buffer, then seek instead of write */
278
                if ((n > run_length) ||
312,524,583✔
279
                    (n > 0 && q == p) ||
312,356,803✔
280
                    (n > 0 && q + n >= e)) {
27,502,476✔
281
                        if (q > w) {
178,065✔
282
                                l = write(fd, w, q - w);
164,475✔
283
                                if (l < 0)
164,475✔
284
                                        return -errno;
×
285
                                if (l != q -w)
164,475✔
286
                                        return -EIO;
287
                        }
288

289
                        if (lseek(fd, n, SEEK_CUR) < 0)
178,065✔
290
                                return -errno;
×
291

292
                        q += n;
178,065✔
293
                        w = q;
178,065✔
294
                } else if (n > 0)
27,496,125✔
295
                        q += n;
296
                else
297
                        q++;
284,850,393✔
298
        }
299

300
        if (q > w) {
33,132✔
301
                l = write(fd, w, q - w);
15,810✔
302
                if (l < 0)
15,810✔
303
                        return -errno;
×
304
                if (l != q - w)
15,810✔
305
                        return -EIO;
306
        }
307

308
        return q - (const uint8_t*) p;
33,132✔
309
}
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