• 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

94.23
/src/test/test-process-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <linux/oom.h>
5
#include <pthread.h>
6
#include <sys/eventfd.h>
7
#include <sys/mount.h>
8
#include <sys/personality.h>
9
#include <sys/prctl.h>
10
#include <sys/stat.h>
11
#include <sys/types.h>
12
#include <sys/wait.h>
13
#include <unistd.h>
14
#if HAVE_VALGRIND_VALGRIND_H
15
#include <valgrind/valgrind.h>
16
#endif
17

18
#include "alloc-util.h"
19
#include "architecture.h"
20
#include "dirent-util.h"
21
#include "errno-list.h"
22
#include "errno-util.h"
23
#include "fd-util.h"
24
#include "ioprio-util.h"
25
#include "log.h"
26
#include "macro.h"
27
#include "missing_sched.h"
28
#include "missing_syscall.h"
29
#include "namespace-util.h"
30
#include "parse-util.h"
31
#include "pidfd-util.h"
32
#include "process-util.h"
33
#include "procfs-util.h"
34
#include "rlimit-util.h"
35
#include "signal-util.h"
36
#include "stdio-util.h"
37
#include "string-util.h"
38
#include "terminal-util.h"
39
#include "tests.h"
40
#include "user-util.h"
41
#include "virt.h"
42

43
static void test_pid_get_comm_one(pid_t pid) {
2✔
44
        struct stat st;
2✔
45
        _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
×
46
        _cleanup_free_ char *env = NULL;
×
47
        char path[STRLEN("/proc//comm") + DECIMAL_STR_MAX(pid_t)];
2✔
48
        pid_t e;
2✔
49
        uid_t u;
2✔
50
        gid_t g;
2✔
51
        dev_t h;
2✔
52
        int r;
2✔
53

54
        log_info("/* %s */", __func__);
2✔
55

56
        xsprintf(path, "/proc/"PID_FMT"/comm", pid);
2✔
57

58
        if (stat(path, &st) == 0) {
2✔
59
                ASSERT_OK(pid_get_comm(pid, &a));
2✔
60
                log_info("PID"PID_FMT" comm: '%s'", pid, a);
2✔
61
        } else
62
                log_warning("%s not exist.", path);
×
63

64
        ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
2✔
65
        log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
2✔
66

67
        ASSERT_OK(pid_get_cmdline(pid, 8, 0, &d));
2✔
68
        log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
2✔
69

70
        free(d);
2✔
71
        ASSERT_OK(pid_get_cmdline(pid, 1, 0, &d));
2✔
72
        log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
2✔
73

74
        r = pid_get_ppid(pid, &e);
2✔
75
        if (pid == 1)
2✔
76
                ASSERT_ERROR(r, EADDRNOTAVAIL);
1✔
77
        else
78
                ASSERT_OK(r);
1✔
79
        if (r >= 0) {
1✔
80
                log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
1✔
81
                ASSERT_GT(e, 0);
1✔
82
        }
83

84
        ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
2✔
85

86
        r = get_process_exe(pid, &f);
2✔
87
        if (r != -EACCES)
2✔
88
                ASSERT_OK(r);
2✔
89
        log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
2✔
90

91
        ASSERT_OK_ZERO(pid_get_uid(pid, &u));
2✔
92
        log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
2✔
93

94
        ASSERT_OK_ZERO(get_process_gid(pid, &g));
2✔
95
        log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
2✔
96

97
        r = get_process_environ(pid, &env);
2✔
98
        if (r != -EACCES)
2✔
99
                ASSERT_OK(r);
2✔
100
        log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
2✔
101

102
        if (!detect_container() && pid == 1)
2✔
103
                ASSERT_ERROR(get_ctty_devnr(pid, &h), ENXIO);
×
104

105
        (void) getenv_for_pid(pid, "PATH", &i);
2✔
106
        log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
2✔
107
}
2✔
108

109
TEST(pid_get_comm) {
1✔
110
        if (saved_argc > 1) {
1✔
111
                pid_t pid = 0;
×
112

113
                (void) parse_pid(saved_argv[1], &pid);
×
114
                test_pid_get_comm_one(pid);
×
115
        } else {
116
                TEST_REQ_RUNNING_SYSTEMD(test_pid_get_comm_one(1));
1✔
117
                test_pid_get_comm_one(getpid());
1✔
118
        }
119
}
1✔
120

121
static void test_pid_get_cmdline_one(pid_t pid) {
44✔
122
        _cleanup_free_ char *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL, *h = NULL, *joined = NULL;
×
123
        _cleanup_strv_free_ char **strv_a = NULL, **strv_b = NULL;
44✔
124
        int r;
44✔
125

126
        r = pid_get_cmdline(pid, SIZE_MAX, 0, &c);
44✔
127
        log_info("PID "PID_FMT": %s", pid, r >= 0 ? c : errno_to_name(r));
44✔
128

129
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &d);
44✔
130
        log_info("      %s", r >= 0 ? d : errno_to_name(r));
44✔
131

132
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &e);
44✔
133
        log_info("      %s", r >= 0 ? e : errno_to_name(r));
44✔
134

135
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE | PROCESS_CMDLINE_COMM_FALLBACK, &f);
44✔
136
        log_info("      %s", r >= 0 ? f : errno_to_name(r));
44✔
137

138
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &g);
44✔
139
        log_info("      %s", r >= 0 ? g : errno_to_name(r));
44✔
140

141
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX | PROCESS_CMDLINE_COMM_FALLBACK, &h);
44✔
142
        log_info("      %s", r >= 0 ? h : errno_to_name(r));
44✔
143

144
        r = pid_get_cmdline_strv(pid, 0, &strv_a);
