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

systemd / systemd / 16038438970

03 Jul 2025 12:06AM UTC coverage: 72.096% (+0.1%) from 71.988%
16038438970

push

github

web-flow
test-xattr-util.c: migrate to new assertion macros (#38025)

We recently added a new set of assertion macros such as ASSERT_GE,
ASSERT_OK, ASSERT_EQ, ... which show not only the expression that failed
but also the values of the arguments of the expression. Let's use them.

12 of 13 new or added lines in 1 file covered. (92.31%)

3080 existing lines in 44 files now uncovered.

300788 of 417204 relevant lines covered (72.1%)

711634.61 hits per line

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

94.19
/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 <stdlib.h>
7
#include <sys/eventfd.h>
8
#include <sys/mount.h>
9
#include <sys/personality.h>
10
#include <sys/prctl.h>
11
#include <sys/stat.h>
12
#include <sys/wait.h>
13
#include <unistd.h>
14
#include "strv.h"
15
#if HAVE_VALGRIND_VALGRIND_H
16
#include <valgrind/valgrind.h>
17
#endif
18

19
#include "sd-daemon.h"
20

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

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

57
        log_info("/* %s */", __func__);
2✔
58

59
        xsprintf(path, "/proc/"PID_FMT"/comm", pid);
2✔
60

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

67
        ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
2✔
68
        log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
2✔
69

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

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

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

87
        ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
2✔
88

89
        ASSERT_OK_OR(get_process_exe(pid, &f), -EACCES);
2✔
90
        log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
2✔
91

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

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

98
        ASSERT_OK_OR(get_process_environ(pid, &env), -EACCES);
2✔
99
        log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
2✔
100

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

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

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

UNCOV
112
                (void) parse_pid(saved_argv[1], &pid);
×
UNCOV
113
                test_pid_get_comm_one(pid);
×
114
        } else {
115
                if (sd_booted() > 0)
1✔
116
                        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) {
46✔
UNCOV
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;
46✔
124
        int r;
46✔
125

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

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

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

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

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

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

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

149
        joined = mfree(joined);
46✔
150

151
        r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
46✔
152
        if (r >= 0)
46✔
153
                ASSERT_NOT_NULL((joined = strv_join(strv_b, "\", \"")));
46✔
154
        log_info("      \"%s\"", r >= 0 ? joined : errno_to_name(r));
46✔
155
}
46✔
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 (;;) {
46✔
164
                pid_t pid;
47✔
165
                ASSERT_OK(r = proc_dir_read(d, &pid));
47✔
166

167
                if (r == 0) /* EOF */
47✔
168
                        break;
169

170
                test_pid_get_cmdline_one(pid);
46✔
171
        }
172
}
1✔
173

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

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

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

182
        log_debug("got: <%s>", n);
10✔
183

184
        ASSERT_STREQ(n, output);
10✔
185
}
10✔
186

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

190
        ASSERT_OK(pid_get_comm(0, &saved));
1✔
191

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

203
        ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
1✔
204
}
1✔
205

206
TEST(pid_is_unwaited) {
1✔
207
        pid_t pid;
1✔
208

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

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

223
TEST(pid_is_alive) {
1✔
224
        pid_t pid;
1✔
225

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

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

240
TEST(personality) {
1✔
241
        ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
1✔
242
        ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
1✔
243

244
        ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
1✔
245

246
        ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX)), (unsigned long) PER_LINUX);
1✔
247
        ASSERT_EQ(personality_from_string(architecture_to_string(native_architecture())), (unsigned long) PER_LINUX);
1✔
248

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

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

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

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

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

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

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

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

294
                (void) wait_for_terminate(pid, &si);
1✔
295

296
                ASSERT_EQ(si.si_code, CLD_EXITED);
1✔
297
                ASSERT_OK_ZERO(si.si_status);
1✔
298

299
                return;
1✔
300
        }
301

302
        ASSERT_OK_ZERO(pid);
1✔
303

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

312
        fd = mkostemp(path, O_CLOEXEC);
1✔
313
        ASSERT_OK_ERRNO(fd);
1✔
314

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

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

329
        ASSERT_OK_ERRNO(unlink(path));
1✔
330

331
        ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
1✔
332

333
        ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
1✔
334

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

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

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

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

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

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

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

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

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

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

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

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

386
        /* Test with multiple arguments that don't require quoting */
387

388
        ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
1✔
389

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

496
        ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
1✔
497

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

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

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

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

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

522
        /* Test with multiple arguments that do require quoting */
523

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

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

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

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

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

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

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

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

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

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

574
        safe_close(fd);
1✔
575
        _exit(EXIT_SUCCESS);
1✔
576
}
577

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

582
        a = getpid();
1✔
583
        b = getpid_cached();
1✔
584
        c = getpid();
1✔
585

586
        ASSERT_EQ(a, b);
1✔
587
        ASSERT_EQ(a, c);
1✔
588

589
        child = fork();
1✔
590
        ASSERT_OK_ERRNO(child);
2✔
591

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

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

603
        d = getpid();
1✔
604
        e = getpid_cached();
