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

systemd / systemd / 26546993077

27 May 2026 08:34PM UTC coverage: 72.995% (+0.3%) from 72.667%
26546993077

push

github

bluca
test-pressure: set timeout to make not wait forever

If this runs on a slow or busy machine, then we may not get enough
pressure to trigger the event sources. In such case, the test does not
finish. It is problematic when the test is _not_ run with 'meson test',
e.g. debian/ubuntu CIs.

Let's introduce a timeout for each event loop, and skip test cases
gracefully.

8 of 12 new or added lines in 1 file covered. (66.67%)

19671 existing lines in 226 files now uncovered.

337119 of 461841 relevant lines covered (72.99%)

1326365.62 hits per line

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

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

3
#include <fcntl.h>
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <string.h>
7
#include <sys/file.h>
8
#include <unistd.h>
9

10
#include "alloc-util.h"
11
#include "errno-util.h"
12
#include "fd-util.h"
13
#include "fs-util.h"
14
#include "lock-util.h"
15
#include "log.h"
16
#include "path-util.h"
17
#include "pidref.h"
18
#include "process-util.h"
19
#include "string-util.h"
20
#include "time-util.h"
21

22
int make_lock_file_at(int dir_fd, const char *p, int operation, LockFile *ret) {
163,422✔
23
        _cleanup_close_ int fd = -EBADF, dfd = -EBADF;
163,422✔
24
        _cleanup_free_ char *t = NULL;
163,422✔
25

26
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
163,422✔
27
        assert(p);
163,422✔
28
        assert(IN_SET(operation & ~LOCK_NB, LOCK_EX, LOCK_SH));
163,422✔
29
        assert(ret);
163,422✔
30

31
        if (isempty(p))
326,844✔
32
                return -EINVAL;
33

34
        /* We use UNPOSIX locks as they have nice semantics, and are mostly compatible with NFS. */
35

36
        dfd = fd_reopen(dir_fd, O_CLOEXEC|O_PATH|O_DIRECTORY);
163,422✔
37
        if (dfd < 0)
163,422✔
38
                return dfd;
39

40
        t = strdup(p);
163,422✔
41
        if (!t)
163,422✔
42
                return -ENOMEM;
43

44
        fd = xopenat_lock_full(dfd,
163,422✔
45
                               p,
46
                               O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY,
47
                               /* xopen_flags= */ 0,
48
                               0600,
49
                               LOCK_UNPOSIX,
50
                               operation);
51
        if (fd < 0)
163,422✔
52
                return fd == -EAGAIN ? -EBUSY : fd;
3✔
53

54
        *ret = (LockFile) {
163,419✔
55
                .dir_fd = TAKE_FD(dfd),
163,419✔
56
                .path = TAKE_PTR(t),
163,419✔
57
                .fd = TAKE_FD(fd),
163,419✔
58
                .operation = operation,
59
        };
60

61
        return 0;
163,419✔
62
}
63

64
int make_lock_file_for(const char *p, int operation, LockFile *ret) {
857✔
65
        _cleanup_free_ char *fn = NULL, *dn = NULL, *t = NULL;
857✔
66
        int r;
857✔
67

68
        assert(p);
857✔
69
        assert(ret);
857✔
70

71
        r = path_split_prefix_filename(p, &dn, &fn);
857✔
72
        if (r < 0)
857✔
73
                return r;
74

75
        if (dn)
857✔
76
                t = strjoin(dn, "/.#", fn, ".lck");
857✔
77
        else
UNCOV
78
                t = strjoin(".#", fn, ".lck");
×
79
        if (!t)
857✔
80
                return -ENOMEM;
81

82
        return make_lock_file(t, operation, ret);
857✔
83
}
84

85
void release_lock_file(LockFile *f) {
325,802✔
86
        if (!f)
325,802✔
87
                return;
88

89
        if (f->path) {
325,802✔
90

91
                /* If we are the exclusive owner we can safely delete
92
                 * the lock file itself. If we are not the exclusive
93
                 * owner, we can try becoming it. */
94

95
                if (f->fd >= 0 &&
162,929✔
96
                    (f->operation & ~LOCK_NB) == LOCK_SH &&
163,647✔
97
                    unposix_lock(f->fd, LOCK_EX|LOCK_NB) >= 0)
718✔
98
                        f->operation = LOCK_EX|LOCK_NB;
717✔
99

100
                if ((f->operation & ~LOCK_NB) == LOCK_EX)
162,929✔
101
                        (void) unlinkat(f->dir_fd, f->path, 0);
162,928✔
102

103
                f->path = mfree(f->path);
162,929✔
104
        }
105

106
        f->dir_fd = safe_close(f->dir_fd);
325,802✔
107
        f->fd = safe_close(f->fd);
325,802✔
108
        f->operation = 0;
325,802✔
109
}
110