44✔
145
        if (r >= 0)
44✔
146
                ASSERT_NOT_NULL((joined = strv_join(strv_a, "\", \"")));
44✔
147
        log_info("      \"%s\"", r >= 0 ? joined : errno_to_name(r));
44✔
148

149
        joined = mfree(joined);
44✔
150

151
        r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
44✔
152
        if (r >= 0)
44✔
153
                ASSERT_NOT_NULL((joined = strv_join(strv_b, "\", \"")));
44✔
154
        log_info("      \"%s\"", r >= 0 ? joined : errno_to_name(r));
44✔
155
}
44✔
156

157
TEST(pid_get_cmdline) {
1✔
158
        _cleanup_closedir_ DIR *d = NULL;
2✔
159
        int r;
1✔
160

161
        ASSERT_OK(proc_dir_open(&d));
1✔
162

163
        for (;;) {
44✔
164
                pid_t pid;
45✔
165

166
                r = proc_dir_read(d, &pid);
45✔
167
                ASSERT_OK(r);
45✔
168

169
                if (r == 0) /* EOF */
45✔
170
                        break;
171

172
                test_pid_get_cmdline_one(pid);
44✔
173
        }
174
}
1✔
175

176
static void test_pid_get_comm_escape_one(const char *input, const char *output) {
10✔
177
        _cleanup_free_ char *n = NULL;
20✔
178

179
        log_debug("input: <%s> — output: <%s>", input, output);
10✔
180

181
        ASSERT_OK_ERRNO(prctl(PR_SET_NAME, input));
10✔
182
        ASSERT_OK(pid_get_comm(0, &n));
10✔
183

184
        log_debug("got: <%s>", n);
10✔
185

186
        ASSERT_STREQ(n, output);
10✔
187
}
10✔
188

189
TEST(pid_get_comm_escape) {
1✔
190
        _cleanup_free_ char *saved = NULL;
2✔
191

192
        ASSERT_OK(pid_get_comm(0, &saved));
1✔
193

194
        test_pid_get_comm_escape_one("", "");
1✔
195
        test_pid_get_comm_escape_one("foo", "foo");
1✔
196
        test_pid_get_comm_escape_one("012345678901234", "012345678901234");
1✔
197
        test_pid_get_comm_escape_one("0123456789012345", "012345678901234");
1✔
198
        test_pid_get_comm_escape_one("äöüß", "\\303\\244\\303\\266\\303\\274\\303\\237");
1✔
199
        test_pid_get_comm_escape_one("xäöüß", "x\\303\\244\\303\\266\\303\\274\\303\\237");
1✔
200
        test_pid_get_comm_escape_one("xxäöüß", "xx\\303\\244\\303\\266\\303\\274\\303\\237");
1✔
201
        test_pid_get_comm_escape_one("xxxäöüß", "xxx\\303\\244\\303\\266\\303\\274\\303\\237");
1✔
202
        test_pid_get_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
1✔
203
        test_pid_get_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
1✔
204

205
        ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
1✔
206
}
1✔
207

208
TEST(pid_is_unwaited) {
1✔
209
        pid_t pid;
1✔
210

211
        pid = fork();
1✔
212
        ASSERT_OK_ERRNO(pid);
2✔
213
        if (pid == 0) {
2✔
214
                _exit(EXIT_SUCCESS);
1✔
215
        } else {
216
                int status;
1✔
217

218
                ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
1✔
219
                ASSERT_OK_ZERO(pid_is_unwaited(pid));
1✔
220
        }
221
        ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
1✔
222
        ASSERT_FAIL(pid_is_unwaited(-1));
1✔
223
}
1✔
224

225
TEST(pid_is_alive) {
1✔
226
        pid_t pid;
1✔
227

228
        pid = fork();
1✔
229
        ASSERT_OK_ERRNO(pid);
2✔
230
        if (pid == 0) {
2✔
231
                _exit(EXIT_SUCCESS);
1✔
232
        } else {
233
                int status;
1✔
234

235
                ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
1✔
236
                ASSERT_OK_ZERO(pid_is_alive(pid));
1✔
237
        }
238
        ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
1✔
239
        ASSERT_FAIL(pid_is_alive(-1));
1✔
240
}
1✔
241

242
TEST(personality) {
1✔
243
        ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
1✔
244
        ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
1✔
245

246
        ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
1✔
247

248
        ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX)), (unsigned long) PER_LINUX);
1✔
249
        ASSERT_EQ(personality_from_string(architecture_to_string(native_architecture())), (unsigned long) PER_LINUX);
1✔
250

251
#ifdef __x86_64__
252
        ASSERT_STREQ(personality_to_string(PER_LINUX), "x86-64");
1✔
253
        ASSERT_STREQ(personality_to_string(PER_LINUX32), "x86");
1✔
254

255
        ASSERT_EQ(personality_from_string("x86-64"), (unsigned long) PER_LINUX);
1✔
256
        ASSERT_EQ(personality_from_string("x86"), (unsigned long) PER_LINUX32);
1✔
257
        ASSERT_EQ(personality_from_string("ia64"), PERSONALITY_INVALID);
1✔
258
        ASSERT_EQ(personality_from_string(NULL), PERSONALITY_INVALID);
1✔
259

260
        ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32)), (unsigned long) PER_LINUX32);
1✔
261
#endif
262
}
1✔
263

