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

systemd / systemd / 20401947236

20 Dec 2025 09:56PM UTC coverage: 72.701% (+0.1%) from 72.578%
20401947236

push

github

DaanDeMeyer
core/socket: modernize listen/accept_in_cgroup

4 of 9 new or added lines in 1 file covered. (44.44%)

7723 existing lines in 114 files now uncovered.

309972 of 426363 relevant lines covered (72.7%)

1133403.64 hits per line

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

93.88
/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 "namespace-util.h"
30
#include "parse-util.h"
31
#include "pidfd-util.h"
32
#include "pidref.h"
33
#include "process-util.h"
34
#include "procfs-util.h"
35
#include "rlimit-util.h"
36
#include "signal-util.h"
37
#include "stdio-util.h"
38
#include "string-util.h"
39
#include "terminal-util.h"
40
#include "tests.h"
41
#include "time-util.h"
42
#include "user-util.h"
43
#include "virt.h"
44

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

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

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

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

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

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

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

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

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

88
        ASSERT_OK_OR(get_process_exe(pid, &f), -EACCES);
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
        ASSERT_OK_OR(get_process_environ(pid, &env), -EACCES);
2✔
98
        log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
2✔
99

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

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

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

111
                (void) parse_pid(saved_argv[1], &pid);
×
112
                test_pid_get_comm_one(pid);
×
113
        } else {
114
                if (sd_booted() > 0)
1✔
115
                        test_pid_get_comm_one(1);
1✔
116
                test_pid_get_comm_one(getpid());
1✔
117
        }
118
}
1✔
119

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

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

128
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &d);
41✔
129
        log_info("      %s", r >= 0 ? d : ERRNO_NAME(r));
41✔
130

131
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &e);
41✔
132
        log_info("      %s", r >= 0 ? e : ERRNO_NAME(r));
41✔
133

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

137
        r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &g);
41✔
138
        log_info("      %s", r >= 0 ? g : ERRNO_NAME(r));
41✔
139

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

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

148
        joined = mfree(joined);
41✔
149

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

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

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

162
        for (;;) {
41✔
163
                pid_t pid;
42✔
164
                ASSERT_OK(r = proc_dir_read(d, &pid));
42✔
165

166
                if (r == 0) /* EOF */
42✔
167
                        break;
168

169
                test_pid_get_cmdline_one(pid);
41✔
170
        }
171
}
1✔
172

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