111
static int fcntl_lock(int fd, int operation, bool ofd) {
165,546✔
112
        int cmd, type, r;
165,546✔
113

114
        assert(fd >= 0);
165,546✔
115

116
        if (ofd)
165,546✔
117
                cmd = (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW;
164,977✔
118
        else
119
                cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW;
569✔
120

121
        switch (operation & ~LOCK_NB) {
165,546✔
122
                case LOCK_EX:
123
                        type = F_WRLCK;
124
                        break;
125
                case LOCK_SH:
758✔
126
                        type = F_RDLCK;
758✔
127
                        break;
758✔
128
                case LOCK_UN:
284✔
129
                        type = F_UNLCK;
284✔
130
                        break;
284✔
UNCOV
131
                default:
×
132
                        assert_not_reached();
×
133
        }
134

135
        r = RET_NERRNO(fcntl(fd, cmd, &(struct flock) {
165,546✔
136
                .l_type = type,
137
                .l_whence = SEEK_SET,
138
                .l_start = 0,
139
                .l_len = 0,
140
        }));
141

142
        /* If we are doing non-blocking operations, treat EACCES/EAGAIN the same as per man page. But if
143
         * not, propagate EACCES back, as it will likely be due to an LSM denying the operation (for example
144
         * LXC with AppArmor when running on kernel < 6.2), and in some cases we want to gracefully
145
         * fallback (e.g.: PrivateNetwork=yes). As per documentation, it's only the non-blocking operation
146
         * F_SETLK that might return EACCES on some platforms (although the Linux implementation doesn't
147
         * seem to), as F_SETLKW and F_OFD_SETLKW block so this is not an issue, and F_OFD_SETLK is documented
148
         * to only return EAGAIN if the lock is already held. */
149
        if ((operation & LOCK_NB) && r == -EACCES)
165,546✔
UNCOV
150
                r = -EAGAIN;
×
151

152
        return r;
165,546✔
153
}
154

155
int posix_lock(int fd, int operation) {
330✔
156
        return fcntl_lock(fd, operation, /* ofd= */ false);
330✔
157
}
158

159
int unposix_lock(int fd, int operation) {
164,977✔
160
        return fcntl_lock(fd, operation, /* ofd= */ true);
164,977✔
161
}
162

163
void posix_unlockpp(int **fd) {
239✔
164
        assert(fd);
239✔
165

166
        if (!*fd || **fd < 0)
239✔
167
                return;
168

169
        (void) fcntl_lock(**fd, LOCK_UN, /* ofd= */ false);
239✔
170
        *fd = NULL;
239✔
171
}
172

UNCOV
173
void unposix_unlockpp(int **fd) {
×
174
        assert(fd);
×
175

UNCOV
176
        if (!*fd || **fd < 0)
×
177
                return;
178

UNCOV
179
        (void) fcntl_lock(**fd, LOCK_UN, /* ofd= */ true);
×
180
        *fd = NULL;
×
181
}
182

183
int lock_generic(int fd, LockType type, int operation) {
204,437✔
184
        assert(fd >= 0);
204,437✔
185

186
        switch (type) {
204,437✔
187
        case LOCK_NONE:
188
                return 0;
189
        case LOCK_BSD:
3,190✔
190
                return RET_NERRNO(flock(fd, operation));
3,190✔
191
        case LOCK_POSIX:
1✔
192
                return posix_lock(fd, operation);
1✔
193
        case LOCK_UNPOSIX:
163,948✔
194
                return unposix_lock(fd, operation);
163,948✔
UNCOV
195
        default:
×
196
                assert_not_reached();
×
197
        }
198
}
199

200
int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeout) {
541✔
201
        int r;
541✔
202

203
        assert(fd >= 0);
541✔
204

205
        /* A version of lock_generic(), but with a timeout. We do this in a child process, since the kernel
206
         * APIs natively don't support a timeout. We set a SIGALRM timer that will kill the child after the
207
         * timeout is hit. Returns -ETIMEDOUT if the timeout is hit, and 0 on success.
208
         *
209
         * This only works for BSD and UNPOSIX locks, as only those are fd-bound, and hence can be acquired
210
         * from any process that has access to the fd. POSIX locks OTOH are process-bound, and hence if we'd
211
         * acquire them in a child process they'd remain unlocked in the parent. */
212

213
        if (type == LOCK_NONE)
541✔
214
                return 0;
541✔
215
        if (!IN_SET(type, LOCK_BSD, LOCK_UNPOSIX)) /* Not for POSIX locks, see above. */
541✔
216
                return -EOPNOTSUPP;
217

218
        /* First, try without forking anything off */
219
        r = lock_generic(fd, type, operation | (timeout == USEC_INFINITY ? 0 : LOCK_NB));
1,082✔
220
        if (r != -EAGAIN || timeout == 0 || FLAGS_SET(operation, LOCK_NB))
541✔
221
                return r;
222

223
        /* If that didn't work, try with a child */
224
        _cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
524✔
225
        r = pidref_safe_fork("(sd-flock)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pidref);
524✔
226
        if (r < 0)
1,046✔
UNCOV
227
                return log_error_errno(r, "Failed to flock block device in child process: %m");
×
228
        if (r == 0) {
1,046✔
229
                if (lock_generic(fd, type, operation) < 0) {
522✔
UNCOV
230
                        log_error_errno(errno, "Unable to get an exclusive lock on the device: %m");
×
UNCOV
231
                        _exit(EXIT_FAILURE);
×
232
                }
233

234
                _exit(EXIT_SUCCESS);
522✔
235
        }
236

237
        siginfo_t status;
524✔
238
        r = pidref_wait_for_terminate_full(&pidref, timeout, &status);
524✔
239
        if (r < 0)
524✔
240
                return r;
241

242
        pidref_done(&pidref);
522✔
243

244
        switch (status.si_code) {
522✔
245

246
        case CLD_EXITED:
522✔
247
                if (status.si_status != EXIT_SUCCESS)
522✔
UNCOV
248
                        return -EPROTO;
×
249

250
                return 0;
251

252
        case CLD_KILLED:
253
        case CLD_DUMPED:
254
                return -EPROTO;
255

UNCOV
256
        default:
×
UNCOV
257
                assert_not_reached();
×
258
        }
259
}
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