264
TEST(pid_get_cmdline_harder) {
1✔
265
        char path[] = "/tmp/test-cmdlineXXXXXX";
1✔
266
        _cleanup_close_ int fd = -EBADF;
1✔
267
        _cleanup_free_ char *line = NULL;
1✔
268
        _cleanup_strv_free_ char **args = NULL;
×
269
        pid_t pid;
1✔
270
        int r;
1✔
271

272
        if (geteuid() != 0) {
1✔
273
                log_info("Skipping %s: not root", __func__);
×
274
                return;
×
275
        }
276

277
        if (!have_namespaces()) {
1✔
278
                log_notice("Testing without namespaces, skipping %s", __func__);
×
279
                return;
×
280
        }
281

282
#if HAVE_VALGRIND_VALGRIND_H
283
        /* valgrind patches open(/proc//cmdline)
284
         * so, test_pid_get_cmdline_harder fails always
285
         * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
286
        if (RUNNING_ON_VALGRIND) {
287
                log_info("Skipping %s: running on valgrind", __func__);
288
                return;
289
        }
290
#endif
291

292
        pid = fork();
1✔
293
        if (pid > 0) {
2✔
294
                siginfo_t si;
1✔
295

296
                (void) wait_for_terminate(pid, &si);
1✔
297

298
                ASSERT_EQ(si.si_code, CLD_EXITED);
1✔
299
                ASSERT_OK_ZERO(si.si_status);
1✔
300

301
                return;
1✔
302
        }
303

304
        ASSERT_OK_ZERO(pid);
1✔
305

306
        r = detach_mount_namespace();
1✔
307
        if (r < 0) {
1✔
308
                log_warning_errno(r, "detach mount namespace failed: %m");
×
309
                if (!ERRNO_IS_PRIVILEGE(r))
×
310
                        ASSERT_OK(r);
×
311
                return;
312
        }
313

314
        fd = mkostemp(path, O_CLOEXEC);
1✔
315
        ASSERT_OK_ERRNO(fd);
1✔
316

317
        /* Note that we don't unmount the following bind-mount at the end of the test because the kernel
318
         * will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
319
        if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
1✔
320
                /* This happens under selinux… Abort the test in this case. */
321
                log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
×
322
                ASSERT_TRUE(IN_SET(errno, EPERM, EACCES));
1✔
323
                return;
324
        }
325

326
        /* Set RLIMIT_STACK to infinity to test we don't try to allocate unnecessarily large values to read
327
         * the cmdline. */