288
        r = ASSERT_OK(safe_fork("(cmdline)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
1✔
289
        if (r == 0) {
2✔
290
                r = detach_mount_namespace();
1✔
291
                if (r < 0) {
1✔
UNCOV
292
                        log_warning_errno(r, "detach mount namespace failed: %m");
×
UNCOV
293
                        if (!ERRNO_IS_PRIVILEGE(r))
×
UNCOV
294
                                ASSERT_OK(r);
×
295
                        return;
296
                }
297

298
                fd = mkostemp(path, O_CLOEXEC);
1✔
299
                ASSERT_OK_ERRNO(fd);
1✔
300

301
                /* Note that we don't unmount the following bind-mount at the end of the test because the kernel
302
                * will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
303
                if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
1✔
304
                        /* This happens under selinux… Abort the test in this case. */
305
                        log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
×
306
                        ASSERT_TRUE(IN_SET(errno, EPERM, EACCES));
×
307
                        return;
308
                }
309

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

315
                ASSERT_OK_ERRNO(unlink(path));
1✔
316

317
                ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
1✔
318

319
                ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
1✔
320

321
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
322
                log_debug("'%s'", line);
1✔
323
                ASSERT_STREQ(line, "[testa]");
1✔
324
                line = mfree(line);
1✔
325

326
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
1✔
327
                log_debug("'%s'", line);
1✔
328
                ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
1✔
329
                line = mfree(line);
1✔
330

331
                ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
332
                log_debug("'%s'", line);
1✔
333
                ASSERT_STREQ(line, "");
1✔
334
                line = mfree(line);
1✔
335

336
                ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
337
                ASSERT_STREQ(line, "…");
1✔
338
                line = mfree(line);
1✔
339

340
                ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
341
                ASSERT_STREQ(line, "[…");
1✔
342
                line = mfree(line);
1✔
343

344
                ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
345
                ASSERT_STREQ(line, "[t…");
1✔
346
                line = mfree(line);
1✔
347

348
                ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
349
                ASSERT_STREQ(line, "[te…");
1✔
350
                line = mfree(line);
1✔
351

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

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

360
                ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
361
                ASSERT_STREQ(line, "[testa]");
1✔
362
                line = mfree(line);
1✔
363

364
                ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
365
                ASSERT_STREQ(line, "[testa]");
1✔
366
                line = mfree(line);
1✔
367

368
                ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
369
                ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
1✔
370
                args = strv_free(args);
1✔
371

372
        /* Test with multiple arguments that don't require quoting */
373

374
                ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
1✔
375

376
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
1✔
377
                log_debug("'%s'", line);
1✔
378
                ASSERT_STREQ(line, "foo bar");
1✔
379
                line = mfree(line);
1✔
380

381
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
382
                ASSERT_STREQ(line, "foo bar");
1✔
383
                line = mfree(line);
1✔
384

385
                ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
386
                ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
1✔
387
                args = strv_free(args);
1✔
388

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

395
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
396
                log_debug("'%s'", line);
1✔
397
                ASSERT_STREQ(line, "foo bar quux");
1✔
398
                line = mfree(line);
1✔
399

400
                ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
401
                log_debug("'%s'", line);
1✔
402
                ASSERT_STREQ(line, "…");
1✔
403
                line = mfree(line);
1✔
404

405
                ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
406
                log_debug("'%s'", line);
1✔
407
                ASSERT_STREQ(line, "f…");
1✔
408
                line = mfree(line);
1✔
409

410
                ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
411
                log_debug("'%s'", line);
1✔
412
                ASSERT_STREQ(line, "fo…");
1✔
413
                line = mfree(line);
1✔
414

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

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

425
                ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
426
                log_debug("'%s'", line);
1✔
427
                ASSERT_STREQ(line, "foo b…");
1✔
428
                line = mfree(line);
1✔
429

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

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

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

445
                ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
446
                log_debug("'%s'", line);
1✔
447
                ASSERT_STREQ(line, "foo bar q…");
1✔
448
                line = mfree(line);
1✔
449

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

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

460
                ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
461
                log_debug("'%s'", line);
1✔
462
                ASSERT_STREQ(line, "foo bar quux");
1✔
463
                line = mfree(line);
1✔
464

465
                ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
466
                log_debug("'%s'", line);
1✔
467
                ASSERT_STREQ(line, "foo bar quux");
1✔
468
                line = mfree(line);
1✔
469

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

475
                ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
476
                ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
1✔
477
                args = strv_free(args);
1✔
478

479
                ASSERT_OK_ERRNO(ftruncate(fd, 0));
1✔
480
                ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
1✔
481

482
                ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
1✔
483

484
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
485
                log_debug("'%s'", line);
1✔
486
                ASSERT_STREQ(line, "[aaaa bbbb cccc]");
1✔
487
                line = mfree(line);
1✔
488

489
                ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
490
                log_debug("'%s'", line);
1✔
491
                ASSERT_STREQ(line, "[aaaa bbb…");
1✔
492
                line = mfree(line);
1✔
493

494
                ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
495
                log_debug("'%s'", line);
1✔
496
                ASSERT_STREQ(line, "[aaaa bbbb…");
1✔
497
                line = mfree(line);
1✔
498

499
                ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
1✔
500
                log_debug("'%s'", line);
1✔
501
                ASSERT_STREQ(line, "[aaaa bbbb …");
1✔
502
                line = mfree(line);
1✔
503

504
                ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
1✔
505
                ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
1✔
506
                args = strv_free(args);
1✔
507

508
                /* Test with multiple arguments that do require quoting */
509

510
#define CMDLINE1 "foo\0'bar'\0\"bar$\"\0x y z\0!``\0"
511
#define EXPECT1  "foo \"'bar'\" \"\\\"bar\\$\\\"\" \"x y z\" \"!\\`\\`\""
512
#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
513
#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
514

515
                ASSERT_OK_ZERO_ERRNO(lseek(fd, 0, SEEK_SET));
1✔
516
                ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
1✔
517
                ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
1✔
518

519
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
1✔
520
                log_debug("got: ==%s==", line);
1✔
521
                log_debug("exp: ==%s==", EXPECT1);
1✔
522
                ASSERT_STREQ(line, EXPECT1);
1✔
523
                line = mfree(line);
1✔
524

525
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
1✔
526
                log_debug("got: ==%s==", line);
1✔
527
                log_debug("exp: ==%s==", EXPECT1p);
1✔
528
                ASSERT_STREQ(line, EXPECT1p);
1✔
529
                line = mfree(line);
1✔
530

531
                ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
1✔
532
                ASSERT_TRUE(strv_equal(args, EXPECT1v));
1✔
533
                args = strv_free(args);
1✔
534

535
#define CMDLINE2 "foo\0\1\2\3\0\0"
536
#define EXPECT2  "foo \"\\001\\002\\003\""
537
#define EXPECT2p "foo $'\\001\\002\\003'"
538
#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
539

540
                ASSERT_OK_ZERO_ERRNO(lseek(fd, 0, SEEK_SET));
1✔
541
                ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
1✔
542
                ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));
