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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

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

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

3
#include <sys/ioctl.h>
4
#include <threads.h>
5
#include <unistd.h>
6

7
#include "errno-util.h"
8
#include "fd-util.h"
9
#include "fileio.h"
10
#include "log.h"
11
#include "macro.h"
12
#include "memory-util.h"
13
#include "missing_fs.h"
14
#include "missing_magic.h"
15
#include "mountpoint-util.h"
16
#include "parse-util.h"
17
#include "path-util.h"
18
#include "pidfd-util.h"
19
#include "process-util.h"
20
#include "stat-util.h"
21
#include "string-util.h"
22

23
static int have_pidfs = -1;
24

25
static int pidfd_check_pidfs(int pid_fd) {
39,385✔
26

27
        /* NB: the passed fd *must* be acquired via pidfd_open(), i.e. must be a true pidfd! */
28

29
        if (have_pidfs >= 0)
39,385✔
30
                return have_pidfs;
31

32
        return (have_pidfs = fd_is_fs_type(pid_fd, PID_FS_MAGIC));
18,524✔
33
}
34

35
int pidfd_get_namespace(int fd, unsigned long ns_type_cmd) {
8,138✔
36
        static bool cached_supported = true;
8,138✔
37

38
        /* Obtain the namespace fd from pidfd directly through ioctl(PIDFD_GET_*_NAMESPACE).
39
         *
40
         * Returns -EOPNOTSUPP if ioctl on pidfds are not supported, -ENOPKG if the requested namespace
41
         * is disabled in kernel. (The errno used are different from what kernel returns via ioctl(),
42
         * see below) */
43

44
        assert(fd >= 0);
8,138✔
45

46
        /* If we know ahead of time that pidfs is unavailable, shortcut things. But otherwise we don't
47
         * call pidfd_check_pidfs() here, which is kinda extraneous and our own cache is required
48
         * anyways (pidfs is introduced in kernel 6.9 while ioctl support there is added in 6.11). */
49
        if (have_pidfs == 0 || !cached_supported)
8,138✔
50
                return -EOPNOTSUPP;
51

52
        int nsfd = ioctl(fd, ns_type_cmd);
7,707✔
53
        if (nsfd < 0) {
7,707✔
54
                /* Kernel returns EOPNOTSUPP if the ns type in question is disabled. Hence we need to look
55
                 * at precise errno instead of generic ERRNO_IS_(IOCTL_)NOT_SUPPORTED. */
56
                if (IN_SET(errno, ENOTTY, EINVAL)) {
17✔
57
                        cached_supported = false;
17✔
58
                        return -EOPNOTSUPP;
17✔
59
                }
60
                if (errno == EOPNOTSUPP) /* Translate to something more recognizable */
×
61
                        return -ENOPKG;
62

63
                return -errno;
×
64
        }
65

66
        return nsfd;
67
}
68

69
static int pidfd_get_info(int fd, struct pidfd_info *info) {
51,280✔
70
        static bool cached_supported = true;
51,280✔
71

72
        assert(fd >= 0);
51,280✔
73
        assert(info);
51,280✔
74

75
        if (have_pidfs == 0 || !cached_supported)
51,280✔
76
                return -EOPNOTSUPP;
77

78
        if (ioctl(fd, PIDFD_GET_INFO, info) < 0) {
36,874✔
79
                if (ERRNO_IS_IOCTL_NOT_SUPPORTED(errno)) {
3,156✔
80
                        cached_supported = false;
2,580✔
81
                        return -EOPNOTSUPP;
2,580✔
82
                }
83

84
                return -errno;
576✔
85
        }
86

87
        return 0;
88
}
89