328
        if (setrlimit(RLIMIT_STACK, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
1✔
329
                log_warning("Testing without RLIMIT_STACK=infinity");
×
330

331
        ASSERT_OK_ERRNO(unlink(path));
1✔
332

333
        ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
1✔
334

335
        ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
1✔
336

337
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
338
        log_debug("'%s'", line);
1✔
339
        ASSERT_STREQ(line, "[testa]");
1✔
340
        line = mfree(line);
1✔
341

342
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
1✔
343
        log_debug("'%s'", line);
1✔
344
        ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
1✔
345
        line = mfree(line);
1✔
346

347
        ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
348
        log_debug("'%s'", line);
1✔
349
        ASSERT_STREQ(line, "");
1✔
350
        line = mfree(line);
1✔
351

352
        ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
353
        ASSERT_STREQ(line, "…");
1✔
354
        line = mfree(line);
1✔
355

356
        ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
357
        ASSERT_STREQ(line, "[…");
1✔
358
        line = mfree(line);
1✔
359

360
        ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
361
        ASSERT_STREQ(line, "[t…");
1✔
362
        line = mfree(line);
1✔
363

364
        ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
365
        ASSERT_STREQ(line, "[te…");
1✔
366
        line = mfree(line);
1✔
367

368
        ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
369
        ASSERT_STREQ(line, "[tes…");
1✔
370
        line = mfree(line);
1✔
371

372
        ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
373
        ASSERT_STREQ(line, "[test…");
1✔
374
        line = mfree(line);
1✔
375

376
        ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
377
        ASSERT_STREQ(line, "[testa]");
1✔
378
        line = mfree(line);
1✔
379

380
        ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
381
        ASSERT_STREQ(line, "[testa]");
1✔
382
        line = mfree(line);
1✔
383

384
        ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
385
        ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
1✔
386
        args = strv_free(args);
1✔
387

388
        /* Test with multiple arguments that don't require quoting */
389

390
        ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
1✔
391

392
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
1✔
393
        log_debug("'%s'", line);
1✔
394
        ASSERT_STREQ(line, "foo bar");
1✔
395
        line = mfree(line);
1✔
396

397
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
398
        ASSERT_STREQ(line, "foo bar");
1✔
399
        line = mfree(line);
1✔
400

401
        ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
402
        ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
1✔
403
        args = strv_free(args);
1✔
404

405
        ASSERT_OK_EQ_ERRNO(write(fd, "quux", 4), 4);
1✔
406
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
1✔
407
        log_debug("'%s'", line);
1✔
408
        ASSERT_STREQ(line, "foo bar quux");
1✔
409
        line = mfree(line);
1✔
410

411
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
412
        log_debug("'%s'", line);
1✔
413
        ASSERT_STREQ(line, "foo bar quux");
1✔
414
        line = mfree(line);
1✔
415

416
        ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
417
        log_debug("'%s'", line);
1✔
418
        ASSERT_STREQ(line, "…");
1✔
419
        line = mfree(line);
1✔
420

421
        ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
422
        log_debug("'%s'", line);
1✔
423
        ASSERT_STREQ(line, "f…");
1✔
424
        line = mfree(line);
1✔
425

426
        ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
427
        log_debug("'%s'", line);
1✔
428
        ASSERT_STREQ(line, "fo…");
1✔
429
        line = mfree(line);
1✔
430

431
        ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
432
        log_debug("'%s'", line);
1✔
433
        ASSERT_STREQ(line, "foo…");
1✔
434
        line = mfree(line);
1✔
435

436
        ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
437
        log_debug("'%s'", line);
1✔
438
        ASSERT_STREQ(line, "foo …");
1✔
439
        line = mfree(line);
1✔
440

441
        ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
442
        log_debug("'%s'", line);
1✔
443
        ASSERT_STREQ(line, "foo b…");
1✔
444
        line = mfree(line);
1✔
445

446
        ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
447
        log_debug("'%s'", line);
1✔
448
        ASSERT_STREQ(line, "foo ba…");
1✔
449
        line = mfree(line);
1✔
450

451
        ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
452
        log_debug("'%s'", line);
1✔
453
        ASSERT_STREQ(line, "foo bar…");
1✔
454
        line = mfree(line);
1✔
455

456
        ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
457
        log_debug("'%s'", line);
1✔
458
        ASSERT_STREQ(line, "foo bar …");
1✔
459
        line = mfree(line);
1✔
460

461
        ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
462
        log_debug("'%s'", line);
1✔
463
        ASSERT_STREQ(line, "foo bar q…");
1✔
464
        line = mfree(line);
1✔
465

466
        ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
467
        log_debug("'%s'", line);
1✔
468
        ASSERT_STREQ(line, "foo bar qu…");
1✔
469
        line = mfree(line);
1✔
470

471
        ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
472
        log_debug("'%s'", line);
1✔
473
        ASSERT_STREQ(line, "foo bar quux");
1✔
474
        line = mfree(line);
1✔
475

476
        ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
477
        log_debug("'%s'", line);
1✔
478
        ASSERT_STREQ(line, "foo bar quux");
1✔
479
        line = mfree(line);
1✔
480

481
        ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
482
        log_debug("'%s'", line);
1✔
483
        ASSERT_STREQ(line, "foo bar quux");
1✔
484
        line = mfree(line);
1✔
485

486
        ASSERT_OK(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
487
        log_debug("'%s'", line);
1✔
488
        ASSERT_STREQ(line, "foo bar quux");
1✔
489
        line = mfree(line);
1✔
490

491
        ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
492
        ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
1✔
493
        args = strv_free(args);
1✔
494

495
        ASSERT_OK_ERRNO(ftruncate(fd, 0));
1✔
496
        ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
1✔
497

498
        ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
1✔
499

500
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
501
        log_debug("'%s'", line);
1✔
502
        ASSERT_STREQ(line, "[aaaa bbbb cccc]");
1✔
503
        line = mfree(line);
1✔
504

505
        ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
506
        log_debug("'%s'", line);
1✔
507
        ASSERT_STREQ(line, "[aaaa bbb…");
1✔
508
        line = mfree(line);
1✔
509

510
        ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
511
        log_debug("'%s'", line);
1✔
512
        ASSERT_STREQ(line, "[aaaa bbbb…");
1✔
513
        line = mfree(line);
1✔
514

515
        ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
516
        log_debug("'%s'", line);
1✔
517
        ASSERT_STREQ(line, "[aaaa bbbb …");
1✔
518
        line = mfree(line);
1✔
519

520
        ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
521
        ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
1✔
522
        args = strv_free(args);
1✔
523

524
        /* Test with multiple arguments that do require quoting */
525

526
#define CMDLINE1 "foo\0'bar'\0\"bar$\"\0x y z\0!``\0"
527
#define EXPECT1  "foo \"'bar'\" \"\\\"bar\\$\\\"\" \"x y z\" \"!\\`\\`\""
528
#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
529
#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
530

531
        ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
1✔
532
        ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
1✔
533
        ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
1✔
534

535
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
1✔
536
        log_debug("got: ==%s==", line);
1✔
537
        log_debug("exp: ==%s==", EXPECT1);
1✔
538
        ASSERT_STREQ(line, EXPECT1);
1✔
539
        line = mfree(line);
1✔
540

541
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
1✔
542
        log_debug("got: ==%s==", line);
1✔
543
        log_debug("exp: ==%s==", EXPECT1p);
1✔
544
        ASSERT_STREQ(line, EXPECT1p);
1✔
545
        line = mfree(line);
1✔
546

547
        ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
1✔
548
        ASSERT_TRUE(strv_equal(args, EXPECT1v));
1✔
549
        args = strv_free(args);
1✔
550

551
#define CMDLINE2 "foo\0\1\2\3\0\0"
552
#define EXPECT2  "foo \"\\001\\002\\003\""
553
#define EXPECT2p "foo $'\\001\\002\\003'"
554
#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
555

556
        ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
1✔
557
        ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
1✔
558
        ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));
1✔
559

560
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
1✔
561
        log_debug("got: ==%s==", line);
1✔
562
        log_debug("exp: ==%s==", EXPECT2);
1✔
563
        ASSERT_STREQ(line, EXPECT2);
1✔
564
        line = mfree(line);
1✔
565

566
        ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
1✔
567
        log_debug("got: ==%s==", line);
1✔
568
        log_debug("exp: ==%s==", EXPECT2p);
1✔
569
        ASSERT_STREQ(line, EXPECT2p);
1✔
570
        line = mfree(line);
1✔
571

572
        ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
1✔
573
        ASSERT_TRUE(strv_equal(args, EXPECT2v));
1✔
574
        args = strv_free(args);
1✔
575

576
        safe_close(fd);
1✔
577
        _exit(EXIT_SUCCESS);
1✔
578
}
579