1✔
543

544
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
1✔
545
                log_debug("got: ==%s==", line);
1✔
546
                log_debug("exp: ==%s==", EXPECT2);
1✔
547
                ASSERT_STREQ(line, EXPECT2);
1✔
548
                line = mfree(line);
1✔
549

550
                ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
1✔
551
                log_debug("got: ==%s==", line);
1✔
552
                log_debug("exp: ==%s==", EXPECT2p);
1✔
553
                ASSERT_STREQ(line, EXPECT2p);
1✔
554
                line = mfree(line);
1✔
555

556
                ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
1✔
557
                ASSERT_TRUE(strv_equal(args, EXPECT2v));
1✔
558
                args = strv_free(args);
1✔
559

560
                safe_close(fd);
1✔
561
                _exit(EXIT_SUCCESS);
1✔
562
        }
563
}
564

565
TEST(getpid_cached) {
1✔
566
        pid_t a, b, c, d, e, f;
1✔
567
        int r;
1✔
568

569
        a = getpid();
1✔
570
        b = getpid_cached();
1✔
571
        c = getpid();
1✔
572

573
        ASSERT_EQ(a, b);
1✔
574
        ASSERT_EQ(a, c);
1✔
575

576
        r = ASSERT_OK(safe_fork("(getpid)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
1✔
577

578
        if (r == 0) {
2✔
579
                /* In child */
580
                a = getpid();
1✔
581
                b = getpid_cached();
1✔
582
                c = getpid();
1✔
583

584
                ASSERT_EQ(a, b);
1✔
585
                ASSERT_EQ(a, c);
1✔
586
                _exit(EXIT_SUCCESS);
1✔
587
        }
588

589
        d = getpid();
1✔
590
        e = getpid_cached();
1✔
591
        f = getpid();
1✔
592

593
        ASSERT_EQ(a, d);
1✔
594
        ASSERT_EQ(a, e);
1✔
595
        ASSERT_EQ(a, f);
1✔
596
}
1✔
597

598
TEST(getpid_measure) {
1✔
599
        usec_t t, q;
1✔
600

601
        unsigned long long iterations = slow_tests_enabled() ? 1000000 : 1000;
1✔
602

603
        log_info("/* %s (%llu iterations) */", __func__, iterations);
1✔
604

605
        t = now(CLOCK_MONOTONIC);
1✔
606
        for (unsigned long long i = 0; i < iterations; i++)
1,001✔
607
                (void) getpid();
1,000✔
608
        q = now(CLOCK_MONOTONIC) - t;
1✔
609

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

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

614
        t = now(CLOCK_MONOTONIC);
1✔
615
        for (unsigned long long i = 0; i < iterations; i++)
50,001✔
616
                (void) getpid_cached();
50,000✔
617
        q = now(CLOCK_MONOTONIC) - t;
1✔
618

619
        log_info("getpid_cached(): %lf μs each", (double) q / iterations);
1✔
620
}
1✔
621

622
TEST(safe_fork) {
1✔
623
        siginfo_t status;
1✔
624
        pid_t pid;
1✔
625
        int r;
1✔
626

627
        r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
1✔
628
        ASSERT_OK(r);
2✔
629

630
        if (r == 0) {
2✔
631
                /* child */
632
                usleep_safe(100 * USEC_PER_MSEC);
1✔
633

634
                _exit(88);
1✔
635
        }
636

637
        _cleanup_(pidref_done) PidRef child = PIDREF_NULL;
1✔
638
        ASSERT_OK(pidref_set_pid(&child, pid));
1✔
639

640
        ASSERT_OK(pidref_wait_for_terminate(&child, &status));
1✔
641
        ASSERT_EQ(status.si_code, CLD_EXITED);
1✔
642
        ASSERT_EQ(status.si_status, 88);
1✔
643

644
        pidref_done(&child);
1✔
645
        r = pidref_safe_fork("(test-child)", FORK_DETACH, &child);
1✔
646
        if (r == 0) {
1✔
647
                /* Don't freeze so this doesn't linger around forever in case something goes wrong. */
UNCOV
648
                usleep_safe(100 * USEC_PER_SEC);
×
UNCOV
649
                _exit(EXIT_SUCCESS);
×
650
        }
651

652
        ASSERT_OK_POSITIVE(r);
1✔
653
        ASSERT_GT(child.pid, 0);
1✔
654
        ASSERT_OK(pidref_get_ppid(&child, &pid));
1✔
655
        ASSERT_OK(pidref_kill(&child, SIGKILL));
1✔
656

657
        if (is_reaper_process())
1✔
UNCOV
658
                ASSERT_EQ(pid, getpid_cached());
×
659
        else
660
                ASSERT_NE(pid, getpid_cached());
1✔
661
}
1✔
662

663
TEST(pid_to_ptr) {
1✔
664
        ASSERT_EQ(PTR_TO_PID(NULL), 0);
1✔
665
        ASSERT_NULL(PID_TO_PTR(0));
1✔
666

667
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
1✔
668
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
1✔
669
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
1✔
670
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
1✔
671

672
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
1✔
673
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
1✔
674

675
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
1✔
676
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
1✔
677
}
1✔
678

679
static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
10✔
680
        ASSERT_EQ(ioprio_class_from_string(val), expected);
10✔
681
        if (expected >= 0) {
10✔
682
                _cleanup_free_ char *s = NULL;
7✔
683
                unsigned ret;
7✔
684
                int combined;
7✔
685

686
                ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
7✔
687
                /* We sometimes get a class number and sometimes a name back */
688
                ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
9✔
689

690
                /* Make sure normalization works, i.e. NONE → BE gets normalized */
691
                combined = ioprio_normalize(ioprio_prio_value(expected, 0));
7✔
692
                ASSERT_EQ(ioprio_prio_class(combined), normalized);
7✔
693
                ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
7✔
694
        }
695
}
10✔
696

697
TEST(ioprio_class_from_to_string) {
1✔
698
        test_ioprio_class_from_to_string_one("none", IOPRIO_CLASS_NONE, IOPRIO_CLASS_BE);
1✔
699
        test_ioprio_class_from_to_string_one("realtime", IOPRIO_CLASS_RT, IOPRIO_CLASS_RT);
1✔
700
        test_ioprio_class_from_to_string_one("best-effort", IOPRIO_CLASS_BE, IOPRIO_CLASS_BE);
1✔
701
        test_ioprio_class_from_to_string_one("idle", IOPRIO_CLASS_IDLE, IOPRIO_CLASS_IDLE);
1✔
702
        test_ioprio_class_from_to_string_one("0", IOPRIO_CLASS_NONE, IOPRIO_CLASS_BE);
1✔
703
        test_ioprio_class_from_to_string_one("1", 1, 1);
1✔
704
        test_ioprio_class_from_to_string_one("7", 7, 7);
1✔
705
        test_ioprio_class_from_to_string_one("8", -EINVAL, -EINVAL);
1✔
706
        test_ioprio_class_from_to_string_one("9", -EINVAL, -EINVAL);
1✔
707
        test_ioprio_class_from_to_string_one("-1", -EINVAL, -EINVAL);
1✔
708
}
1✔
709

710
TEST(setpriority_closest) {
1✔
711
        int r;
1✔
712

713
        r = safe_fork("(test-setprio)",
1✔
714
                      FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
715
        ASSERT_OK(r);
2✔
716

717
        if (r == 0) {
2✔
718
                bool full_test;
1✔
719
                int p, q;
1✔
720
                /* child */
721

722
                /* rlimit of 30 equals nice level of -10 */
723
                if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
1✔
724
                        /* If this fails we are probably unprivileged or in a userns of some kind, let's skip
725
                         * the full test */
UNCOV
726
                        if (!ERRNO_IS_PRIVILEGE(errno))
×
UNCOV
727
                                ASSERT_OK_ERRNO(-1);
×
728
                        full_test = false;
729
                } else {
730
                        /* However, if the hard limit was above 30, setrlimit would succeed unprivileged, so
731
                         * check if the UID/GID can be changed before enabling the full test. */
732
                        if (setresgid(GID_NOBODY, GID_NOBODY, GID_NOBODY) < 0) {
1✔
733
                                /* If the nobody user does not exist (user namespace) we get EINVAL. */
UNCOV
734
                                if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
×
UNCOV
735
                                        ASSERT_OK_ERRNO(-1);
×
736
                                full_test = false;
737
                        } else if (setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) < 0) {
1✔
738
                                /* If the nobody user does not exist (user namespace) we get EINVAL. */
UNCOV
739
                                if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
×
UNCOV
740
                                        ASSERT_OK_ERRNO(-1);
×
741
                                full_test = false;
742
                        } else
743
                                full_test = true;
744
                }
745

746
                errno = 0;
1✔
747
                p = getpriority(PRIO_PROCESS, 0);
1✔
748
                ASSERT_EQ(errno, 0);
1✔
749

750
                /* It should always be possible to set our nice level to the current one */
751
                ASSERT_OK_POSITIVE(setpriority_closest(p));
1✔
752

753
                errno = 0;
1✔
754
                q = getpriority(PRIO_PROCESS, 0);
1✔
755
                ASSERT_EQ(errno, 0);
1✔
756
                ASSERT_EQ(p, q);
1✔
757

758
                /* It should also be possible to set the nice level to one higher */
759
                if (p < PRIO_MAX-1) {
1✔
760
                        ASSERT_OK_POSITIVE(setpriority_closest(++p));
1✔
761

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

768
                /* It should also be possible to set the nice level to two higher */
769
                if (p < PRIO_MAX-1) {
1✔
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

778
                if (full_test) {
1✔
779
                        /* These two should work, given the RLIMIT_NICE we set above */
780
                        ASSERT_OK_POSITIVE(setpriority_closest(-10));
1✔
781
                        errno = 0;
1✔
782
                        q = getpriority(PRIO_PROCESS, 0);
1✔
783
                        ASSERT_EQ(errno, 0);
1✔
784
                        ASSERT_EQ(q, -10);
1✔
785

786
                        ASSERT_OK_POSITIVE(setpriority_closest(-9));
1✔
787
                        errno = 0;
1✔
788
                        q = getpriority(PRIO_PROCESS, 0);
1✔
789
                        ASSERT_EQ(errno, 0);
1✔
790
                        ASSERT_EQ(q, -9);
1✔
791

792
                        /* This should succeed but should be clamped to the limit */
793
                        ASSERT_OK_ZERO(setpriority_closest(-11));
1✔
794
                        errno = 0;
1✔
795
                        q = getpriority(PRIO_PROCESS, 0);
1✔
796
                        ASSERT_EQ(errno, 0);
1✔
797
                        ASSERT_EQ(q, -10);
1✔
798

799
                        ASSERT_OK_POSITIVE(setpriority_closest(-8));
1✔
800
                        errno = 0;
1✔
801
                        q = getpriority(PRIO_PROCESS, 0);
1✔
802
                        ASSERT_EQ(errno, 0);
1✔
803
                        ASSERT_EQ(q, -8);
1✔
804

805
                        /* This should succeed but should be clamped to the limit */
806
                        ASSERT_OK_ZERO(setpriority_closest(-12));
1✔
807
                        errno = 0;
1✔
808
                        q = getpriority(PRIO_PROCESS, 0);
1✔
809
                        ASSERT_EQ(errno, 0);
1✔
810
                        ASSERT_EQ(q, -10);
1✔
811
                }
812

813
                _exit(EXIT_SUCCESS);
1✔
814
        }
815
}
1✔
816

817
TEST(pid_get_ppid) {
1✔
818
        uint64_t limit;
1✔
819
        int r;
1✔
820

821
        ASSERT_ERROR(pid_get_ppid(1, NULL), EADDRNOTAVAIL);
1✔
822

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

827
        if (limit < INT_MAX) {
1✔
828
                r = pid_get_ppid(limit + 1, NULL);
1✔
829
                log_debug_errno(r, "get_process_limit(%"PRIu64") → %d/%m", limit + 1, r);
1✔
830
                assert(r == -ESRCH);
1✔
831
        }
832

833
        for (pid_t pid = 0;;) {
1✔
834
                _cleanup_free_ char *c1 = NULL, *c2 = NULL;
1✔
835
                pid_t ppid;
2✔
836

837
                r = pid_get_ppid(pid, &ppid);
2✔
838
                if (r == -EADDRNOTAVAIL) {
2✔
839
                        log_info("No further parent PID");
1✔
840
                        break;
1✔
841
                }
842

843
                ASSERT_OK(r);
1✔
844

845
                ASSERT_OK(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
1✔
846
                ASSERT_OK(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
1✔
847

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

850
                pid = ppid;
1✔
851
        }
852

853
        /* the same via pidref */
UNCOV
854
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
855
        ASSERT_OK(pidref_set_self(&pidref));
1✔
856
        for (;;) {
3✔
857
                _cleanup_free_ char *c1 = NULL, *c2 = NULL;
2✔
UNCOV
858
                _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
×
859
                r = pidref_get_ppid_as_pidref(&pidref, &parent);
2✔
860
                if (r == -EADDRNOTAVAIL) {
2✔
861
                        log_info("No further parent PID");
1✔
862
                        break;
1✔
863
                }
864

865
                ASSERT_OK(r);
1✔
866

867
                ASSERT_OK(pidref_get_cmdline(&pidref, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
1✔
868
                ASSERT_OK(pidref_get_cmdline(&parent, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
1✔
869

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

872
                pidref_done(&pidref);
1✔
873
                pidref = TAKE_PIDREF(parent);
1✔
874
        }
875
}
1✔
876

877
TEST(set_oom_score_adjust) {
1✔
878
        int a, b, r;
1✔
879

880
        ASSERT_OK(get_oom_score_adjust(&a));
1✔
881

882
        r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
1✔
883
        if (!ERRNO_IS_PRIVILEGE(r))
1✔
884
                ASSERT_OK(r);
1✔
885

UNCOV
886
        if (r >= 0) {
×
887
                ASSERT_OK(get_oom_score_adjust(&b));
1✔
888
                ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
1✔
889
        }
890

891
        ASSERT_OK(set_oom_score_adjust(a));
1✔
892
        ASSERT_OK(get_oom_score_adjust(&b));
1✔
893
        ASSERT_EQ(b, a);
1✔
894
}
1✔
895

896
static void* dummy_thread(void *p) {
2✔
897
        int fd = PTR_TO_FD(p);
2✔
898
        char x;
2✔
899

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

903
        /* wait for the main thread to tell us to shut down */
904
        ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
2✔
905
        return NULL;
2✔
906
}
907

908
TEST(get_process_threads) {
1✔
909
        int r;
1✔
910

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

915
        if (r == 0) {
2✔
UNCOV
916
                _cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
×
917
                pthread_t t, tt;
1✔
918
                char x;
1✔
919

920
                ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd));
1✔
921
                ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd));
1✔
922

923
                ASSERT_OK_EQ(get_process_threads(0), 1);
1✔
924
                ASSERT_OK_ZERO_ERRNO(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])));
1✔
925
                ASSERT_OK_EQ_ERRNO(read(pfd[1], &x, 1), 1);
1✔
926
                ASSERT_OK_EQ(get_process_threads(0), 2);
1✔
927
                ASSERT_OK_ZERO_ERRNO(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])));