1✔
605
        f = getpid();
1✔
606

607
        ASSERT_EQ(a, d);
1✔
608
        ASSERT_EQ(a, e);
1✔
609
        ASSERT_EQ(a, f);
1✔
610

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

616
TEST(getpid_measure) {
1✔
617
        usec_t t, q;
1✔
618

619
        unsigned long long iterations = slow_tests_enabled() ? 1000000 : 1000;
1✔
620

621
        log_info("/* %s (%llu iterations) */", __func__, iterations);
1✔
622

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

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

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

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

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

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

645
        BLOCK_SIGNALS(SIGCHLD);
2✔
646

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

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

654
                _exit(88);
1✔
655
        }
656

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

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

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

674
        if (is_reaper_process())
1✔
UNCOV
675
                ASSERT_EQ(pid, getpid_cached());
×
676
        else
677
                ASSERT_NE(pid, getpid_cached());
1✔
678
}
1✔
679

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

684
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
1✔
685
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
1✔
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

689
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
1✔
690
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
1✔
691

692
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
1✔
693
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
1✔
694
}
1✔
695

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

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

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

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

727
TEST(setpriority_closest) {
1✔
728
        int r;
1✔
729

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

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

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

763
                errno = 0;
1✔
764
                p = getpriority(PRIO_PROCESS, 0);
1✔
765
                ASSERT_EQ(errno, 0);
1✔
766

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

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

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

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

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

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

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

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

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

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

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

830
                _exit(EXIT_SUCCESS);
1✔
831
        }
832
}
1✔
833

834
TEST(pid_get_ppid) {
1✔
835
        uint64_t limit;
1✔
836
        int r;
1✔
837

838
        ASSERT_ERROR(pid_get_ppid(1, NULL), EADDRNOTAVAIL);
1✔
839

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

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

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

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

860
                ASSERT_OK(r);
1✔
861

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

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

867
                pid = ppid;
1✔
868
        }
869

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

882
                ASSERT_OK(r);
1✔
883

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

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

889
                pidref_done(&pidref);
1✔
890
                pidref = TAKE_PIDREF(parent);
1✔
891
        }
892
}
1✔
893

894
TEST(set_oom_score_adjust) {
1✔
895
        int a, b, r;
1✔
896

897
        ASSERT_OK(get_oom_score_adjust(&a));
1✔
898

899
        r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
1✔
900
        if (!ERRNO_IS_PRIVILEGE(r))
1✔
901
                ASSERT_OK(r);
1✔
902

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

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

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

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

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

925
TEST(get_process_threads) {
1✔
926
        int r;
1✔
927

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

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

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

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

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

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

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

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

966
                _exit(EXIT_SUCCESS);
1✔
967
        }
968
}
1✔
969

970
TEST(is_reaper_process) {
1✔
971
        int r;
1✔
972

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

978
                ASSERT_OK_ZERO(is_reaper_process());
1✔
979
                _exit(EXIT_SUCCESS);
1✔
980
        }
981

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

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

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

1003
                _exit(EXIT_SUCCESS);
1✔
1004
        }
1005

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

1012
                ASSERT_OK_POSITIVE(is_reaper_process());
1✔
1013
                _exit(EXIT_SUCCESS);
1✔
1014
        }
1015
}
1✔
1016

1017
TEST(pid_get_start_time) {
1✔
1018
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
1✔
1019

1020
        ASSERT_OK(pidref_set_self(&pidref));
1✔
1021

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

1026
        _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
1✔
1027

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

1030
        usec_t start_time2;
1✔
1031
        ASSERT_OK(pidref_get_start_time(&child, &start_time2));
1✔
1032

1033
        log_info("child starttime: " USEC_FMT, start_time2);
1✔
1034

1035
        ASSERT_GE(start_time2, start_time);
1✔
1036
}
1✔
1037

1038
TEST(pidref_from_same_root_fs) {
1✔
1039
        int r;
1✔
1040

1041
        _cleanup_(pidref_done) PidRef pid1 = PIDREF_NULL, self = PIDREF_NULL;
1✔
1042

1043
        ASSERT_OK(pidref_set_self(&self));
1✔
1044
        ASSERT_OK(pidref_set_pid(&pid1, 1));
1✔
1045

1046
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &self));
1✔
1047
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&pid1, &pid1));
1✔
1048

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

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

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

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

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

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

UNCOV
1074
                ASSERT_OK_EQ_ERRNO(write(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
×
UNCOV
1075
                freeze();
×
1076
        }
1077

1078
        uint64_t u;
1✔
1079
        ASSERT_OK_EQ_ERRNO(read(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
1✔
1080

1081
        ASSERT_OK_ZERO(pidref_from_same_root_fs(&self, &child2));
1✔
1082
        ASSERT_OK_ZERO(pidref_from_same_root_fs(&child2, &self));
1✔
1083
}
1084

1085
TEST(pidfd_get_inode_id_self_cached) {
1✔
1086
        int r;
1✔
1087

1088
        log_info("pid=" PID_FMT, getpid_cached());
1✔
1089

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

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

1105
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