580
TEST(getpid_cached) {
1✔
581
        siginfo_t si;
1✔
582
        pid_t a, b, c, d, e, f, child;
1✔
583

584
        a = getpid();
1✔
585
        b = getpid_cached();
1✔
586
        c = getpid();
1✔
587

588
        ASSERT_EQ(a, b);
1✔
589
        ASSERT_EQ(a, c);
1✔
590

591
        child = fork();
1✔
592
        ASSERT_OK_ERRNO(child);
2✔
593

594
        if (child == 0) {
2✔
595
                /* In child */
596
                a = getpid();
1✔
597
                b = getpid_cached();
1✔
598
                c = getpid();
1✔
599

600
                ASSERT_EQ(a, b);
1✔
601
                ASSERT_EQ(a, c);
1✔
602
                _exit(EXIT_SUCCESS);
1✔
603
        }
604

605
        d = getpid();
1✔
606
        e = getpid_cached();
1✔
607
        f = getpid();
1✔
608

609
        ASSERT_EQ(a, d);
1✔
610
        ASSERT_EQ(a, e);
1✔
611
        ASSERT_EQ(a, f);
1✔
612

613
        ASSERT_OK(wait_for_terminate(child, &si));
1✔
614
        ASSERT_EQ(si.si_status, 0);
1✔
615
        ASSERT_EQ(si.si_code, CLD_EXITED);
1✔
616
}
1✔
617

618
TEST(getpid_measure) {
1✔
619
        usec_t t, q;
1✔
620

621
        unsigned long long iterations = slow_tests_enabled() ? 1000000 : 1000;
1✔
622

623
        log_info("/* %s (%llu iterations) */", __func__, iterations);
1✔
624

625
        t = now(CLOCK_MONOTONIC);
1✔
626
        for (unsigned long long i = 0; i < iterations; i++)
1,001✔
627
                (void) getpid();
1,000✔
628
        q = now(CLOCK_MONOTONIC) - t;
1✔
629

630
        log_info(" glibc getpid(): %lf μs each", (double) q / iterations);
1✔
631

632
        iterations *= 50; /* _cached() is about 50 times faster, so we need more iterations */
1✔
633

634
        t = now(CLOCK_MONOTONIC);
1✔
635
        for (unsigned long long i = 0; i < iterations; i++)
50,001✔
636
                (void) getpid_cached();
50,000✔
637
        q = now(CLOCK_MONOTONIC) - t;
1✔
638

639
        log_info("getpid_cached(): %lf μs each", (double) q / iterations);
1✔
640
}
1✔
641

642
TEST(safe_fork) {
1✔
643
        siginfo_t status;
1✔
644
        pid_t pid;
1✔
645
        int r;
1✔
646

647
        BLOCK_SIGNALS(SIGCHLD);
2✔
648

649
        r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
1✔
650
        ASSERT_OK(r);
2✔
651

652
        if (r == 0) {
2✔
653
                /* child */
654
                usleep_safe(100 * USEC_PER_MSEC);
1✔
655

656
                _exit(88);
1✔
657
        }
658

659
        ASSERT_OK(wait_for_terminate(pid, &status));
1✔
660
        ASSERT_EQ(status.si_code, CLD_EXITED);
1✔
661
        ASSERT_EQ(status.si_status, 88);
1✔
662

663
        _cleanup_(pidref_done) PidRef child = PIDREF_NULL;
1✔
664
        r = pidref_safe_fork("(test-child)", FORK_DETACH, &child);
1✔
665
        if (r == 0) {
1✔
666
                /* Don't freeze so this doesn't linger around forever in case something goes wrong. */
667
                usleep_safe(100 * USEC_PER_SEC);
×
668
                _exit(EXIT_SUCCESS);
×
669
        }
670

671
        ASSERT_OK_POSITIVE(r);
1✔
672
        ASSERT_GT(child.pid, 0);
1✔
673
        ASSERT_OK(pidref_get_ppid(&child, &pid));
1✔
674
        ASSERT_OK(pidref_kill(&child, SIGKILL));
1✔
675

676
        if (is_reaper_process())
1✔
677
                ASSERT_EQ(pid, getpid_cached());
×
678
        else
679
                ASSERT_NE(pid, getpid_cached());
1✔
680
}
1✔
681

682
TEST(pid_to_ptr) {
1✔
683
        ASSERT_EQ(PTR_TO_PID(NULL), 0);
1✔
684
        ASSERT_NULL(PID_TO_PTR(0));
1✔
685

686
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
1✔
687
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
1✔
688
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
1✔
689
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
1✔
690

691
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
1✔
692
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
1✔
693

694
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
1✔
695
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
1✔
696
}
1✔
697

698
static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
10✔
699
        ASSERT_EQ(ioprio_class_from_string(val), expected);
10✔
700
        if (expected >= 0) {
10✔
701
                _cleanup_free_ char *s = NULL;
7✔
702
                unsigned ret;
7✔
703
                int combined;
7✔
704

705
                ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
7✔
706
                /* We sometimes get a class number and sometimes a name back */
707
                ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
9✔
708

709
                /* Make sure normalization works, i.e. NONE → BE gets normalized */
710
                combined = ioprio_normalize(ioprio_prio_value(expected, 0));
7✔
711
                ASSERT_EQ(ioprio_prio_class(combined), normalized);
7✔
712
                ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
7✔
713
        }
714
}
10✔
715