1✔
928
                ASSERT_OK_EQ_ERRNO(read(ppfd[1], &x, 1), 1);
1✔
929
                ASSERT_OK_EQ(get_process_threads(0), 3);
1✔
930

931
                ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
1✔
932
                ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
1✔
933

934
                /* the value reported via /proc/ is decreased asynchronously, and there appears to be no nice
935
                 * way to sync on it. Hence we do the weak >= 2 check, even though == 2 is what we'd actually
936
                 * like to check here */
937
                r = get_process_threads(0);
1✔
938
                ASSERT_OK(r);
1✔
939
                ASSERT_GE(r, 2);
1✔
940

941
                ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
1✔
942
                ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
1✔
943

944
                /* similar here */
945
                r = get_process_threads(0);
1✔
946
                ASSERT_OK(r);
1✔
947
                ASSERT_GE(r, 1);
1✔
948

949
                _exit(EXIT_SUCCESS);
1✔
950
        }
951
}
1✔
952

953
TEST(is_reaper_process) {
1✔
954
        int r;
1✔
955

956
        r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
957
        ASSERT_OK(r);
2✔
958
        if (r == 0) {
2✔
959
                /* child */
960

961
                ASSERT_OK_ZERO(is_reaper_process());
1✔
962
                _exit(EXIT_SUCCESS);
1✔
963
        }
964

965
        r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
966
        ASSERT_OK(r);
2✔
967
        if (r == 0) {
2✔
968
                /* child */
969

970
                if (unshare(CLONE_NEWPID) < 0) {
1✔
UNCOV
971
                        if (ERRNO_IS_PRIVILEGE(errno) || ERRNO_IS_NOT_SUPPORTED(errno)) {
×
UNCOV
972
                                log_notice("Skipping CLONE_NEWPID reaper check, lacking privileges/support");
×
UNCOV
973
                                _exit(EXIT_SUCCESS);
×
974
                        }
975
                }
976

977
                r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
978
                ASSERT_OK(r);
2✔
979
                if (r == 0) {
2✔
980
                        /* grandchild, which is PID1 in a pidns */
981
                        ASSERT_OK_EQ(getpid_cached(), 1);
1✔
982
                        ASSERT_OK_POSITIVE(is_reaper_process());
1✔
983
                        _exit(EXIT_SUCCESS);
1✔
984
                }
985

986
                _exit(EXIT_SUCCESS);
1✔
987
        }
988

989
        r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1✔
990
        ASSERT_OK(r);
2✔
991
        if (r == 0) {
2✔
992
                /* child */
993
                ASSERT_OK(make_reaper_process(true));
1✔
994

995
                ASSERT_OK_POSITIVE(is_reaper_process());
1✔
996
                _exit(EXIT_SUCCESS);
1✔
997
        }
998
}
1✔
999

