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

systemd / systemd / 23927985597

02 Apr 2026 07:45PM UTC coverage: 72.362% (+0.02%) from 72.343%
23927985597

push

github

daandemeyer
ci: Drop base64 encoding in claude review workflow

Doesn't seem to work nearly as good as the previous solution which
just told claude not to escape stuff.

319121 of 441004 relevant lines covered (72.36%)

1167673.48 hits per line

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

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

3
#include <poll.h>
4
#include <stdio.h>
5
#include <string.h>
6
#include <time.h>
7
#include <unistd.h>
8

9
#include "errno-util.h"
10
#include "io-util.h"
11
#include "time-util.h"
12

13
int flush_fd(int fd) {
4,254✔
14
        int count = 0;
4,254✔
15

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

21
        for (;;) {
8,040✔
22
                char buf[LINE_MAX];
8,040✔
23
                ssize_t l;
8,040✔
24
                int r;
8,040✔
25

26
                r = fd_wait_for_event(fd, POLLIN, 0);
8,040✔
27
                if (r == -EINTR)
8,040✔
28
                        continue;
×
29
                if (r < 0)
8,040✔
30
                        return r;
4,254✔
31
                if (r == 0)
8,040✔
32
                        return count;
33

34
                l = read(fd, buf, sizeof(buf));
3,786✔
35
                if (l < 0) {
3,786✔
36
                        if (errno == EINTR)
×
37
                                continue;
×
38
                        if (errno == EAGAIN)
×
39
                                return count;
40

41
                        return -errno;
×
42
                } else if (l == 0)
3,786✔
43
                        return count;
44

45
                if (l > INT_MAX-count) /* On overflow terminate */
3,786✔
46
                        return INT_MAX;
47

48
                count += (int) l;
3,786✔
49
        }
50
}
51

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

56
        assert(fd >= 0);
18,275✔
57

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

60
        if (nbytes > (size_t) SSIZE_MAX)
18,275✔
61
                return -EINVAL;
62

63
        do {
31,780✔
64
                ssize_t k;
31,780✔
65

66
                k = read(fd, p, nbytes);
31,780✔
67
                if (k < 0) {
31,780✔
68
                        if (errno == EINTR)
×
69
                                continue;
×
70

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

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

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

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

84
                if (k == 0)
31,780✔
85
                        return n;
86

87
                assert((size_t) k <= nbytes);
18,031✔
88
                assert(k <= SSIZE_MAX - n);
18,031✔
89

90
                p += k;
18,031✔
91
                nbytes -= k;
18,031✔
92
                n += k;
18,031✔
93
        } while (nbytes > 0);
18,031✔
94

95
        return n;
96
}
97

98
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
3,988✔
99
        ssize_t n;
3,988✔
100

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

107
        return 0;
108
}
109

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

115
        assert(fd >= 0);
25,423✔
116
        assert(buf || nbytes == 0);
25,423✔
117

118
        if (nbytes == 0) {
25,423✔
119
                static const dummy_t dummy[0];
120
                assert_cc(sizeof(dummy) == 0);
121
                p = (const void*) dummy; /* Some valid pointer, in case NULL was specified */
122
        } else {
123
                if (nbytes == SIZE_MAX)
25,397✔
124
                        nbytes = strlen(buf);
346✔
125
                else if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
25,051✔
126
                        return -EINVAL;
127

128
                p = buf;
129
        }
130

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

134
        do {
25,423✔
135
                ssize_t k;
25,423✔
136

137
                k = write(fd, p, nbytes);
25,423✔
138
                if (k < 0) {
25,423✔
139
                        if (errno == EINTR)
1✔
140
                                continue;
×
141

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

145
                        usec_t wait_for;
×
146

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

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

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

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

172
                assert((size_t) k <= nbytes);
25,422✔
173

174
                p += k;
25,422✔
175
                nbytes -= k;
25,422✔
176
        } while (nbytes > 0);
25,422✔
177

178
        return 0;
179
}
180

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

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

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

191
int ppoll_usec_full(struct pollfd *fds, size_t n_fds, usec_t timeout, const sigset_t *ss) {
598,646✔
192
        int r;
598,646✔
193

194
        assert(fds || n_fds == 0);
598,646✔
195

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

211
        if (n_fds == 0 && timeout == 0)
598,646✔
212
                return 0;
598,646✔
213

214
        r = ppoll(fds, n_fds, timeout == USEC_INFINITY ? NULL : TIMESPEC_STORE(timeout), ss);
598,646✔
215
        if (r < 0)
598,646✔
216
                return -errno;
×
217
        if (r == 0)
598,646✔
218
                return 0;
219

220
        for (size_t i = 0, n = r; i < n_fds && n > 0; i++) {
1,100,139✔
221
                if (fds[i].revents == 0)
550,953✔
222
                        continue;
1,680✔
223
                if (fds[i].revents & POLLNVAL)
549,273✔
224
                        return -EBADF;
225
                n--;
549,273✔
226
        }
227

228
        return r;
229
}
230

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

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

241
        r = ppoll_usec(&pollfd, 1, timeout);
69,361✔
242
        if (r <= 0)
69,361✔
243
                return r;
69,361✔
244

245
        return pollfd.revents;
19,906✔
246
}
247

248
static size_t nul_length(const uint8_t *p, size_t sz) {
285,604,734✔
249
        size_t n = 0;
285,604,734✔
250

251
        while (sz > 0) {
830,643,027✔
252
                if (*p != 0)
830,638,569✔
253
                        break;
254

255
                n++;
545,038,293✔
256
                p++;
545,038,293✔
257
                sz--;
545,038,293✔
258
        }
259

260
        return n;
285,604,734✔
261
}
262

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

267
        q = w = p;
6,323✔
268
        e = q + sz;
6,323✔
269
        while (q < e) {
285,611,057✔
270
                size_t n;
285,604,734✔
271

272
                n = nul_length(q, e - q);
285,604,734✔
273

274
                /* If there are more than the specified run length of
275
                 * NUL bytes, or if this is the beginning or the end
276
                 * of the buffer, then seek instead of write */
277
                if ((n > run_length) ||
285,604,734✔
278
                    (n > 0 && q == p) ||
285,436,820✔
279
                    (n > 0 && q + n >= e)) {
19,801,827✔
280
                        if (q > w) {
168,905✔
281
                                l = write(fd, w, q - w);
164,985✔
282
                                if (l < 0)
164,985✔
283
                                        return -errno;
×
284
                                if (l != q -w)
164,985✔
285
                                        return -EIO;
286
                        }
287

288
                        if (lseek(fd, n, SEEK_CUR) < 0)
168,905✔
289
                                return -errno;
×
290

291
                        q += n;
168,905✔
292
                        w = q;
168,905✔
293
                } else if (n > 0)
19,801,148✔
294
                        q += n;
295
                else
296
                        q++;
265,634,681✔
297
        }
298

299
        if (q > w) {
6,323✔
300
                l = write(fd, w, q - w);
1,865✔
301
                if (l < 0)
1,865✔
302
                        return -errno;
×
303
                if (l != q - w)
1,865✔
304
                        return -EIO;
305
        }
306

307
        return q - (const uint8_t*) p;
6,323✔
308
}
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