716
TEST(ioprio_class_from_to_string) {
1✔
717
        test_ioprio_class_from_to_string_one("none", IOPRIO_CLASS_NONE, IOPRIO_CLASS_BE);
1✔
718
        test_ioprio_class_from_to_string_one("realtime", IOPRIO_CLASS_RT, IOPRIO_CLASS_RT);
1✔
719
        test_ioprio_class_from_to_string_one("best-effort", IOPRIO_CLASS_BE, IOPRIO_CLASS_BE);
1✔
720
        test_ioprio_class_from_to_string_one("idle", IOPRIO_CLASS_IDLE, IOPRIO_CLASS_IDLE);
1✔
721
        test_ioprio_class_from_to_string_one("0", IOPRIO_CLASS_NONE, IOPRIO_CLASS_BE);
1✔
722
        test_ioprio_class_from_to_string_one("1", 1, 1);
1✔
723
        test_ioprio_class_from_to_string_one("7", 7, 7);
1✔
724
        test_ioprio_class_from_to_string_one("8", -EINVAL, -EINVAL);
1✔
725
        test_ioprio_class_from_to_string_one("9", -EINVAL, -EINVAL);
1✔
726
        test_ioprio_class_from_to_string_one("-1", -EINVAL, -EINVAL);
1✔
727
}
1✔
728

729
TEST(setpriority_closest) {
1✔
730
        int r;
1✔
731

732
        r = safe_fork("(test-setprio)",
1✔
733
                      FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
734
        ASSERT_OK(r);
2✔
735

736
        if (r == 0) {
2✔
737
                bool full_test;
1✔
738
                int p, q;
1✔
739
                /* child */
740

741
                /* rlimit of 30 equals nice level of -10 */
742
                if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
1✔
743
                        /* If this fails we are probably unprivileged or in a userns of some kind, let's skip
744
                         * the full test */
745
                        if (!ERRNO_IS_PRIVILEGE(errno))
×
746
                                ASSERT_OK_ERRNO(-1);
×
747
                        full_test = false;
748
                } else {
749
                        /* However, if the hard limit was above 30, setrlimit would succeed unprivileged, so
750
                         * check if the UID/GID can be changed before enabling the full test. */
751
                        if (setresgid(GID_NOBODY, GID_NOBODY, GID_NOBODY) < 0) {
1✔
752
                                /* If the nobody user does not exist (user namespace) we get EINVAL. */
753
                                if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
×
754
                                        ASSERT_OK_ERRNO(-1);
×
755
                                full_test = false;
756
                        } else if (setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) < 0) {
1✔
757
                                /* If the nobody user does not exist (user namespace) we get EINVAL. */
758
                                if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
×
759
                                        ASSERT_OK_ERRNO(-1);
×
760
                                full_test = false;
761
                        } else
762
                                full_test = true;
763
                }
764

765
                errno = 0;
1✔
766
                p = getpriority(PRIO_PROCESS, 0);
1✔
767
                ASSERT_EQ(errno, 0);
1✔
768

769
                /* It should always be possible to set our nice level to the current one */
770
                ASSERT_OK_POSITIVE(setpriority_closest(p));
1✔
771

772
                errno = 0;
1✔
773
                q = getpriority(PRIO_PROCESS, 0);
1✔
774
                ASSERT_EQ(errno, 0);
1✔
775
                ASSERT_EQ(p, q);
1✔
776

777
                /* It should also be possible to set the nice level to one higher */
778
                if (p < PRIO_MAX-1) {
1✔
779
                        ASSERT_OK_POSITIVE(setpriority_closest(++p));
1✔
780

781
                        errno = 0;
1✔
782
                        q = getpriority(PRIO_PROCESS, 0);
1✔
783
                        ASSERT_EQ(errno, 0);
1✔
784
                        ASSERT_EQ(p, q);
1✔
785
                }
786

787
                /* It should also be possible to set the nice level to two higher */
788
                if (p < PRIO_MAX-1) {
1✔
789
                        ASSERT_OK_POSITIVE(setpriority_closest(++p));
1✔
790

791
                        errno = 0;
1✔
792
                        q = getpriority(PRIO_PROCESS, 0);
1✔
793
                        ASSERT_EQ(errno, 0);
1✔
794
                        ASSERT_EQ(p, q);
1✔
795
                }
796

797
                if (full_test) {
1✔
798
                        /* These two should work, given the RLIMIT_NICE we set above */
799
                        ASSERT_OK_POSITIVE(setpriority_closest(-10));
1✔
800
                        errno = 0;
1✔
801
                        q = getpriority(PRIO_PROCESS, 0);
1✔
802
                        ASSERT_EQ(errno, 0);
1✔
803
                        ASSERT_EQ(q, -10);
1✔
804

805
                        ASSERT_OK_POSITIVE(setpriority_closest(-9));
1✔
806
                        errno = 0;
1✔
807
                        q = getpriority(PRIO_PROCESS, 0);
1✔
808
                        ASSERT_EQ(errno, 0);
1✔
809
                        ASSERT_EQ(q, -9);
1✔
810

811
                        /* This should succeed but should be clamped to the limit */
812
                        ASSERT_OK_ZERO(setpriority_closest(-11));
1✔
813
                        errno = 0;
1✔
814
                        q = getpriority(PRIO_PROCESS, 0);
1✔
815
                        ASSERT_EQ(errno, 0);
1✔
816
                        ASSERT_EQ(q, -10);
1✔
817

818
                        ASSERT_OK_POSITIVE(setpriority_closest(-8));
1✔
819
                        errno = 0;
1✔
820
                        q = getpriority(PRIO_PROCESS, 0);
1✔
821
                        ASSERT_EQ(errno, 0);
1✔
822
                        ASSERT_EQ(q, -8);
1✔
823

824
                        /* This should succeed but should be clamped to the limit */
825
                        ASSERT_OK_ZERO(setpriority_closest(-12));
1✔
826
                        errno = 0;
1✔
827
                        q = getpriority(PRIO_PROCESS, 0);
1✔
828
                        ASSERT_EQ(errno, 0);
1✔
829
                        ASSERT_EQ(q, -10);
1✔
830
                }
831

832
                _exit(EXIT_SUCCESS);
1✔
833
        }
834
}
1✔
835