1000
TEST(pid_get_start_time) {
1✔
1001
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
1✔
1002

1003
        ASSERT_OK(pidref_set_self(&pidref));
1✔
1004

1005
        usec_t start_time;
1✔
1006
        ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
1✔
1007
        log_info("our starttime: " USEC_FMT, start_time);
1✔
1008

1009
        _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
1✔
1010

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

1013
        usec_t start_time2;
1✔
1014
        ASSERT_OK(pidref_get_start_time(&child, &start_time2));
1✔
1015

1016
        log_info("child starttime: " USEC_FMT, start_time2);
1✔
1017

1018
        ASSERT_GE(start_time2, start_time);
1✔
1019
}
1✔
1020

1021
TEST(pidref_from_same_root_fs) {
1✔
1022
        int r;
1✔
1023

1024
        _cleanup_(pidref_done) PidRef pid1 = PIDREF_NULL, self = PIDREF_NULL;
1✔
1025

1026
        ASSERT_OK(pidref_set_self(&self));
1✔
1027
        ASSERT_OK(pidref_set_pid(&pid1, 1));
1✔
1028

1029
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &self));
1✔
1030
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&pid1, &pid1));
1✔
1031

1032
        r = pidref_from_same_root_fs(&pid1, &self);
1✔
1033
        if (ERRNO_IS_NEG_PRIVILEGE(r))