90
static int pidfd_get_pid_fdinfo(int fd, pid_t *ret) {
15,589✔
91
        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
15,589✔
92
        _cleanup_free_ char *fdinfo = NULL;
15,589✔
93
        int r;
15,589✔
94

95
        assert(fd >= 0);
15,589✔
96

97
        xsprintf(path, "/proc/self/fdinfo/%i", fd);
15,589✔
98

99
        r = read_full_virtual_file(path, &fdinfo, NULL);
15,589✔
100
        if (r == -ENOENT)
15,589✔
101
                return proc_fd_enoent_errno();
×
102
        if (r < 0)
15,589✔
103
                return r;
104

105
        char *p = find_line_startswith(fdinfo, "Pid:");
15,589✔
106
        if (!p)
15,589✔
107
                return -ENOTTY; /* not a pidfd? */
108

109
        p = skip_leading_chars(p, /* bad = */ NULL);
15,589✔
110
        p[strcspn(p, WHITESPACE)] = 0;
15,589✔
111

112
        if (streq(p, "0"))
15,589✔
113
                return -EREMOTE; /* PID is in foreign PID namespace? */
114
        if (streq(p, "-1"))
15,589✔
115
                return -ESRCH;   /* refers to reaped process? */
116

117
        return parse_pid(p, ret);
14,202✔
118
}
119

120
static int pidfd_get_pid_ioctl(int fd, pid_t *ret) {
48,826✔
121
        struct pidfd_info info = { .mask = PIDFD_INFO_PID };
48,826✔
122
        int r;
48,826✔
123

124
        assert(fd >= 0);
48,826✔
125

126
        r = pidfd_get_info(fd, &info);
48,826✔
127
        if (r < 0)
48,826✔
128
                return r;
48,826✔
129

130
        assert(FLAGS_SET(info.mask, PIDFD_INFO_PID));
32,661✔
131

132
        if (ret)
32,661✔
133
                *ret = info.pid;
32,661✔
134
        return 0;
135
}
136

137
int pidfd_get_pid(int fd, pid_t *ret) {
48,826✔
138
        int r;
48,826✔
139

140
        /* Converts a pidfd into a pid. We try ioctl(PIDFD_GET_INFO) (kernel 6.13+) first,
141
         * /proc/self/fdinfo/ as fallback. Well known errors:
142
         *
143
         *    -EBADF   → fd invalid
144
         *    -ESRCH   → fd valid, but process is already reaped
145
         *
146
         * pidfd_get_pid_fdinfo() might additionally fail for other reasons:
147
         *
148
         *    -ENOSYS  → /proc/ not mounted
149
         *    -ENOTTY  → fd valid, but not a pidfd
150
         *    -EREMOTE → fd valid, but pid is in another namespace we cannot translate to the local one
151
         *               (when using PIDFD_GET_INFO this is indistinguishable from -ESRCH)
152
         */
153

154
        assert(fd >= 0);
48,826✔
155

156
        r = pidfd_get_pid_ioctl(fd, ret);
48,826✔
157
        if (r != -EOPNOTSUPP)
48,826✔
158
                return r;
159

160
        return pidfd_get_pid_fdinfo(fd, ret);
15,589✔
161
}
162

163
int pidfd_verify_pid(int pidfd, pid_t pid) {
32,405✔
164
        pid_t current_pid;
32,405✔
165
        int r;
32,405✔
166

167
        assert(pidfd >= 0);
32,405✔
168
        assert(pid > 0);
32,405✔
169

170
        r = pidfd_get_pid(pidfd, &current_pid);
32,405✔
171
        if (r < 0)
32,405✔
172
                return r;
32,405✔
173

174
        return current_pid != pid ? -ESRCH : 0;
30,442✔
175
}
176

177
int pidfd_get_ppid(int fd, pid_t *ret) {
2,400✔
178
        struct pidfd_info info = { .mask = PIDFD_INFO_PID };
2,400✔
179
        int r;
2,400✔
180

181
        assert(fd >= 0);
2,400✔
182

183
        r = pidfd_get_info(fd, &info);
2,400✔
184
        if (r < 0)
2,400✔
185
                return r;
2,400✔
186

187
        assert(FLAGS_SET(info.mask, PIDFD_INFO_PID));
1,012✔
188

189
        if (info.ppid == 0) /* See comments in pid_get_ppid() */
1,012✔
190
                return -EADDRNOTAVAIL;
191

192
        if (ret)
1,012✔
193
                *ret = info.ppid;
1,012✔
194
        return 0;
195
}
196

197
int pidfd_get_uid(int fd, uid_t *ret) {
54✔
198
        struct pidfd_info info = { .mask = PIDFD_INFO_CREDS };
54✔
199
        int r;
54✔
200

201
        assert(fd >= 0);
54✔
202

203
        r = pidfd_get_info(fd, &info);
54✔
204
        if (r < 0)
54✔
205
                return r;
54✔
206

207
        assert(FLAGS_SET(info.mask, PIDFD_INFO_CREDS));
45✔
208

209
        if (ret)
45✔
210
                *ret = info.ruid;
45✔
211
        return 0;
212
}
213