836
TEST(pid_get_ppid) {
1✔
837
        uint64_t limit;
1✔
838
        int r;
1✔
839

840
        ASSERT_ERROR(pid_get_ppid(1, NULL), EADDRNOTAVAIL);
1✔
841

842
        /* the process with the PID above the global limit definitely doesn't exist. Verify that */
843
        ASSERT_OK(procfs_get_pid_max(&limit));
1✔
844
        log_debug("kernel.pid_max = %"PRIu64, limit);
1✔
845

846
        if (limit < INT_MAX) {
1✔
847
                r = pid_get_ppid(limit + 1, NULL);
1✔
848
                log_debug_errno(r, "get_process_limit(%"PRIu64") → %d/%m", limit + 1, r);
1✔
849
                assert(r == -ESRCH);
1✔
850
        }
851

852
        for (pid_t pid = 0;;) {
1✔
853
                _cleanup_free_ char *c1 = NULL, *c2 = NULL;
1✔
854
                pid_t ppid;
2✔
855

856
                r = pid_get_ppid(pid, &ppid);
2✔
857
                if (r == -EADDRNOTAVAIL) {
2✔
858
                        log_info("No further parent PID");
1✔
859
                        break;
1✔
860
                }
861

862
                ASSERT_OK(r);
1✔
863

864
                ASSERT_OK(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
1✔
865
                ASSERT_OK(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
1✔
866

867
                log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2);
1✔
868

869
                pid = ppid;
1✔
870
        }
871

872
        /* the same via pidref */
873
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
874
        ASSERT_OK(pidref_set_self(&pidref));
1✔
875
        for (;;) {
3✔
876
                _cleanup_free_ char *c1 = NULL, *c2 = NULL;
2✔
877
                _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
×
878
                r = pidref_get_ppid_as_pidref(&pidref, &parent);
2✔
879
                if (r == -EADDRNOTAVAIL) {
2✔
880
                        log_info("No further parent PID");
1✔
881
                        break;
1✔
882
                }
883

884
                ASSERT_OK(r);
1✔
885

886
                ASSERT_OK(pidref_get_cmdline(&pidref, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
1✔
887
                ASSERT_OK(pidref_get_cmdline(&parent, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
1✔
888

889
                log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pidref.pid, c1, parent.pid, c2);
1✔
890

891
                pidref_done(&pidref);
1✔
892
                pidref = TAKE_PIDREF(parent);
1✔
893
        }
894
}
1✔
895

896
TEST(set_oom_score_adjust) {
1✔
897
        int a, b, r;
1✔
898

899
        ASSERT_OK(get_oom_score_adjust(&a));
1✔
900

901
        r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
1✔
902
        if (!ERRNO_IS_PRIVILEGE(r))
1✔
903
                ASSERT_OK(r);
1✔
904

905
        if (r >= 0) {
×
906
                ASSERT_OK(get_oom_score_adjust(&b));
1✔
907
                ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
1✔
908
        }
909

910
        ASSERT_OK(set_oom_score_adjust(a));
1✔
911
        ASSERT_OK(get_oom_score_adjust(&b));
1✔
912
        ASSERT_EQ(b, a);
1✔
913
}
1✔
914

915
static void* dummy_thread(void *p) {
2✔
916
        int fd = PTR_TO_FD(p);
2✔
917
        char x;
2✔
918

919
        /* let main thread know we are ready */
920
        ASSERT_OK_EQ_ERRNO(write(fd, &(const char) { 'x' }, 1), 1);
2✔
921

922
        /* wait for the main thread to tell us to shut down */
923
        ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
2✔
924
        return NULL;
2✔
925
}
926

927
TEST(get_process_threads) {
1✔
928
        int r;
1✔
929

930
        /* Run this test in a child, so that we can guarantee there's exactly one thread around in the child */
931
        r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
1✔
932
        ASSERT_OK(r);
2✔
933

934
        if (r == 0) {
2✔
935
                _cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
×
936
                pthread_t t, tt;
1✔
937
                char x;
1✔
938

939
                ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd));
1✔
940
                ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd));
1✔
941

942
                ASSERT_OK_EQ(get_process_threads(0), 1);
1✔
943
                ASSERT_OK_ZERO_ERRNO(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])));
1✔
944
                ASSERT_OK_EQ_ERRNO(read(pfd[1], &x, 1), 1);
1✔
945
                ASSERT_OK_EQ(get_process_threads(0), 2);
1✔
946
                ASSERT_OK_ZERO_ERRNO(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])));
1✔
947
                ASSERT_OK_EQ_ERRNO(read(ppfd[1], &x, 1), 1);
1✔
948
                ASSERT_OK_EQ(get_process_threads(0), 3);
1✔
949

950
                ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
1✔
951
                ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
1✔
952

953
                /* the value reported via /proc/ is decreased asynchronously, and there appears to be no nice
954
                 * way to sync on it. Hence we do the weak >= 2 check, even though == 2 is what we'd actually
955
                 * like to check here */
956
                r = get_process_threads(0);
1✔
957
                ASSERT_OK(r);
1✔
958
                ASSERT_GE(r, 2);
1✔
959

960
                ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
1✔
961
                ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
1✔
962

963
                /* similar here */
964
                r = get_process_threads(0);
1✔
965
                ASSERT_OK(r);
1✔
966
                ASSERT_GE(r, 1);
1✔
967

968
                _exit(EXIT_SUCCESS);
1✔
969
        }
970
}
1✔
971