1✔
UNCOV
1034
                return (void) log_tests_skipped("skipping pidref_from_same_root_fs() test, lacking privileged.");
×
1035
        ASSERT_OK(r);
1✔
1036
        log_info("PID1 and us have the same rootfs: %s", yes_no(r));
2✔
1037

1038
        int q = pidref_from_same_root_fs(&self, &pid1);
1✔
1039
        ASSERT_OK(q);
1✔
1040
        ASSERT_EQ(r, q);
1✔
1041

UNCOV
1042
        _cleanup_(pidref_done_sigkill_wait) PidRef child1 = PIDREF_NULL;
×
1043
        ASSERT_OK(pidref_safe_fork("(child1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_FREEZE, &child1));
1✔
1044
        ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &child1));
1✔
1045

1046
        _cleanup_close_ int efd = eventfd(0, EFD_CLOEXEC);
2✔
1047
        ASSERT_OK_ERRNO(efd);
1✔
1048

UNCOV
1049
        _cleanup_(pidref_done_sigkill_wait) PidRef child2 = PIDREF_NULL;
×
1050
        r = pidref_safe_fork("(child2)", FORK_RESET_SIGNALS|FORK_REOPEN_LOG, &child2);
1✔
1051
        ASSERT_OK(r);
1✔
1052