214
int pidfd_get_cgroupid(int fd, uint64_t *ret) {
×
215
        struct pidfd_info info = { .mask = PIDFD_INFO_CGROUPID };
×
216
        int r;
×
217

218
        assert(fd >= 0);
×
219

220
        r = pidfd_get_info(fd, &info);
×
221
        if (r < 0)
×
222
                return r;
×
223

224
        assert(FLAGS_SET(info.mask, PIDFD_INFO_CGROUPID));
×
225

226
        if (ret)
×
227
                *ret = info.cgroupid;
×
228
        return 0;
229
}
230

231
int pidfd_get_inode_id(int fd, uint64_t *ret) {
39,385✔
232
        static bool file_handle_supported = true;
39,385✔
233
        int r;
39,385✔
234

235
        assert(fd >= 0);
39,385✔
236

237
        r = pidfd_check_pidfs(fd);
39,385✔
238
        if (r < 0)
39,385✔
239
                return r;
39,385✔
240
        if (r == 0)
39,385✔
241
                return -EOPNOTSUPP;
242

243
        if (file_handle_supported) {
39,385✔
244
                union {
37,309✔
245
                        struct file_handle file_handle;
246
                        uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)];
247
                } fh = {
37,309✔
248
                        .file_handle.handle_bytes = sizeof(uint64_t),
249
                        .file_handle.handle_type = FILEID_KERNFS,
250
                };
251
                int mnt_id;
37,309✔
252

253
                r = RET_NERRNO(name_to_handle_at(fd, "", &fh.file_handle, &mnt_id, AT_EMPTY_PATH));
37,309✔
254
                if (r >= 0) {
3,616✔
255
                        if (ret)
33,693✔
256
                                *ret = *(uint64_t*) fh.file_handle.f_handle;
33,693✔
257
                        return 0;
33,693✔
258
                }
259
                assert(r != -EOVERFLOW);
3,616✔
260
                if (is_name_to_handle_at_fatal_error(r))
3,616✔
261
                        return r;
262

263
                file_handle_supported = false;
3,616✔
264
        }
265

266
#if SIZEOF_INO_T == 8
267
        struct stat st;
5,692✔
268
        if (fstat(fd, &st) < 0)
5,692✔
269
                return -errno;
×
270

271
        if (ret)
5,692✔
272
                *ret = (uint64_t) st.st_ino;
5,692✔
273
        return 0;
274

275
#elif SIZEOF_INO_T == 4
276
        /* On 32-bit systems (where sizeof(ino_t) == 4), the inode id returned by fstat() cannot be used to
277
         * reliably identify the process, nor can we communicate the origin of the id with the clients.
278
         * Hence let's just refuse to acquire pidfdid through fstat() here. All clients shall also insist on
279
         * the 64-bit id from name_to_handle_at(). */
280
        return -EOPNOTSUPP;
281
#else
282
#  error Unsupported ino_t size
283
#endif
284
}
285

286
int pidfd_get_inode_id_self_cached(uint64_t *ret) {
38,756✔
287
        static thread_local uint64_t cached = 0;
38,756✔
288
        static thread_local pid_t initialized = 0; /* < 0: cached error; == 0: invalid; > 0: valid and pid that was current */
38,756✔
289
        int r;
38,756✔
290

291
        assert(ret);
38,756✔
292

293
        if (initialized == getpid_cached()) {
38,756✔
294
                *ret = cached;
4,676✔
295
                return 0;
4,676✔
296
        }
297
        if (initialized < 0)
34,080✔
298
                return initialized;
299

300
        _cleanup_close_ int fd = pidfd_open(getpid_cached(), 0);
72,836✔
301
        if (fd < 0)
34,080✔
302
                return -errno;
×
303

304
        r = pidfd_get_inode_id(fd, &cached);
34,080✔
305
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
34,080✔
306
                return (initialized = -EOPNOTSUPP);
×
307
        if (r < 0)
34,080✔
308
                return r;
309

310
        *ret = cached;
34,080✔
311
        initialized = getpid_cached();
34,080✔
312
        return 0;
34,080✔
313
}
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