972
TEST(is_reaper_process) {
1✔
973
        int r;
1✔
974

975
        r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
976
        ASSERT_OK(r);
2✔
977
        if (r == 0) {
2✔
978
                /* child */
979

980
                ASSERT_OK_ZERO(is_reaper_process());
1✔
981
                _exit(EXIT_SUCCESS);
1✔
982
        }
983

984
        r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
985
        ASSERT_OK(r);
2✔
986
        if (r == 0) {
2✔
987
                /* child */
988

989
                if (unshare(CLONE_NEWPID) < 0) {
1✔
990
                        if (ERRNO_IS_PRIVILEGE(errno) || ERRNO_IS_NOT_SUPPORTED(errno)) {
×
991
                                log_notice("Skipping CLONE_NEWPID reaper check, lacking privileges/support");
×
992
                                _exit(EXIT_SUCCESS);
×
993
                        }
994
                }
995

996
                r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
997
                ASSERT_OK(r);
2✔
998
                if (r == 0) {
2✔
999
                        /* grandchild, which is PID1 in a pidns */
1000
                        ASSERT_OK_EQ(getpid_cached(), 1);
1✔
1001
                        ASSERT_OK_POSITIVE(is_reaper_process());
1✔
1002
                        _exit(EXIT_SUCCESS);
1✔
1003
                }
1004

1005
                _exit(EXIT_SUCCESS);
1✔
1006
        }
1007

1008
        r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
1009
        ASSERT_OK(r);
2✔
1010
        if (r == 0) {
2✔
1011
                /* child */
1012
                ASSERT_OK(make_reaper_process(true));
1✔
1013

1014
                ASSERT_OK_POSITIVE(is_reaper_process());
1✔
1015
                _exit(EXIT_SUCCESS);
1✔
1016
        }
1017
}
1✔
1018

1019
TEST(pid_get_start_time) {
1✔
1020
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
1✔
1021

1022
        ASSERT_OK(pidref_set_self(&pidref));
1✔
1023

1024
        usec_t start_time;
1✔
1025
        ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
1✔
1026
        log_info("our starttime: " USEC_FMT, start_time);
1✔
1027

1028
        _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
1✔
1029

1030
        ASSERT_OK_POSITIVE(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_FREEZE, &child));
1✔
1031

1032
        usec_t start_time2;
1✔
1033
        ASSERT_OK(pidref_get_start_time(&child, &start_time2));
1✔
1034

1035
        log_info("child starttime: " USEC_FMT, start_time2);
1✔
1036

1037
        ASSERT_GE(start_time2, start_time);
1✔
1038
}
1✔
1039

1040
TEST(pidref_from_same_root_fs) {
1✔
1041
        int r;
1✔
1042

1043
        _cleanup_(pidref_done) PidRef pid1 = PIDREF_NULL, self = PIDREF_NULL;
1✔
1044

1045
        ASSERT_OK(pidref_set_self(&self));
1✔
1046
        ASSERT_OK(pidref_set_pid(&pid1, 1));
1✔
1047

1048
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &self));
1✔
1049
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&pid1, &pid1));
1✔
1050

1051
        r = pidref_from_same_root_fs(&pid1, &self);
1✔
1052
        if (ERRNO_IS_NEG_PRIVILEGE(r))
1✔
1053
                return (void) log_tests_skipped("skipping pidref_from_same_root_fs() test, lacking privileged.");
×
1054
        ASSERT_OK(r);
1✔
1055
        log_info("PID1 and us have the same rootfs: %s", yes_no(r));
2✔
1056

1057
        int q = pidref_from_same_root_fs(&self, &pid1);
1✔
1058
        ASSERT_OK(q);
1✔
1059
        ASSERT_EQ(r, q);
1✔
1060

1061
        _cleanup_(pidref_done_sigkill_wait) PidRef child1 = PIDREF_NULL;
×
1062
        ASSERT_OK(pidref_safe_fork("(child1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_FREEZE, &child1));
1✔
1063
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &child1));
1✔
1064

1065
        _cleanup_close_ int efd = eventfd(0, EFD_CLOEXEC);
2✔
1066
        ASSERT_OK_ERRNO(efd);
1✔
1067

1068
        _cleanup_(pidref_done_sigkill_wait) PidRef child2 = PIDREF_NULL;
1✔
1069
        r = pidref_safe_fork("(child2)", FORK_RESET_SIGNALS|FORK_REOPEN_LOG, &child2);
1✔
1070
        ASSERT_OK(r);
1✔
1071

1072
        if (r == 0) {
1✔
1073
                ASSERT_OK_ERRNO(chroot("/usr"));
×
1074
                uint64_t u = 1;
×
1075

1076
                ASSERT_OK_EQ_ERRNO(write(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
×
1077
                freeze();
×
1078
        }
1079

1080
        uint64_t u;
1✔
1081
        ASSERT_OK_EQ_ERRNO(read(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
1✔
1082

1083
        ASSERT_OK_ZERO(pidref_from_same_root_fs(&self, &child2));
1✔
1084
        ASSERT_OK_ZERO(pidref_from_same_root_fs(&child2, &self));
1✔
1085
}
1086

1087
TEST(pidfd_get_inode_id_self_cached) {
1✔
1088
        int r;
1✔
1089

1090
        log_info("pid=" PID_FMT, getpid_cached());
1✔
1091

1092
        uint64_t id;
1✔
1093
        r = pidfd_get_inode_id_self_cached(&id);
1✔
1094
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
1✔
1095
                log_info("pidfdid not supported");
×
1096
        else {
1097
                assert(r >= 0);
1✔
1098
                log_info("pidfdid=%" PRIu64, id);
1✔
1099
        }
1100
}
1✔
1101

1102
static int intro(void) {
1✔
1103
        log_show_color(true);
1✔
1104
        return EXIT_SUCCESS;
1✔
1105
}
1106

1107
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
1✔
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