1053
        if (r == 0) {
1✔
UNCOV
1054
                ASSERT_OK_ERRNO(chroot("/usr"));
×
UNCOV
1055
                uint64_t u = 1;
×
1056

UNCOV
1057
                ASSERT_OK_EQ_ERRNO(write(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
×
1058
                freeze();
×
1059
        }
1060

1061
        uint64_t u;
1✔
1062
        ASSERT_OK_EQ_ERRNO(read(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
1✔
1063

1064
        ASSERT_OK_ZERO(pidref_from_same_root_fs(&self, &child2));
1✔
1065
        ASSERT_OK_ZERO(pidref_from_same_root_fs(&child2, &self));
1✔
1066
}
1067

1068
TEST(pidfd_get_inode_id_self_cached) {
1✔
1069
        int r;
1✔
1070

1071
        log_info("pid=" PID_FMT, getpid_cached());
1✔
1072

1073
        uint64_t id;
1✔
1074
        r = pidfd_get_inode_id_self_cached(&id);
1✔
1075
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
1✔
UNCOV
1076
                log_info("pidfdid not supported");
×
1077
        else {
1078
                assert(r >= 0);
1✔
1079
                log_info("pidfdid=%" PRIu64, id);
1✔
1080
        }
1081
}
1✔
1082

1083
TEST(getenv_for_pid) {
1✔
1084
        _cleanup_strv_free_ char **copy_env = NULL;
1✔
1085
        pid_t pid = getpid_cached();
1✔
1086
        int r;
1✔
1087

1088
        ASSERT_NOT_NULL(copy_env = strv_copy(environ));
1✔
1089

1090
        ASSERT_OK(r = pidref_safe_fork("(getenv_for_pid)", FORK_WAIT, NULL));
1✔
1091
        if (r == 0) {
2✔
1092
                STRV_FOREACH(e, copy_env) {
12✔
1093
                        const char *v = strchr(*e, '=');
11✔
1094
                        if (!v)
11✔
UNCOV
1095
                                continue;
×
1096

UNCOV
1097
                        _cleanup_free_ char *k = NULL;
×
1098
                        ASSERT_NOT_NULL(k = strndup(*e, v - *e));
11✔
1099

1100
                        v++;
11✔
1101

1102
                        _cleanup_free_ char *value = NULL;
11✔
1103
                        ASSERT_OK_POSITIVE(getenv_for_pid(pid, k, &value));
11✔
1104
                        ASSERT_STREQ(value, v);
11✔
1105
                }
1106

1107
                if (!strv_find_startswith(copy_env, "HOGEHOGE")) {
1✔
1108
                        char *value = POINTER_MAX;
1✔
1109
                        ASSERT_OK_ZERO(getenv_for_pid(pid, "HOGEHOGE", &value));
1✔
1110
                        ASSERT_NULL(value);
1✔
1111
                }
1112

1113
                _exit(EXIT_SUCCESS);
1✔
1114
        }
1115
}
1✔
1116

1117
static int intro(void) {
1✔
1118
        log_show_color(true);
1✔
1119
        return EXIT_SUCCESS;
1✔
1120
}
1121

1122
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